PageRenderTime 83ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 2ms

/epan/dissectors/packet-dnp.c

https://github.com/labx-technologies-llc/wireshark
C | 4190 lines | 3199 code | 570 blank | 421 comment | 160 complexity | 7a6f393440ba0f929e503195337d5919 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
  1. /* packet-dnp.c
  2. * Routines for DNP dissection
  3. * Copyright 2003, 2006, 2007, Graham Bloice <graham.bloice@trihedral.com>
  4. *
  5. * DNP3.0 Application Layer Object dissection added by Chris Bontje (chrisbontje@shaw.ca)
  6. * Copyright 2005
  7. *
  8. * Major updates: tcp and application layer defragmentation, more object dissections by Graham Bloice
  9. *
  10. * $Id$
  11. *
  12. * Wireshark - Network traffic analyzer
  13. * By Gerald Combs <gerald@wireshark.org>
  14. * Copyright 1998 Gerald Combs
  15. *
  16. * This program is free software; you can redistribute it and/or
  17. * modify it under the terms of the GNU General Public License
  18. * as published by the Free Software Foundation; either version 2
  19. * of the License, or (at your option) any later version.
  20. *
  21. * This program is distributed in the hope that it will be useful,
  22. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. * GNU General Public License for more details.
  25. *
  26. * You should have received a copy of the GNU General Public License
  27. * along with this program; if not, write to the Free Software
  28. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  29. */
  30. #include "config.h"
  31. #include <string.h>
  32. #include <math.h>
  33. #include <glib.h>
  34. #include <epan/packet.h>
  35. #include <epan/prefs.h>
  36. #include <epan/reassemble.h>
  37. #include <epan/emem.h>
  38. #include <epan/dissectors/packet-tcp.h>
  39. #include <epan/conversation.h>
  40. #include <epan/expert.h>
  41. /*
  42. * See
  43. *
  44. * http://www.dnp.org/
  45. *
  46. * although note that you have to join the DNP organization to get to
  47. * see the protocol specs online - otherwise, you have to buy a
  48. * dead-tree version.
  49. *
  50. * ...Application Layer Notes...
  51. *
  52. * Application Layer Decoding based on information available in
  53. * DNP3 Basic 4 Documentation Set, specifically the document:
  54. * "DNP V3.00 Application Layer" v0.03 P009-0PD.APP & Technical Bulletins
  55. *
  56. * ---------------------------------------------------------------------------
  57. *
  58. * Several command codes were missing, causing the dissector to abort decoding
  59. * on valid packets. Those commands have been added.
  60. *
  61. * The semantics of Variation 0 have been cleaned up. Variation 0 is the
  62. * "Default Variation". It is used only in Master -> Slave read commands
  63. * to request the data in whatever variation the Slave is configured to use by
  64. * default. Decoder strings have been added to the Binary Output and
  65. * Analog Output objects (10 and 40) so that group read commands will
  66. * decode properly.
  67. *
  68. * Roy M. Silvernail <roy@rant-central.com> 01/05/2009
  69. *
  70. */
  71. /***************************************************************************/
  72. /* DNP 3.0 Constants */
  73. /***************************************************************************/
  74. #define DNP_HDR_LEN 10
  75. #define TCP_PORT_DNP 20000
  76. #define UDP_PORT_DNP 20000
  77. /***************************************************************************/
  78. /* Datalink and Transport Layer Bit-Masks */
  79. /***************************************************************************/
  80. #define DNP3_CTL_DIR 0x80
  81. #define DNP3_CTL_PRM 0x40
  82. #define DNP3_CTL_FCB 0x20
  83. #define DNP3_CTL_FCV 0x10
  84. #define DNP3_CTL_RES 0x20
  85. #define DNP3_CTL_DFC 0x10
  86. #define DNP3_CTL_FUNC 0x0f
  87. #define DNP3_TR_FIR 0x40
  88. #define DNP3_TR_FIN 0x80
  89. #define DNP3_TR_SEQ 0x3f
  90. #define AL_MAX_CHUNK_SIZE 16
  91. /***************************************************************************/
  92. /* Data Link Function codes */
  93. /***************************************************************************/
  94. /* Primary to Secondary */
  95. #define DL_FUNC_RESET_LINK 0x00
  96. #define DL_FUNC_RESET_PROC 0x01
  97. #define DL_FUNC_TEST_LINK 0x02
  98. #define DL_FUNC_USER_DATA 0x03
  99. #define DL_FUNC_UNC_DATA 0x04
  100. #define DL_FUNC_LINK_STAT 0x09
  101. /* Secondary to Primary */
  102. #define DL_FUNC_ACK 0x00
  103. #define DL_FUNC_NACK 0x01
  104. #define DL_FUNC_STAT_LINK 0x0B
  105. #define DL_FUNC_NO_FUNC 0x0E
  106. #define DL_FUNC_NOT_IMPL 0x0F
  107. /***************************************************************************/
  108. /* Application Layer Bit-Masks */
  109. /***************************************************************************/
  110. #define DNP3_AL_UNS 0x10
  111. #define DNP3_AL_CON 0x20
  112. #define DNP3_AL_FIN 0x40
  113. #define DNP3_AL_FIR 0x80
  114. #define DNP3_AL_SEQ 0x0f
  115. #define DNP3_AL_FUNC 0xff
  116. /***************************************************************************/
  117. /* Application Layer Function codes */
  118. /***************************************************************************/
  119. #define AL_FUNC_CONFIRM 0x00 /* 00 - Confirm */
  120. #define AL_FUNC_READ 0x01 /* 01 - Read */
  121. #define AL_FUNC_WRITE 0x02 /* 02 - Write */
  122. #define AL_FUNC_SELECT 0x03 /* 03 - Select */
  123. #define AL_FUNC_OPERATE 0x04 /* 04 - Operate */
  124. #define AL_FUNC_DIROP 0x05 /* 05 - Direct Operate */
  125. #define AL_FUNC_DIROPNACK 0x06 /* 06 - Direct Operate No ACK */
  126. #define AL_FUNC_FRZ 0x07 /* 07 - Immediate Freeze */
  127. #define AL_FUNC_FRZNACK 0x08 /* 08 - Immediate Freeze No ACK */
  128. #define AL_FUNC_FRZCLR 0x09 /* 09 - Freeze and Clear */
  129. #define AL_FUNC_FRZCLRNACK 0x0A /* 10 - Freeze and Clear No ACK */
  130. #define AL_FUNC_FRZT 0x0B /* 11 - Freeze With Time */
  131. #define AL_FUNC_FRZTNACK 0x0C /* 12 - Freeze With Time No ACK */
  132. #define AL_FUNC_COLDRST 0x0D /* 13 - Cold Restart */
  133. #define AL_FUNC_WARMRST 0x0E /* 14 - Warm Restart */
  134. #define AL_FUNC_INITDATA 0x0F /* 15 - Initialize Data */
  135. #define AL_FUNC_INITAPP 0x10 /* 16 - Initialize Application */
  136. #define AL_FUNC_STARTAPP 0x11 /* 17 - Start Application */
  137. #define AL_FUNC_STOPAPP 0x12 /* 18 - Stop Application */
  138. #define AL_FUNC_SAVECFG 0x13 /* 19 - Save Configuration */
  139. #define AL_FUNC_ENSPMSG 0x14 /* 20 - Enable Spontaneous Msg */
  140. #define AL_FUNC_DISSPMSG 0x15 /* 21 - Disable Spontaneous Msg */
  141. #define AL_FUNC_ASSIGNCL 0x16 /* 22 - Assign Classes */
  142. #define AL_FUNC_DELAYMST 0x17 /* 23 - Delay Measurement */
  143. #define AL_FUNC_RECCT 0x18 /* 24 - Record Current Time */
  144. #define AL_FUNC_OPENFILE 0x19 /* 25 - Open File */
  145. #define AL_FUNC_CLOSEFILE 0x1A /* 26 - Close File */
  146. #define AL_FUNC_DELETEFILE 0x1B /* 27 - Delete File */
  147. #define AL_FUNC_GETFILEINF 0x1C /* 28 - Get File Info */
  148. #define AL_FUNC_AUTHFILE 0x1D /* 29 - Authenticate File */
  149. #define AL_FUNC_ABORTFILE 0x1E /* 30 - Abort File */
  150. #define AL_FUNC_ACTCNF 0x1F /* 31 - Activate Config */
  151. #define AL_FUNC_AUTHREQ 0x20 /* 32 - Authentication Request */
  152. #define AL_FUNC_AUTHERR 0x21 /* 33 - Authentication Error */
  153. #define AL_FUNC_RESPON 0x81 /* 129 - Response */
  154. #define AL_FUNC_UNSOLI 0x82 /* 130 - Unsolicited Response */
  155. #define AL_FUNC_AUTHRESP 0x83 /* 131 - Authentication Response */
  156. /***************************************************************************/
  157. /* Application Layer Internal Indication (IIN) bits */
  158. /* 2 Bytes, message formatting: [First Octet] | [Second Octet] */
  159. /***************************************************************************/
  160. /* Octet 1 */
  161. #define AL_IIN_BMSG 0x0100 /* Bit 0 - Broadcast message rx'd */
  162. #define AL_IIN_CLS1D 0x0200 /* Bit 1 - Class 1 Data Available */
  163. #define AL_IIN_CLS2D 0x0400 /* Bit 2 - Class 2 Data Available */
  164. #define AL_IIN_CLS3D 0x0800 /* Bit 3 - Class 3 Data Available */
  165. #define AL_IIN_TSR 0x1000 /* Bit 4 - Time Sync Req'd from Master */
  166. #define AL_IIN_DOL 0x2000 /* Bit 5 - Outputs in Local Mode */
  167. #define AL_IIN_DT 0x4000 /* Bit 6 - Device Trouble */
  168. #define AL_IIN_RST 0x8000 /* Bit 7 - Device Restart */
  169. /* Octet 2 */
  170. #define AL_IIN_FCNI 0x0001 /* Bit 0 - Function code not implemented */
  171. #define AL_IIN_OBJU 0x0002 /* Bit 1 - Requested Objects Unknown */
  172. #define AL_IIN_PIOOR 0x0004 /* Bit 2 - Parameters Invalid or Out of Range */
  173. #define AL_IIN_EBO 0x0008 /* Bit 3 - Event Buffer Overflow */
  174. #define AL_IIN_OAE 0x0010 /* Bit 4 - Operation Already Executing */
  175. #define AL_IIN_CC 0x0020 /* Bit 5 - Device Configuration Corrupt */
  176. /* 0x0040 Bit 6 - Reserved */
  177. /* 0x0080 Bit 7 - Reserved */
  178. /***************************************************************************/
  179. /* Application Layer Data Object Qualifier */
  180. /***************************************************************************/
  181. /* Bit-Masks */
  182. #define AL_OBJQ_INDEX 0x70 /* x111xxxx Masks Index from Qualifier */
  183. #define AL_OBJQ_CODE 0x0F /* xxxx1111 Masks Code from Qualifier */
  184. /* Index Size (3-bits x111xxxx) */
  185. /* When Qualifier Code != 11 */
  186. #define AL_OBJQL_IDX_NI 0x00 /* Objects are Packed with no index */
  187. #define AL_OBJQL_IDX_1O 0x01 /* Objects are prefixed w/ 1-octet index */
  188. #define AL_OBJQL_IDX_2O 0x02 /* Objects are prefixed w/ 2-octet index */
  189. #define AL_OBJQL_IDX_4O 0x03 /* Objects are prefixed w/ 4-octet index */
  190. #define AL_OBJQL_IDX_1OS 0x04 /* Objects are prefixed w/ 1-octet object size */
  191. #define AL_OBJQL_IDX_2OS 0x05 /* Objects are prefixed w/ 2-octet object size */
  192. #define AL_OBJQL_IDX_4OS 0x06 /* Objects are prefixed w/ 4-octet object size */
  193. /* When Qualifier Code == 11 */
  194. #define AL_OBJQL_IDX11_1OIS 0x01 /* 1 octet identifier size */
  195. #define AL_OBJQL_IDX11_2OIS 0x02 /* 2 octet identifier size */
  196. #define AL_OBJQL_IDX11_4OIS 0x03 /* 4 octet identifier size */
  197. /* Qualifier Code (4-bits) */
  198. /* 4-bits ( xxxx1111 ) */
  199. #define AL_OBJQL_CODE_SSI8 0x00 /* 00 8-bit Start and Stop Indices in Range Field */
  200. #define AL_OBJQL_CODE_SSI16 0x01 /* 01 16-bit Start and Stop Indices in Range Field */
  201. #define AL_OBJQL_CODE_SSI32 0x02 /* 02 32-bit Start and Stop Indices in Range Field */
  202. #define AL_OBJQL_CODE_AA8 0x03 /* 03 8-bit Absolute Address in Range Field */
  203. #define AL_OBJQL_CODE_AA16 0x04 /* 04 16-bit Absolute Address in Range Field */
  204. #define AL_OBJQL_CODE_AA32 0x05 /* 05 32-bit Absolute Address in Range Field */
  205. #define AL_OBJQL_CODE_R0 0x06 /* 06 Length of Range field is 0 (no range field) */
  206. #define AL_OBJQL_CODE_SF8 0x07 /* 07 8-bit Single Field Quantity */
  207. #define AL_OBJQL_CODE_SF16 0x08 /* 08 16-bit Single Field Quantity */
  208. #define AL_OBJQL_CODE_SF32 0x09 /* 09 32-bit Single Field Quantity */
  209. /* 0x0A 10 Reserved */
  210. #define AL_OBJQL_CODE_FF 0x0B /* 11 Free-format Qualifier, range field has 1 octet count of objects */
  211. /* 0x0C 12 Reserved */
  212. /* 0x0D 13 Reserved */
  213. /* 0x0E 14 Reserved */
  214. /* 0x0F 15 Reserved */
  215. /***************************************************************************/
  216. /* Application Layer Data Object Definitions */
  217. /***************************************************************************/
  218. /* Binary Input Objects */
  219. #define AL_OBJ_BI_ALL 0x0100 /* 01 00 Binary Input Default Variation */
  220. #define AL_OBJ_BI_1BIT 0x0101 /* 01 01 Single-bit Binary Input */
  221. #define AL_OBJ_BI_STAT 0x0102 /* 01 02 Binary Input With Status */
  222. #define AL_OBJ_BIC_ALL 0x0200 /* 02 00 Binary Input Change Default Variation */
  223. #define AL_OBJ_BIC_NOTIME 0x0201 /* 02 01 Binary Input Change Without Time */
  224. #define AL_OBJ_BIC_TIME 0x0202 /* 02 02 Binary Input Change With Time */
  225. #define AL_OBJ_BIC_RTIME 0x0203 /* 02 03 Binary Input Change With Relative Time */
  226. /* Double-bit Input Objects */
  227. #define AL_OBJ_2BI_ALL 0x0300 /* 03 00 Double-bit Input Default Variation */
  228. #define AL_OBJ_2BI_NF 0x0301 /* 03 01 Double-bit Input No Flags */
  229. #define AL_OBJ_2BI_STAT 0x0302 /* 03 02 Double-bit Input With Status */
  230. #define AL_OBJ_2BIC_NOTIME 0x0401 /* 04 01 Double-bit Input Change Without Time */
  231. #define AL_OBJ_2BIC_TIME 0x0402 /* 04 02 Double-bit Input Change With Time */
  232. #define AL_OBJ_2BIC_RTIME 0x0403 /* 04 03 Double-bit Input Change With Relative Time */
  233. /* Binary Input Quality Flags */
  234. #define AL_OBJ_BI_FLAG0 0x0001 /* Point Online (0=Offline; 1=Online) */
  235. #define AL_OBJ_BI_FLAG1 0x0002 /* Restart (0=Normal; 1=Restart) */
  236. #define AL_OBJ_BI_FLAG2 0x0004 /* Comms Lost (0=Normal; 1=Lost) */
  237. #define AL_OBJ_BI_FLAG3 0x0008 /* Remote Force (0=Normal; 1=Forced) */
  238. #define AL_OBJ_BI_FLAG4 0x0010 /* Local Force (0=Normal; 1=Forced) */
  239. #define AL_OBJ_BI_FLAG5 0x0020 /* Chatter Filter (0=Normal; 1=Filter On) */
  240. #define AL_OBJ_BI_FLAG6 0x0040 /* Double-bit LSB (0=Off; 1=On) */
  241. #define AL_OBJ_BI_FLAG7 0x0080 /* Point State (0=Off; 1=On) or Double-bit MSB */
  242. /***************************************************************************/
  243. /* Binary Output Objects */
  244. #define AL_OBJ_BO_ALL 0x0A00 /* 10 00 Binary Output Default Variation */
  245. #define AL_OBJ_BO 0x0A01 /* 10 01 Binary Output */
  246. #define AL_OBJ_BO_STAT 0x0A02 /* 10 02 Binary Output Status */
  247. #define AL_OBJ_BOC_ALL 0x0B00 /* 11 00 Binary Output Change Default Variation */
  248. #define AL_OBJ_BOC_NOTIME 0x0B01 /* 11 01 Binary Output Change Without Time */
  249. #define AL_OBJ_BOC_TIME 0x0B02 /* 11 02 Binary Output Change With Time */
  250. #define AL_OBJ_CTLOP_BLK 0x0C01 /* 12 01 Control Relay Output Block */
  251. /* 0x0C02 12 02 Pattern Control Block */
  252. /* 0x0C03 12 03 Pattern Mask */
  253. #define AL_OBJCTLC_CODE 0x0F /* Bit-Mask xxxx1111 for Control Code 'Code' */
  254. #define AL_OBJCTLC_MISC 0x30 /* Bit-Mask xx11xxxx for Control Code Queue (obsolete) and Clear Fields */
  255. #define AL_OBJCTLC_TC 0xC0 /* Bit-Mask 11xxxxxx for Control Code 'Trip/Close' */
  256. #define AL_OBJCTLC_CODE0 0x00 /* xxxx0000 NUL Operation; only process R attribute */
  257. #define AL_OBJCTLC_CODE1 0x01 /* xxxx0001 Pulse On ^On-Time -> vOff-Time, remain off */
  258. #define AL_OBJCTLC_CODE2 0x02 /* xxxx0010 Pulse Off vOff-Time -> ^On-Time, remain on */
  259. #define AL_OBJCTLC_CODE3 0x03 /* xxxx0011 Latch On */
  260. #define AL_OBJCTLC_CODE4 0x04 /* xxxx0100 Latch Off */
  261. /* 0x05-0x15 Reserved */
  262. #define AL_OBJCTLC_NOTSET 0x00 /* xx00xxxx for Control Code, Clear and Queue not set */
  263. #define AL_OBJCTLC_QUEUE 0x01 /* xxx1xxxx for Control Code, Clear Field 'Queue' */
  264. #define AL_OBJCTLC_CLEAR 0x02 /* xx1xxxxx for Control Code, Clear Field 'Clear' */
  265. #define AL_OBJCTLC_BOTHSET 0x03 /* xx11xxxx for Control Code, Clear and Queue both set */
  266. #define AL_OBJCTLC_TC0 0x00 /* 00xxxxxx NUL */
  267. #define AL_OBJCTLC_TC1 0x01 /* 01xxxxxx Close */
  268. #define AL_OBJCTLC_TC2 0x02 /* 10xxxxxx Trip */
  269. #define AL_OBJCTLC_TC3 0x03 /* 11xxxxxx Reserved */
  270. #define AL_OBJCTL_STAT0 0x00 /* Request Accepted, Initiated or Queued */
  271. #define AL_OBJCTL_STAT1 0x01 /* Request Not Accepted; Arm-timer expired */
  272. #define AL_OBJCTL_STAT2 0x02 /* Request Not Accepted; No 'SELECT' rx'd */
  273. #define AL_OBJCTL_STAT3 0x03 /* Request Not Accepted; Format errors in ctrl request */
  274. #define AL_OBJCTL_STAT4 0x04 /* Control Operation Not Supported for this point */
  275. #define AL_OBJCTL_STAT5 0x05 /* Request Not Accepted; Ctrl Queue full or pt. active */
  276. #define AL_OBJCTL_STAT6 0x06 /* Request Not Accepted; Ctrl HW Problems */
  277. #define AL_OBJCTL_STAT7 0x07 /* Request Not Accepted; Local/Remote switch in Local*/
  278. #define AL_OBJCTL_STAT8 0x08 /* Request Not Accepted; Too many operations requested */
  279. #define AL_OBJCTL_STAT9 0x09 /* Request Not Accepted; Insufficient authorization */
  280. #define AL_OBJCTL_STAT10 0x0A /* Request Not Accepted; Local automation proc active */
  281. /* Binary Output Quality Flags */
  282. #define AL_OBJ_BO_FLAG0 0x0001 /* Point Online (0=Offline; 1=Online) */
  283. #define AL_OBJ_BO_FLAG1 0x0002 /* Restart (0=Normal; 1=Restart) */
  284. #define AL_OBJ_BO_FLAG2 0x0004 /* Comms Lost (0=Normal; 1=Lost) */
  285. #define AL_OBJ_BO_FLAG3 0x0008 /* Remote Force (0=Normal; 1=Forced) */
  286. #define AL_OBJ_BO_FLAG4 0x0010 /* Local Force (0=Normal; 1=Forced) */
  287. #define AL_OBJ_BO_FLAG5 0x0020 /* Reserved */
  288. #define AL_OBJ_BO_FLAG6 0x0040 /* Reserved */
  289. #define AL_OBJ_BO_FLAG7 0x0080 /* Point State (0=Off; 1=On) */
  290. /***************************************************************************/
  291. /* Counter Objects */
  292. #define AL_OBJ_CTR_ALL 0x1400 /* 20 00 Binary Counter Default Variation */
  293. #define AL_OBJ_CTR_32 0x1401 /* 20 01 32-Bit Binary Counter */
  294. #define AL_OBJ_CTR_16 0x1402 /* 20 02 16-Bit Binary Counter */
  295. #define AL_OBJ_DCTR_32 0x1403 /* 20 03 32-Bit Delta Counter */
  296. #define AL_OBJ_DCTR_16 0x1404 /* 20 04 16-Bit Delta Counter */
  297. #define AL_OBJ_CTR_32NF 0x1405 /* 20 05 32-Bit Binary Counter Without Flag */
  298. #define AL_OBJ_CTR_16NF 0x1406 /* 20 06 16-Bit Binary Counter Without Flag */
  299. #define AL_OBJ_DCTR_32NF 0x1407 /* 20 07 32-Bit Delta Counter Without Flag */
  300. #define AL_OBJ_DCTR_16NF 0x1408 /* 20 08 16-Bit Delta Counter Without Flag */
  301. #define AL_OBJ_FCTR_ALL 0x1500 /* 21 00 Frozen Binary Counter Default Variation */
  302. #define AL_OBJ_FCTR_32 0x1501 /* 21 01 32-Bit Frozen Counter */
  303. #define AL_OBJ_FCTR_16 0x1502 /* 21 02 16-Bit Frozen Counter */
  304. #define AL_OBJ_FDCTR_32 0x1503 /* 21 03 32-Bit Frozen Delta Counter */
  305. #define AL_OBJ_FDCTR_16 0x1504 /* 21 04 16-Bit Frozen Delta Counter */
  306. #define AL_OBJ_FCTR_32T 0x1505 /* 21 05 32-Bit Frozen Counter w/ Time of Freeze */
  307. #define AL_OBJ_FCTR_16T 0x1506 /* 21 06 16-Bit Frozen Counter w/ Time of Freeze */
  308. #define AL_OBJ_FDCTR_32T 0x1507 /* 21 07 32-Bit Frozen Delta Counter w/ Time of Freeze */
  309. #define AL_OBJ_FDCTR_16T 0x1508 /* 21 08 16-Bit Frozen Delta Counter w/ Time of Freeze */
  310. #define AL_OBJ_FCTR_32NF 0x1509 /* 21 09 32-Bit Frozen Counter Without Flag */
  311. #define AL_OBJ_FCTR_16NF 0x150A /* 21 10 16-Bit Frozen Counter Without Flag */
  312. #define AL_OBJ_FDCTR_32NF 0x150B /* 21 11 32-Bit Frozen Delta Counter Without Flag */
  313. #define AL_OBJ_FDCTR_16NF 0x150C /* 21 12 16-Bit Frozen Delta Counter Without Flag */
  314. #define AL_OBJ_CTRC_ALL 0x1600 /* 22 00 Counter Change Event Default Variation */
  315. #define AL_OBJ_CTRC_32 0x1601 /* 22 01 32-Bit Counter Change Event w/o Time */
  316. #define AL_OBJ_CTRC_16 0x1602 /* 22 02 16-Bit Counter Change Event w/o Time */
  317. #define AL_OBJ_DCTRC_32 0x1603 /* 22 03 32-Bit Delta Counter Change Event w/o Time */
  318. #define AL_OBJ_DCTRC_16 0x1604 /* 22 04 16-Bit Delta Counter Change Event w/o Time */
  319. #define AL_OBJ_CTRC_32T 0x1605 /* 22 05 32-Bit Counter Change Event with Time */
  320. #define AL_OBJ_CTRC_16T 0x1606 /* 22 06 16-Bit Counter Change Event with Time */
  321. #define AL_OBJ_DCTRC_32T 0x1607 /* 22 07 32-Bit Delta Counter Change Event with Time */
  322. #define AL_OBJ_DCTRC_16T 0x1608 /* 22 08 16-Bit Delta Counter Change Event with Time */
  323. #define AL_OBJ_FCTRC_ALL 0x1700 /* 21 00 Frozen Binary Counter Change Event Default Variation */
  324. #define AL_OBJ_FCTRC_32 0x1701 /* 21 01 32-Bit Frozen Counter Change Event */
  325. #define AL_OBJ_FCTRC_16 0x1702 /* 21 02 16-Bit Frozen Counter Change Event */
  326. #define AL_OBJ_FDCTRC_32 0x1703 /* 21 03 32-Bit Frozen Delta Counter Change Event */
  327. #define AL_OBJ_FDCTRC_16 0x1704 /* 21 04 16-Bit Frozen Delta Counter Change Event */
  328. #define AL_OBJ_FCTRC_32T 0x1705 /* 21 05 32-Bit Frozen Counter Change Event w/ Time of Freeze */
  329. #define AL_OBJ_FCTRC_16T 0x1706 /* 21 06 16-Bit Frozen Counter Change Event w/ Time of Freeze */
  330. #define AL_OBJ_FDCTRC_32T 0x1707 /* 21 07 32-Bit Frozen Delta Counter Change Event w/ Time of Freeze */
  331. #define AL_OBJ_FDCTRC_16T 0x1708 /* 21 08 16-Bit Frozen Delta Counter Change Event w/ Time of Freeze */
  332. /* Counter Quality Flags */
  333. #define AL_OBJ_CTR_FLAG0 0x0001 /* Point Online (0=Offline; 1=Online) */
  334. #define AL_OBJ_CTR_FLAG1 0x0002 /* Restart (0=Normal; 1=Restart) */
  335. #define AL_OBJ_CTR_FLAG2 0x0004 /* Comms Lost (0=Normal; 1=Lost) */
  336. #define AL_OBJ_CTR_FLAG3 0x0008 /* Remote Force (0=Normal; 1=Forced) */
  337. #define AL_OBJ_CTR_FLAG4 0x0010 /* Local Force (0=Normal; 1=Forced) */
  338. #define AL_OBJ_CTR_FLAG5 0x0020 /* Roll-over (0=Normal; 1=Roll-Over) */
  339. #define AL_OBJ_CTR_FLAG6 0x0040 /* Discontinuity (0=Normal; 1=Discontinuity) */
  340. #define AL_OBJ_CTR_FLAG7 0x0080 /* Reserved */
  341. /***************************************************************************/
  342. /* Analog Input Objects */
  343. #define AL_OBJ_AI_ALL 0x1E00 /* 30 00 Analog Input Default Variation */
  344. #define AL_OBJ_AI_32 0x1E01 /* 30 01 32-Bit Analog Input */
  345. #define AL_OBJ_AI_16 0x1E02 /* 30 02 16-Bit Analog Input */
  346. #define AL_OBJ_AI_32NF 0x1E03 /* 30 03 32-Bit Analog Input Without Flag */
  347. #define AL_OBJ_AI_16NF 0x1E04 /* 30 04 16-Bit Analog Input Without Flag */
  348. #define AL_OBJ_AI_FLT 0x1E05 /* 30 05 32-Bit Floating Point Input */
  349. #define AL_OBJ_AI_DBL 0x1E06 /* 30 06 64-Bit Floating Point Input */
  350. /* 0x1F01 31 01 32-Bit Frozen Analog Input */
  351. /* 0x1F02 31 02 16-Bit Frozen Analog Input */
  352. /* 0x1F03 31 03 32-Bit Frozen Analog Input w/ Time of Freeze */
  353. /* 0x1F04 31 04 16-Bit Frozen Analog Input w/ Time of Freeze */
  354. /* 0x1F05 31 05 32-Bit Frozen Analog Input Without Flag */
  355. /* 0x1F06 31 06 16-Bit Frozen Analog Input Without Flag */
  356. #define AL_OBJ_AIF_FLT 0x1F07 /* 31 07 32-Bit Frozen Floating Point Input */
  357. #define AL_OBJ_AIF_DBL 0x1F08 /* 31 08 64-Bit Frozen Floating Point Input */
  358. #define AL_OBJ_AIC_ALL 0x2000 /* 32 00 Analog Input Change Default Variation */
  359. #define AL_OBJ_AIC_32NT 0x2001 /* 32 01 32-Bit Analog Change Event w/o Time */
  360. #define AL_OBJ_AIC_16NT 0x2002 /* 32 02 16-Bit Analog Change Event w/o Time */
  361. #define AL_OBJ_AIC_32T 0x2003 /* 32 03 32-Bit Analog Change Event w/ Time */
  362. #define AL_OBJ_AIC_16T 0x2004 /* 32 04 16-Bit Analog Change Event w/ Time */
  363. #define AL_OBJ_AIC_FLTNT 0x2005 /* 32 05 32-Bit Floating Point Change Event w/o Time*/
  364. #define AL_OBJ_AIC_DBLNT 0x2006 /* 32 06 64-Bit Floating Point Change Event w/o Time*/
  365. #define AL_OBJ_AIC_FLTT 0x2007 /* 32 07 32-Bit Floating Point Change Event w/ Time*/
  366. #define AL_OBJ_AIC_DBLT 0x2008 /* 32 08 64-Bit Floating Point Change Event w/ Time*/
  367. /* 0x2101 33 01 32-Bit Frozen Analog Event w/o Time */
  368. /* 0x2102 33 02 16-Bit Frozen Analog Event w/o Time */
  369. /* 0x2103 33 03 32-Bit Frozen Analog Event w/ Time */
  370. /* 0x2104 33 04 16-Bit Frozen Analog Event w/ Time */
  371. #define AL_OBJ_AIFC_FLTNT 0x2105 /* 33 05 32-Bit Floating Point Frozen Change Event w/o Time*/
  372. #define AL_OBJ_AIFC_DBLNT 0x2106 /* 33 06 64-Bit Floating Point Frozen Change Event w/o Time*/
  373. #define AL_OBJ_AIFC_FLTT 0x2107 /* 33 07 32-Bit Floating Point Frozen Change Event w/ Time*/
  374. #define AL_OBJ_AIFC_DBLT 0x2108 /* 33 08 64-Bit Floating Point Frozen Change Event w/ Time*/
  375. /* Analog Input Quality Flags */
  376. #define AL_OBJ_AI_FLAG0 0x0001 /* Point Online (0=Offline; 1=Online) */
  377. #define AL_OBJ_AI_FLAG1 0x0002 /* Restart (0=Normal; 1=Restart) */
  378. #define AL_OBJ_AI_FLAG2 0x0004 /* Comms Lost (0=Normal; 1=Lost) */
  379. #define AL_OBJ_AI_FLAG3 0x0008 /* Remote Force (0=Normal; 1=Forced) */
  380. #define AL_OBJ_AI_FLAG4 0x0010 /* Local Force (0=Normal; 1=Forced) */
  381. #define AL_OBJ_AI_FLAG5 0x0020 /* Over-Range (0=Normal; 1=Over-Range) */
  382. #define AL_OBJ_AI_FLAG6 0x0040 /* Reference Check (0=Normal; 1=Error) */
  383. #define AL_OBJ_AI_FLAG7 0x0080 /* Reserved */
  384. #define AL_OBJ_AIDB_ALL 0x2200 /* 34 00 Analog Input Deadband Default Variation */
  385. #define AL_OBJ_AIDB_16 0x2201 /* 34 01 16-Bit Analog Input Deadband */
  386. #define AL_OBJ_AIDB_32 0x2202 /* 34 02 32-Bit Analog Input Deadband */
  387. #define AL_OBJ_AIDB_FLT 0x2203 /* 34 03 Floating Point Analog Input Deadband */
  388. /***************************************************************************/
  389. /* Analog Output Objects */
  390. #define AL_OBJ_AO_ALL 0x2800 /* 40 00 Analog Output Default Variation */
  391. #define AL_OBJ_AO_32 0x2801 /* 40 01 32-Bit Analog Output Status */
  392. #define AL_OBJ_AO_16 0x2802 /* 40 02 16-Bit Analog Output Status */
  393. #define AL_OBJ_AO_FLT 0x2803 /* 40 03 32-Bit Floating Point Output Status */
  394. #define AL_OBJ_AO_DBL 0x2804 /* 40 04 64-Bit Floating Point Output Status */
  395. #define AL_OBJ_AO_32OPB 0x2901 /* 41 01 32-Bit Analog Output Block */
  396. #define AL_OBJ_AO_16OPB 0x2902 /* 41 02 16-Bit Analog Output Block */
  397. #define AL_OBJ_AO_FLTOPB 0x2903 /* 41 03 32-Bit Floating Point Output Block */
  398. #define AL_OBJ_AO_DBLOPB 0x2904 /* 41 04 64-Bit Floating Point Output Block */
  399. #define AL_OBJ_AOC_ALL 0x2A00 /* 42 00 Analog Output Event Default Variation */
  400. #define AL_OBJ_AOC_32NT 0x2A01 /* 42 01 32-Bit Analog Output Event w/o Time */
  401. #define AL_OBJ_AOC_16NT 0x2A02 /* 42 02 16-Bit Analog Output Event w/o Time */
  402. #define AL_OBJ_AOC_32T 0x2A03 /* 42 03 32-Bit Analog Output Event w/ Time */
  403. #define AL_OBJ_AOC_16T 0x2A04 /* 42 04 16-Bit Analog Output Event w/ Time */
  404. #define AL_OBJ_AOC_FLTNT 0x2A05 /* 42 05 32-Bit Floating Point Output Event w/o Time*/
  405. #define AL_OBJ_AOC_DBLNT 0x2A06 /* 42 06 64-Bit Floating Point Output Event w/o Time*/
  406. #define AL_OBJ_AOC_FLTT 0x2A07 /* 42 07 32-Bit Floating Point Output Event w/ Time*/
  407. #define AL_OBJ_AOC_DBLT 0x2A08 /* 42 08 64-Bit Floating Point Output Event w/ Time*/
  408. /* Analog Output Quality Flags */
  409. #define AL_OBJ_AO_FLAG0 0x0001 /* Point Online (0=Offline; 1=Online) */
  410. #define AL_OBJ_AO_FLAG1 0x0002 /* Restart (0=Normal; 1=Restart) */
  411. #define AL_OBJ_AO_FLAG2 0x0004 /* Comms Lost (0=Normal; 1=Lost) */
  412. #define AL_OBJ_AO_FLAG3 0x0008 /* Remote Force (0=Normal; 1=Forced) */
  413. #define AL_OBJ_AO_FLAG4 0x0010 /* Local Force (0=Normal; 1=Forced) */
  414. #define AL_OBJ_AO_FLAG5 0x0020 /* Reserved */
  415. #define AL_OBJ_AO_FLAG6 0x0040 /* Reserved */
  416. #define AL_OBJ_AO_FLAG7 0x0080 /* Reserved */
  417. /***************************************************************************/
  418. /* Time Objects */
  419. #define AL_OBJ_TD_ALL 0x3200 /* 50 00 Time and Date Default Variation */
  420. #define AL_OBJ_TD 0x3201 /* 50 01 Time and Date */
  421. #define AL_OBJ_TDI 0x3202 /* 50 02 Time and Date w/ Interval */
  422. #define AL_OBJ_TDR 0x3203 /* 50 03 Last Recorded Time and Date */
  423. #define AL_OBJ_TDCTO 0x3301 /* 51 01 Time and Date CTO */
  424. #define AL_OBJ_UTDCTO 0x3302 /* 51 02 Unsynchronized Time and Date CTO */
  425. #define AL_OBJ_TDELAYC 0x3401 /* 52 01 Time Delay Coarse */
  426. #define AL_OBJ_TDELAYF 0x3402 /* 52 02 Time Delay Fine */
  427. /***************************************************************************/
  428. /* Class Data Objects */
  429. #define AL_OBJ_CLASS0 0x3C01 /* 60 01 Class 0 Data */
  430. #define AL_OBJ_CLASS1 0x3C02 /* 60 02 Class 1 Data */
  431. #define AL_OBJ_CLASS2 0x3C03 /* 60 03 Class 2 Data */
  432. #define AL_OBJ_CLASS3 0x3C04 /* 60 04 Class 3 Data */
  433. /***************************************************************************/
  434. /* File Objects */
  435. #define AL_OBJ_FILE_CMD 0x4603 /* 70 03 File Control - Command */
  436. #define AL_OBJ_FILE_STAT 0x4604 /* 70 04 File Control - Status */
  437. #define AL_OBJ_FILE_TRANS 0x4605 /* 70 05 File Control - Transport */
  438. #define AL_OBJ_FILE_TRAN_ST 0x4606 /* 70 05 File Control - Transport Status */
  439. /* File Control Mode flags */
  440. #define AL_OBJ_FILE_MODE_NULL 0x00 /* NULL */
  441. #define AL_OBJ_FILE_MODE_READ 0x01 /* READ */
  442. #define AL_OBJ_FILE_MODE_WRITE 0x02 /* WRITE */
  443. #define AL_OBJ_FILE_MODE_APPEND 0x03 /* APPEND */
  444. /***************************************************************************/
  445. /* Device Objects */
  446. #define AL_OBJ_IIN 0x5001 /* 80 01 Internal Indications */
  447. /***************************************************************************/
  448. /* Octet String Objects */
  449. #define AL_OBJ_OCT 0x6E00 /* 110 xx Octet string */
  450. #define AL_OBJ_OCT_EVT 0x6F00 /* 110 xx Octet string event */
  451. /***************************************************************************/
  452. /* End of Application Layer Data Object Definitions */
  453. /***************************************************************************/
  454. void proto_register_dnp3(void);
  455. void proto_reg_handoff_dnp3(void);
  456. /* Initialize the protocol and registered fields */
  457. static int proto_dnp3 = -1;
  458. static int hf_dnp3_start = -1;
  459. static int hf_dnp3_len = -1;
  460. static int hf_dnp3_ctl = -1;
  461. static int hf_dnp3_ctl_prifunc = -1;
  462. static int hf_dnp3_ctl_secfunc = -1;
  463. static int hf_dnp3_ctl_dir = -1;
  464. static int hf_dnp3_ctl_prm = -1;
  465. static int hf_dnp3_ctl_fcb = -1;
  466. static int hf_dnp3_ctl_fcv = -1;
  467. static int hf_dnp3_ctl_dfc = -1;
  468. static int hf_dnp3_dst = -1;
  469. static int hf_dnp3_src = -1;
  470. static int hf_dnp_hdr_CRC = -1;
  471. static int hf_dnp_hdr_CRC_bad = -1;
  472. static int hf_dnp3_tr_ctl = -1;
  473. static int hf_dnp3_tr_fin = -1;
  474. static int hf_dnp3_tr_fir = -1;
  475. static int hf_dnp3_tr_seq = -1;
  476. static int hf_dnp3_al_ctl = -1;
  477. static int hf_dnp3_al_fir = -1;
  478. static int hf_dnp3_al_fin = -1;
  479. static int hf_dnp3_al_con = -1;
  480. static int hf_dnp3_al_uns = -1;
  481. static int hf_dnp3_al_seq = -1;
  482. static int hf_dnp3_al_func = -1;
  483. /* Added for Application Layer Decoding */
  484. static int hf_dnp3_al_iin = -1;
  485. static int hf_dnp3_al_iin_bmsg = -1;
  486. static int hf_dnp3_al_iin_cls1d = -1;
  487. static int hf_dnp3_al_iin_cls2d = -1;
  488. static int hf_dnp3_al_iin_cls3d = -1;
  489. static int hf_dnp3_al_iin_tsr = -1;
  490. static int hf_dnp3_al_iin_dol = -1;
  491. static int hf_dnp3_al_iin_dt = -1;
  492. static int hf_dnp3_al_iin_rst = -1;
  493. static int hf_dnp3_al_iin_fcni = -1;
  494. static int hf_dnp3_al_iin_obju = -1;
  495. static int hf_dnp3_al_iin_pioor = -1;
  496. static int hf_dnp3_al_iin_ebo = -1;
  497. static int hf_dnp3_al_iin_oae = -1;
  498. static int hf_dnp3_al_iin_cc = -1;
  499. static int hf_dnp3_al_obj = -1;
  500. static int hf_dnp3_al_objq_index = -1;
  501. static int hf_dnp3_al_objq_code = -1;
  502. static int hf_dnp3_al_range_start8 = -1;
  503. static int hf_dnp3_al_range_stop8 = -1;
  504. static int hf_dnp3_al_range_start16 = -1;
  505. static int hf_dnp3_al_range_stop16 = -1;
  506. static int hf_dnp3_al_range_start32 = -1;
  507. static int hf_dnp3_al_range_stop32 = -1;
  508. static int hf_dnp3_al_range_abs8 = -1;
  509. static int hf_dnp3_al_range_abs16 = -1;
  510. static int hf_dnp3_al_range_abs32 = -1;
  511. static int hf_dnp3_al_range_quant8 = -1;
  512. static int hf_dnp3_al_range_quant16 = -1;
  513. static int hf_dnp3_al_range_quant32 = -1;
  514. static int hf_dnp3_al_index8 = -1;
  515. static int hf_dnp3_al_index16 = -1;
  516. static int hf_dnp3_al_index32 = -1;
  517. static int hf_dnp3_al_size8 = -1;
  518. static int hf_dnp3_al_size16 = -1;
  519. static int hf_dnp3_al_size32 = -1;
  520. /*static int hf_dnp3_al_objq = -1;
  521. static int hf_dnp3_al_nobj = -1; */
  522. /* XXX - unused
  523. static int hf_dnp3_al_ptnum = -1; */
  524. static int hf_dnp3_al_biq_b0 = -1;
  525. static int hf_dnp3_al_biq_b1 = -1;
  526. static int hf_dnp3_al_biq_b2 = -1;
  527. static int hf_dnp3_al_biq_b3 = -1;
  528. static int hf_dnp3_al_biq_b4 = -1;
  529. static int hf_dnp3_al_biq_b5 = -1;
  530. static int hf_dnp3_al_biq_b6 = -1;
  531. static int hf_dnp3_al_biq_b7 = -1;
  532. static int hf_dnp3_al_boq_b0 = -1;
  533. static int hf_dnp3_al_boq_b1 = -1;
  534. static int hf_dnp3_al_boq_b2 = -1;
  535. static int hf_dnp3_al_boq_b3 = -1;
  536. static int hf_dnp3_al_boq_b4 = -1;
  537. static int hf_dnp3_al_boq_b5 = -1;
  538. static int hf_dnp3_al_boq_b6 = -1;
  539. static int hf_dnp3_al_boq_b7 = -1;
  540. static int hf_dnp3_al_ctrq_b0 = -1;
  541. static int hf_dnp3_al_ctrq_b1 = -1;
  542. static int hf_dnp3_al_ctrq_b2 = -1;
  543. static int hf_dnp3_al_ctrq_b3 = -1;
  544. static int hf_dnp3_al_ctrq_b4 = -1;
  545. static int hf_dnp3_al_ctrq_b5 = -1;
  546. static int hf_dnp3_al_ctrq_b6 = -1;
  547. static int hf_dnp3_al_ctrq_b7 = -1;
  548. static int hf_dnp3_al_aiq_b0 = -1;
  549. static int hf_dnp3_al_aiq_b1 = -1;
  550. static int hf_dnp3_al_aiq_b2 = -1;
  551. static int hf_dnp3_al_aiq_b3 = -1;
  552. static int hf_dnp3_al_aiq_b4 = -1;
  553. static int hf_dnp3_al_aiq_b5 = -1;
  554. static int hf_dnp3_al_aiq_b6 = -1;
  555. static int hf_dnp3_al_aiq_b7 = -1;
  556. static int hf_dnp3_al_aoq_b0 = -1;
  557. static int hf_dnp3_al_aoq_b1 = -1;
  558. static int hf_dnp3_al_aoq_b2 = -1;
  559. static int hf_dnp3_al_aoq_b3 = -1;
  560. static int hf_dnp3_al_aoq_b4 = -1;
  561. static int hf_dnp3_al_aoq_b5 = -1;
  562. static int hf_dnp3_al_aoq_b6 = -1;
  563. static int hf_dnp3_al_aoq_b7 = -1;
  564. static int hf_dnp3_al_timestamp = -1;
  565. static int hf_dnp3_al_file_perms = -1;
  566. static int hf_dnp3_al_file_perms_read_owner = -1;
  567. static int hf_dnp3_al_file_perms_write_owner = -1;
  568. static int hf_dnp3_al_file_perms_exec_owner = -1;
  569. static int hf_dnp3_al_file_perms_read_group = -1;
  570. static int hf_dnp3_al_file_perms_write_group = -1;
  571. static int hf_dnp3_al_file_perms_exec_group = -1;
  572. static int hf_dnp3_al_file_perms_read_world = -1;
  573. static int hf_dnp3_al_file_perms_write_world = -1;
  574. static int hf_dnp3_al_file_perms_exec_world = -1;
  575. static int hf_dnp3_al_rel_timestamp = -1;
  576. static int hf_dnp3_al_ana16 = -1;
  577. static int hf_dnp3_al_ana32 = -1;
  578. static int hf_dnp3_al_anaflt = -1;
  579. static int hf_dnp3_al_anadbl = -1;
  580. static int hf_dnp3_al_bit = -1;
  581. static int hf_dnp3_al_2bit = -1;
  582. static int hf_dnp3_al_cnt16 = -1;
  583. static int hf_dnp3_al_cnt32 = -1;
  584. static int hf_dnp3_al_ctrlstatus = -1;
  585. static int hf_dnp3_al_anaout16 = -1;
  586. static int hf_dnp3_al_anaout32 = -1;
  587. static int hf_dnp3_al_anaoutflt = -1;
  588. static int hf_dnp3_al_anaoutdbl = -1;
  589. static int hf_dnp3_al_file_mode = -1;
  590. static int hf_dnp3_al_file_auth = -1;
  591. static int hf_dnp3_al_file_size = -1;
  592. static int hf_dnp3_al_file_maxblk = -1;
  593. static int hf_dnp3_al_file_reqID = -1;
  594. static int hf_dnp3_al_file_handle = -1;
  595. static int hf_dnp3_al_file_status = -1;
  596. static int hf_dnp3_al_file_blocknum = -1;
  597. static int hf_dnp3_al_file_lastblock = -1;
  598. static int hf_dnp3_al_file_data = -1;
  599. static int hf_dnp3_ctlobj_code_c = -1;
  600. static int hf_dnp3_ctlobj_code_m = -1;
  601. static int hf_dnp3_ctlobj_code_tc = -1;
  602. /***************************************************************************/
  603. /* Value String Look-Ups */
  604. /***************************************************************************/
  605. static const value_string dnp3_ctl_func_pri_vals[] = {
  606. { DL_FUNC_RESET_LINK, "Reset of Remote Link" },
  607. { DL_FUNC_RESET_PROC, "Reset of User Process" },
  608. { DL_FUNC_TEST_LINK, "Test Function For Link" },
  609. { DL_FUNC_USER_DATA, "User Data" },
  610. { DL_FUNC_UNC_DATA, "Unconfirmed User Data" },
  611. { DL_FUNC_LINK_STAT, "Request Link Status" },
  612. { 0, NULL }
  613. };
  614. static const value_string dnp3_ctl_func_sec_vals[] = {
  615. { DL_FUNC_ACK, "ACK" },
  616. { DL_FUNC_NACK, "NACK" },
  617. { DL_FUNC_STAT_LINK, "Status of Link" },
  618. { DL_FUNC_NO_FUNC, "Link Service Not Functioning" },
  619. { DL_FUNC_NOT_IMPL, "Link Service Not Used or Implemented" },
  620. { 0, NULL }
  621. };
  622. #if 0
  623. static const value_string dnp3_ctl_flags_pri_vals[] = {
  624. { DNP3_CTL_DIR, "DIR" },
  625. { DNP3_CTL_PRM, "PRM" },
  626. { DNP3_CTL_FCB, "FCB" },
  627. { DNP3_CTL_FCV, "FCV" },
  628. { 0, NULL }
  629. };
  630. #endif
  631. #if 0
  632. static const value_string dnp3_ctl_flags_sec_vals[]= {
  633. { DNP3_CTL_DIR, "DIR" },
  634. { DNP3_CTL_PRM, "PRM" },
  635. { DNP3_CTL_RES, "RES" },
  636. { DNP3_CTL_DFC, "DFC" },
  637. { 0, NULL }
  638. };
  639. #endif
  640. #if 0
  641. static const value_string dnp3_tr_flags_vals[] = {
  642. { DNP3_TR_FIN, "FIN" },
  643. { DNP3_TR_FIR, "FIR" },
  644. { 0, NULL }
  645. };
  646. #endif
  647. #if 0
  648. static const value_string dnp3_al_flags_vals[] = {
  649. { DNP3_AL_FIR, "FIR" },
  650. { DNP3_AL_FIN, "FIN" },
  651. { DNP3_AL_CON, "CON" },
  652. { DNP3_AL_UNS, "UNS" },
  653. { 0, NULL }
  654. };
  655. #endif
  656. /* Application Layer Function Code Values */
  657. static const value_string dnp3_al_func_vals[] = {
  658. { AL_FUNC_CONFIRM, "Confirm" },
  659. { AL_FUNC_READ, "Read" },
  660. { AL_FUNC_WRITE, "Write" },
  661. { AL_FUNC_SELECT, "Select" },
  662. { AL_FUNC_OPERATE, "Operate" },
  663. { AL_FUNC_DIROP, "Direct Operate" },
  664. { AL_FUNC_DIROPNACK, "Direct Operate No Ack" },
  665. { AL_FUNC_FRZ, "Immediate Freeze" },
  666. { AL_FUNC_FRZNACK, "Immediate Freeze No Ack" },
  667. { AL_FUNC_FRZCLR, "Freeze and Clear" },
  668. { AL_FUNC_FRZCLRNACK, "Freeze and Clear No ACK" },
  669. { AL_FUNC_FRZT, "Freeze With Time" },
  670. { AL_FUNC_FRZTNACK, "Freeze With Time No ACK" },
  671. { AL_FUNC_COLDRST, "Cold Restart" },
  672. { AL_FUNC_WARMRST, "Warm Restart" },
  673. { AL_FUNC_INITDATA, "Initialize Data" },
  674. { AL_FUNC_INITAPP, "Initialize Application" },
  675. { AL_FUNC_STARTAPP, "Start Application" },
  676. { AL_FUNC_STOPAPP, "Stop Application" },
  677. { AL_FUNC_SAVECFG, "Save Configuration" },
  678. { AL_FUNC_ENSPMSG, "Enable Spontaneous Messages" },
  679. { AL_FUNC_DISSPMSG, "Disable Spontaneous Messages" },
  680. { AL_FUNC_ASSIGNCL, "Assign Classes" },
  681. { AL_FUNC_DELAYMST, "Delay Measurement" },
  682. { AL_FUNC_RECCT, "Record Current Time" },
  683. { AL_FUNC_OPENFILE, "Open File" },
  684. { AL_FUNC_CLOSEFILE, "Close File" },
  685. { AL_FUNC_DELETEFILE, "Delete File" },
  686. { AL_FUNC_GETFILEINF, "Get File Info" },
  687. { AL_FUNC_AUTHFILE, "Authenticate File" },
  688. { AL_FUNC_ABORTFILE, "Abort File" },
  689. { AL_FUNC_ACTCNF, "Activate Config" },
  690. { AL_FUNC_AUTHREQ, "Authentication Request" },
  691. { AL_FUNC_AUTHERR, "Authentication Error" },
  692. { AL_FUNC_RESPON, "Response" },
  693. { AL_FUNC_UNSOLI, "Unsolicited Response" },
  694. { AL_FUNC_AUTHRESP, "Authentication Response" },
  695. { 0, NULL }
  696. };
  697. static value_string_ext dnp3_al_func_vals_ext = VALUE_STRING_EXT_INIT(dnp3_al_func_vals);
  698. #if 0
  699. /* Application Layer Internal Indication (IIN) bit Values */
  700. static const value_string dnp3_al_iin_vals[] = {
  701. { AL_IIN_BMSG, "Broadcast message Rx'd" },
  702. { AL_IIN_CLS1D, "Class 1 Data Available" },
  703. { AL_IIN_CLS2D, "Class 2 Data Available" },
  704. { AL_IIN_CLS3D, "Class 3 Data Available" },
  705. { AL_IIN_TSR, "Time Sync Required from Master" },
  706. { AL_IIN_DOL, "Outputs in Local Mode" },
  707. { AL_IIN_DT, "Device Trouble" },
  708. { AL_IIN_RST, "Device Restart" },
  709. { AL_IIN_FCNI, "Function Code not implemented" },
  710. { AL_IIN_OBJU, "Requested Objects Unknown" },
  711. { AL_IIN_PIOOR, "Parameters Invalid or Out of Range" },
  712. { AL_IIN_EBO, "Event Buffer Overflow" },
  713. { AL_IIN_OAE, "Operation Already Executing" },
  714. { AL_IIN_CC, "Device Configuration Corrupt" },
  715. { 0, NULL }
  716. };
  717. #endif
  718. /* Application Layer Object Qualifier Index Values When Qualifier Code != 11 */
  719. static const value_string dnp3_al_objq_index_vals[] = {
  720. { AL_OBJQL_IDX_NI, "None" },
  721. { AL_OBJQL_IDX_1O, "1-Octet Indexing" },
  722. { AL_OBJQL_IDX_2O, "2-Octet Indexing" },
  723. { AL_OBJQL_IDX_4O, "4-Octet Indexing" },
  724. { AL_OBJQL_IDX_1OS, "1-Octet Object Size" },
  725. { AL_OBJQL_IDX_2OS, "2-Octet Object Size" },
  726. { AL_OBJQL_IDX_4OS, "4-Octet Object Size" },
  727. { 0, NULL }
  728. };
  729. static value_string_ext dnp3_al_objq_index_vals_ext = VALUE_STRING_EXT_INIT(dnp3_al_objq_index_vals);
  730. /* Application Layer Object Qualifier Code Values */
  731. static const value_string dnp3_al_objq_code_vals[] = {
  732. { AL_OBJQL_CODE_SSI8, "8-bit Start and Stop Indices" },
  733. { AL_OBJQL_CODE_SSI16, "16-bit Start and Stop Indices" },
  734. { AL_OBJQL_CODE_SSI32, "32-bit Start and Stop Indices" },
  735. { AL_OBJQL_CODE_AA8, "8-bit Absolute Address in Range Field" },
  736. { AL_OBJQL_CODE_AA16, "16-bit Absolute Address in Range Field" },
  737. { AL_OBJQL_CODE_AA32, "32-bit Absolute Address in Range Field" },
  738. { AL_OBJQL_CODE_R0, "No Range Field" },
  739. { AL_OBJQL_CODE_SF8, "8-bit Single Field Quantity" },
  740. { AL_OBJQL_CODE_SF16, "16-bit Single Field Quantity" },
  741. { AL_OBJQL_CODE_SF32, "32-bit Single Field Quantity" },
  742. { 10, "Reserved" },
  743. { AL_OBJQL_CODE_FF, "Free-format Qualifier" },
  744. { 0, NULL }
  745. };
  746. static value_string_ext dnp3_al_objq_code_vals_ext = VALUE_STRING_EXT_INIT(dnp3_al_objq_code_vals);
  747. /* Application Layer Data Object Values */
  748. static const value_string dnp3_al_obj_vals[] = {
  749. { AL_OBJ_BI_ALL, "Binary Input Default Variation (Obj:01, Var:Default)" },
  750. { AL_OBJ_BI_1BIT, "Single-Bit Binary Input (Obj:01, Var:01)" },
  751. { AL_OBJ_BI_STAT, "Binary Input With Status (Obj:01, Var:02)" },
  752. { AL_OBJ_BIC_ALL, "Binary Input Change Default Variation (Obj:02, Var:Default)" },
  753. { AL_OBJ_BIC_NOTIME, "Binary Input Change Without Time (Obj:02, Var:01)" },
  754. { AL_OBJ_BIC_TIME, "Binary Input Change With Time (Obj:02, Var:02)" },
  755. { AL_OBJ_BIC_RTIME, "Binary Input Change With Relative Time (Obj:02, Var:03)" },
  756. { AL_OBJ_2BI_ALL, "Double-bit Input Default Variation (Obj:03, Var:Default)" },
  757. { AL_OBJ_2BI_NF, "Double-bit Input No Flags (Obj:03, Var:01)" },
  758. { AL_OBJ_2BI_STAT, "Double-bit Input With Status (Obj:03, Var:02)" },
  759. { AL_OBJ_2BIC_NOTIME, "Double-bit Input Change Without Time (Obj:04, Var:01)" },
  760. { AL_OBJ_2BIC_TIME, "Double-bit Input Change With Time (Obj:04, Var:02)" },
  761. { AL_OBJ_2BIC_RTIME, "Double-bit Input Change With Relative Time (Obj:04, Var:03)" },
  762. { AL_OBJ_BO_ALL, "Binary Output Default Variation (Obj:10, Var:Default)" },
  763. { AL_OBJ_BO, "Binary Output (Obj:10, Var:01)" },
  764. { AL_OBJ_BO_STAT, "Binary Output Status (Obj:10, Var:02)" },
  765. { AL_OBJ_BOC_ALL, "Binary Output Change Default Variation (Obj:11, Var:Default)" },
  766. { AL_OBJ_BOC_NOTIME, "Binary Output Change Without Time (Obj:11, Var:01)" },
  767. { AL_OBJ_BOC_TIME, "Binary Output Change With Time (Obj:11, Var:02)" },
  768. { AL_OBJ_CTLOP_BLK, "Control Relay Output Block (Obj:12, Var:01)" },
  769. { AL_OBJ_CTR_ALL, "Binary Counter Default Variation (Obj:20, Var:Default)" },
  770. { AL_OBJ_CTR_32, "32-Bit Binary Counter (Obj:20, Var:01)" },
  771. { AL_OBJ_CTR_16, "16-Bit Binary Counter (Obj:20, Var:02)" },
  772. { AL_OBJ_DCTR_32, "32-Bit Binary Delta Counter (Obj:20, Var:03)" },
  773. { AL_OBJ_DCTR_16, "16-Bit Binary Delta Counter (Obj:20, Var:04)" },
  774. { AL_OBJ_CTR_32NF, "32-Bit Binary Counter Without Flag (Obj:20, Var:05)" },
  775. { AL_OBJ_CTR_16NF, "16-Bit Binary Counter Without Flag (Obj:20, Var:06)" },
  776. { AL_OBJ_DCTR_32NF, "32-Bit Binary Delta Counter Without Flag (Obj:20, Var:07)" },
  777. { AL_OBJ_DCTR_16NF, "16-Bit Binary Delta Counter Without Flag (Obj:20, Var:08)" },
  778. { AL_OBJ_FCTR_ALL, "Frozen Binary Counter Default Variation (Obj:21, Var:Default)" },
  779. { AL_OBJ_FCTR_32, "32-Bit Frozen Binary Counter (Obj:21, Var:01)" },
  780. { AL_OBJ_FCTR_16, "16-Bit Frozen Binary Counter (Obj:21, Var:02)" },
  781. { AL_OBJ_FDCTR_32, "32-Bit Frozen Binary Delta Counter (Obj:21, Var:03)" },
  782. { AL_OBJ_FDCTR_16, "16-Bit Frozen Binary Delta Counter (Obj:21, Var:04)" },
  783. { AL_OBJ_FCTR_32T, "32-Bit Frozen Binary Counter (Obj:21, Var:01)" },
  784. { AL_OBJ_FCTR_16T, "16-Bit Frozen Binary Counter (Obj:21, Var:02)" },
  785. { AL_OBJ_FDCTR_32T, "32-Bit Frozen Binary Delta Counter (Obj:21, Var:03)" },
  786. { AL_OBJ_FDCTR_16T, "16-Bit Frozen Binary Delta Counter (Obj:21, Var:04)" },
  787. { AL_OBJ_FCTR_32NF, "32-Bit Frozen Binary Counter Without Flag (Obj:21, Var:05)" },
  788. { AL_OBJ_FCTR_16NF, "16-Bit Frozen Binary Counter Without Flag (Obj:21, Var:06)" },
  789. { AL_OBJ_FDCTR_32NF, "32-Bit Frozen Binary Delta Counter Without Flag (Obj:21, Var:07)" },
  790. { AL_OBJ_FDCTR_16NF, "16-Bit Frozen Binary Delta Counter Without Flag (Obj:21, Var:08)" },
  791. { AL_OBJ_CTRC_ALL, "Binary Counter Change Default Variation (Obj:22, Var:Default)" },
  792. { AL_OBJ_CTRC_32, "32-Bit Counter Change Event w/o Time (Obj:22, Var:01)" },
  793. { AL_OBJ_CTRC_16, "16-Bit Counter Change Event w/o Time (Obj:22, Var:02)" },
  794. { AL_OBJ_DCTRC_32, "32-Bit Delta Counter Change Event w/o Time (Obj:22, Var:03)" },
  795. { AL_OBJ_DCTRC_16, "16-Bit Delta Counter Change Event w/o Time (Obj:22, Var:04)" },
  796. { AL_OBJ_CTRC_32T, "32-Bit Counter Change Event with Time (Obj:22, Var:05)" },
  797. { AL_OBJ_CTRC_16T, "16-Bit Counter Change Event with Time (Obj:22, Var:06)" },
  798. { AL_OBJ_DCTRC_32T, "32-Bit Delta Counter Change Event with Time (Obj:22, Var:07)" },
  799. { AL_OBJ_DCTRC_16T, "16-Bit Delta Counter Change Event with Time (Obj:22, Var:08)" },
  800. { AL_OBJ_FCTRC_ALL, "Frozen Binary Counter Change Default Variation (Obj:23, Var:Default)" },
  801. { AL_OBJ_FCTRC_32, "32-Bit Frozen Counter Change Event w/o Time (Obj:23, Var:01)" },
  802. { AL_OBJ_FCTRC_16, "16-Bit Frozen Counter Change Event w/o Time (Obj:23, Var:02)" },
  803. { AL_OBJ_FDCTRC_32, "32-Bit Frozen Delta Counter Change Event w/o Time (Obj:23, Var:03)" },
  804. { AL_OBJ_FDCTRC_16, "16-Bit Frozen Delta Counter Change Event w/o Time (Obj:23, Var:04)" },
  805. { AL_OBJ_FCTRC_32T, "32-Bit Frozen Counter Change Event with Time (Obj:23, Var:05)" },
  806. { AL_OBJ_FCTRC_16T, "16-Bit Frozen Counter Change Event with Time (Obj:23, Var:06)" },
  807. { AL_OBJ_FDCTRC_32T, "32-Bit Frozen Delta Counter Change Event with Time (Obj:23, Var:07)" },
  808. { AL_OBJ_FDCTRC_16T, "16-Bit Frozen Delta Counter Change Event with Time (Obj:23, Var:08)" },
  809. { AL_OBJ_AI_ALL, "Analog Input Default Variation (Obj:30, Var:Default)" },
  810. { AL_OBJ_AI_32, "32-Bit Analog Input (Obj:30, Var:01)" },
  811. { AL_OBJ_AI_16, "16-Bit Analog Input (Obj:30, Var:02)" },
  812. { AL_OBJ_AI_32NF, "32-Bit Analog Input Without Flag (Obj:30, Var:03)" },
  813. { AL_OBJ_AI_16NF, "16-Bit Analog Input Without Flag (Obj:30, Var:04)" },
  814. { AL_OBJ_AI_FLT, "32-Bit Floating Point Input (Obj:30, Var:05)" },
  815. { AL_OBJ_AI_DBL, "64-Bit Floating Point Input (Obj:30, Var:06)" },
  816. { AL_OBJ_AIF_FLT, "32-Bit Frozen Floating Point Input (Obj:31, Var:07)" },
  817. { AL_OBJ_AIF_DBL, "64-Bit Frozen Floating Point Input (Obj:31, Var:08)" },
  818. { AL_OBJ_AIC_ALL, "Analog Input Change Default Variation (Obj:32, Var:Default)" },
  819. { AL_OBJ_AIC_32NT, "32-Bit Analog Change Event w/o Time (Obj:32, Var:01)" },
  820. { AL_OBJ_AIC_16NT, "16-Bit Analog Change Event w/o Time (Obj:32, Var:02)" },
  821. { AL_OBJ_AIC_32T, "32-Bit Analog Change Event with Time (Obj:32, Var:03)" },
  822. { AL_OBJ_AIC_16T, "16-Bit Analog Change Event with Time (Obj:32, Var:04)" },
  823. { AL_OBJ_AIC_FLTNT, "32-Bit Floating Point Change Event w/o Time (Obj:32, Var:05)" },
  824. { AL_OBJ_AIC_DBLNT, "64-Bit Floating Point Change Event w/o Time (Obj:32, Var:06)" },
  825. { AL_OBJ_AIC_FLTT, "32-Bit Floating Point Change Event w/ Time (Obj:32, Var:07)" },
  826. { AL_OBJ_AIC_DBLT, "64-Bit Floating Point Change Event w/ Time (Obj:32, Var:08)" },
  827. { AL_OBJ_AIFC_FLTNT, "32-Bit Floating Point Frozen Change Event w/o Time (Obj:33, Var:05)" },
  828. { AL_OBJ_AIFC_DBLNT, "64-Bit Floating Point Frozen Change Event w/o Time (Obj:33, Var:06)" },
  829. { AL_OBJ_AIFC_FLTT, "32-Bit Floating Point Frozen Change Event w/ Time (Obj:33, Var:07)" },
  830. { AL_OBJ_AIFC_DBLT, "64-Bit Floating Point Frozen Change Event w/ Time (Obj:33, Var:08)" },
  831. { AL_OBJ_AIDB_ALL, "Analog Input Deadband Default Variation (Obj:34, Var:Default)" },
  832. { AL_OBJ_AIDB_16, "16-Bit Analog Input Deadband (Obj:34, Var:01)" },
  833. { AL_OBJ_AIDB_32, "32-Bit Analog Input Deadband (Obj:34, Var:02)" },
  834. { AL_OBJ_AIDB_FLT, "32-Bit Floating Point Analog Input Deadband (Obj:34, Var:03)" },
  835. { AL_OBJ_AO_ALL, "Analog Output Default Variation (Obj:40, Var:Default)" },
  836. { AL_OBJ_AO_32, "32-Bit Analog Output Status (Obj:40, Var:01)" },
  837. { AL_OBJ_AO_16, "16-Bit Analog Output Status (Obj:40, Var:02)" },
  838. { AL_OBJ_AO_FLT, "32-Bit Floating Point Output Status (Obj:40, Var:03)" },
  839. { AL_OBJ_AO_DBL, "64-Bit Floating Point Output Status (Obj:40, Var:04)" },
  840. { AL_OBJ_AO_32OPB, "32-Bit Analog Output Block (Obj:41, Var:01)" },
  841. { AL_OBJ_AO_16OPB, "16-Bit Analog Output Block (Obj:41, Var:02)" },
  842. { AL_OBJ_AO_FLTOPB, "32-Bit Floating Point Output Block (Obj:41, Var:03)" },
  843. { AL_OBJ_AO_DBLOPB, "64-Bit Floating Point Output Block (Obj:41, Var:04)" },
  844. { AL_OBJ_AOC_ALL, "Analog Output Event Default Variation (Obj:42, Var:Default)" },
  845. { AL_OBJ_AOC_32NT, "32-Bit Analog Output Event w/o Time (Obj:42, Var:01)" },
  846. { AL_OBJ_AOC_16NT, "16-Bit Analog Output Event w/o Time (Obj:42, Var:02)" },
  847. { AL_OBJ_AOC_32T, "32-Bit Analog Output Event with Time (Obj:42, Var:03)" },
  848. { AL_OBJ_AOC_16T, "16-Bit Analog Output Event with Time (Obj:42, Var:04)" },
  849. { AL_OBJ_AOC_FLTNT, "32-Bit Floating Point Output Event w/o Time (Obj:42, Var:05)" },
  850. { AL_OBJ_AOC_DBLNT, "64-Bit Floating Point Output Event w/o Time (Obj:42, Var:06)" },
  851. { AL_OBJ_AOC_FLTT, "32-Bit Floating Point Output Event w/ Time (Obj:42, Var:07)" },
  852. { AL_OBJ_AOC_DBLT, "64-Bit Floating Point Output Event w/ Time (Obj:42, Var:08)" },
  853. { AL_OBJ_TD_ALL, "Time and Date Default Variations (Obj:50, Var:Default)" },
  854. { AL_OBJ_TD, "Time and Date (Obj:50, Var:01)" },
  855. { AL_OBJ_TDI, "Time and Date w/Interval (Obj:50, Var:02)" },
  856. { AL_OBJ_TDR, "Last Recorded Time and Date (Obj:50, Var:03)" },
  857. { AL_OBJ_TDCTO, "Time and Date CTO (Obj:51, Var:01)" },
  858. { AL_OBJ_TDELAYF, "Time Delay - Fine (Obj:52, Var:02)" },
  859. { AL_OBJ_CLASS0, "Class 0 Data (Obj:60, Var:01)" },
  860. { AL_OBJ_CLASS1, "Class 1 Data (Obj:60, Var:02)" },
  861. { AL_OBJ_CLASS2, "Class 2 Data (Obj:60, Var:03)" },
  862. { AL_OBJ_CLASS3, "Class 3 Data (Obj:60, Var:04)" },
  863. { AL_OBJ_FILE_CMD, "File Control - File Command (Obj:70, Var:03)" },
  864. { AL_OBJ_FILE_STAT, "File Control - File Status (Obj:70, Var:04)" },
  865. { AL_OBJ_FILE_TRANS, "File Control - File Transport (Obj:70, Var:05)" },
  866. { AL_OBJ_FILE_TRAN_ST, "File Control - File Transport Status (Obj:70, Var:06)" },
  867. { AL_OBJ_IIN, "Internal Indications (Obj:80, Var:01)" },
  868. { AL_OBJ_OCT, "Octet String (Obj:110)" },
  869. { AL_OBJ_OCT_EVT, "Octet String Event (Obj:111)" },
  870. { 0, NULL }
  871. };
  872. static value_string_ext dnp3_al_obj_vals_ext = VALUE_STRING_EXT_INIT(dnp3_al_obj_vals);
  873. /* Application Layer Control Code 'Operation Type' Values */
  874. static const value_string dnp3_al_ctlc_code_vals[] = {
  875. { AL_OBJCTLC_CODE0, "NUL Operation" },
  876. { AL_OBJCTLC_CODE1, "Pulse On" },
  877. { AL_OBJCTLC_CODE2, "Pulse Off" },
  878. { AL_OBJCTLC_CODE3, "Latch On" },
  879. { AL_OBJCTLC_CODE4, "Latch Off" },
  880. { 0, NULL }
  881. };
  882. /* Application Layer Control Code 'Clear Field' Values */
  883. static const value_string dnp3_al_ctlc_misc_vals[] = {
  884. { AL_OBJCTLC_QUEUE, "Queue" },
  885. { AL_OBJCTLC_CLEAR, "Clear" },
  886. { AL_OBJCTLC_NOTSET, "Not Set" },
  887. { AL_OBJCTLC_BOTHSET, "Queue and Clear" },
  888. { 0, NULL }
  889. };
  890. /* Application Layer Control Code 'Trip Close Code' Values */
  891. static const value_string dnp3_al_ctlc_tc_vals[] = {
  892. { AL_OBJCTLC_TC0, "NUL" },
  893. { AL_OBJCTLC_TC1, "Close" },
  894. { AL_OBJCTLC_TC2, "Trip" },
  895. { AL_OBJCTLC_TC3, "Reserved" },
  896. { 0, NULL }
  897. };
  898. /* Application Layer Control Status Values */
  899. static const value_string dnp3_al_ctl_status_vals[] = {
  900. { AL_OBJCTL_STAT0, "Req. Accepted/Init/Queued" },
  901. { AL_OBJCTL_STAT1, "Req. Not Accepted; Arm-Timer Expired" },
  902. { AL_OBJCTL_STAT2, "Req. Not Accepted; No 'SELECT' Received" },
  903. { AL_OBJCTL_STAT3, "Req. Not Accepted; Format Err. in Ctl Req." },
  904. { AL_OBJCTL_STAT4, "Ctl Oper. Not Supported For This Point" },
  905. { AL_OBJCTL_STAT5, "Req. Not Accepted; Ctrl Queue Full/Point Active" },
  906. { AL_OBJCTL_STAT6, "Req. Not Accepted; Ctrl Hardware Problems" },
  907. { AL_OBJCTL_STAT7, "Req. Not Accepted; Local/Remote switch in Local" },
  908. { AL_OBJCTL_STAT8, "Req. Not Accepted; Too many operations" },
  909. { AL_OBJCTL_STAT9, "Req. Not Accepted; Insufficient authorization" },
  910. { AL_OBJCTL_STAT10, "Req. Not Accepted; Local automation proc active" },
  911. { 0, NULL }
  912. };
  913. static value_string_ext dnp3_al_ctl_status_vals_ext = VALUE_STRING_EXT_INIT(dnp3_al_ctl_status_vals);
  914. #if 0
  915. /* Application Layer Binary Input Quality Flag Values */
  916. static const value_string dnp3_al_biflag_vals[] = {
  917. { AL_OBJ_BI_FLAG0, "Online" },
  918. { AL_OBJ_BI_FLAG1, "Restart" },
  919. { AL_OBJ_BI_FLAG2, "Comm Fail" },
  920. { AL_OBJ_BI_FLAG3, "Remote Forced" },
  921. { AL_OBJ_BI_FLAG4, "Locally Forced" },
  922. { AL_OBJ_BI_FLAG5, "Chatter Filter" },
  923. { 0, NULL }
  924. };
  925. #endif
  926. #if 0
  927. /* Application Layer Counter Quality Flag Values */
  928. static const value_string dnp3_al_ctrflag_vals[] = {
  929. { AL_OBJ_CTR_FLAG0, "Online" },
  930. { AL_OBJ_CTR_FLAG1, "Restart" },
  931. { AL_OBJ_CTR_FLAG2, "Comm Fail" },
  932. { AL_OBJ_CTR_FLAG3, "Remote Forced" },
  933. { AL_OBJ_CTR_FLAG4, "Locally Forced" },
  934. { AL_OBJ_CTR_FLAG5, "Roll-Over" },
  935. { AL_OBJ_CTR_FLAG6, "Discontinuity" },
  936. { 0, NULL }
  937. };
  938. #endif
  939. #if 0
  940. /* Application Layer Analog Input Quality Flag Values */
  941. static const value_string dnp3_al_aiflag_vals[] = {
  942. { AL_OBJ_AI_FLAG0, "Online" },
  943. { AL_OBJ_AI_FLAG1, "Restart" },
  944. { AL_OBJ_AI_FLAG2, "Comm Fail" },
  945. { AL_OBJ_AI_FLAG3, "Remote Forced" },
  946. { AL_OBJ_AI_FLAG4, "Locally Forced" },
  947. { AL_OBJ_AI_FLAG5, "Over-Range" },
  948. { AL_OBJ_AI_FLAG6, "Ref. Error" },
  949. { 0, NULL }
  950. };
  951. #endif
  952. /* Application Layer File Control Mode values */
  953. static const value_string dnp3_al_file_mode_vals[] = {
  954. { AL_OBJ_FILE_MODE_NULL, "NULL" },
  955. { AL_OBJ_FILE_MODE_READ, "READ" },
  956. { AL_OBJ_FILE_MODE_WRITE, "WRITE" },
  957. { AL_OBJ_FILE_MODE_APPEND, "APPEND" },
  958. { 0, NULL }
  959. };
  960. /* Application Layer File Control Status values */
  961. static const value_string dnp3_al_file_status_vals[] = {
  962. { 0, "SUCCESS" },
  963. { 1, "PERMISSION DENIED" },
  964. { 2, "INVALID MODE" },
  965. { 3, "FILE NOT FOUND" },
  966. { 4, "FILE LOCKED" },
  967. { 5, "TOO MANY OPEN" },
  968. { 6, "INVALID HANDLE" },
  969. { 7, "WRITE BLOCK SIZE" },
  970. { 8, "COMM LOST" },
  971. { 9, "CANNOT ABORT" },
  972. { 16, "NOT OPENED" },
  973. { 17, "HANDLE EXPIRED" },
  974. { 18, "BUFFER OVERRUN" },
  975. { 19, "FATAL" },
  976. { 20, "BLOCK SEQUENCE" },
  977. { 255, "UNDEFINED" },
  978. { 0, NULL }
  979. };
  980. static value_string_ext dnp3_al_file_status_vals_ext = VALUE_STRING_EXT_INIT(dnp3_al_file_status_vals);
  981. /* Initialize the subtree pointers */
  982. static gint ett_dnp3 = -1;
  983. static gint ett_dnp3_dl = -1;
  984. static gint ett_dnp3_dl_ctl = -1;
  985. static gint ett_dnp3_tr_ctl = -1;
  986. static gint ett_dnp3_al_data = -1;
  987. static gint ett_dnp3_al = -1;
  988. static gint ett_dnp3_al_ctl = -1;
  989. static gint ett_dnp3_al_obj_point_tcc = -1;
  990. /* Added for Application Layer Decoding */
  991. static gint ett_dnp3_al_iin = -1;
  992. static gint ett_dnp3_al_obj = -1;
  993. static gint ett_dnp3_al_obj_qualifier = -1;
  994. static gint ett_dnp3_al_obj_range = -1;
  995. static gint ett_dnp3_al_objdet = -1;
  996. static gint ett_dnp3_al_obj_quality = -1;
  997. static gint ett_dnp3_al_obj_point = -1;
  998. static gint ett_dnp3_al_obj_point_perms = -1;
  999. static expert_field ei_dnp_num_items_neg = EI_INIT;
  1000. static expert_field ei_dnp_invalid_length = EI_INIT;
  1001. /* Tables for reassembly of fragments. */
  1002. static reassembly_table al_reassembly_table;
  1003. static GHashTable *dl_conversation_table = NULL;
  1004. /* Data-Link-Layer Conversation Key Structure */
  1005. typedef struct _dl_conversation_key
  1006. {
  1007. guint32 conversation; /* TCP / UDP conversation index */
  1008. guint16 src; /* DNP3.0 Source Address */
  1009. guint16 dst; /* DNP3.0 Destination Address */
  1010. } dl_conversation_key_t;
  1011. /* Data-Link-Layer conversation key equality function */
  1012. static gboolean
  1013. dl_conversation_equal(gconstpointer v, gconstpointer w)
  1014. {
  1015. const dl_conversation_key_t* v1 = (const dl_conversation_key_t*)v;
  1016. const dl_conversation_key_t* v2 = (const dl_conversation_key_t*)w;
  1017. if ((v1->conversation == v2->conversation) &&
  1018. (v1->src == v2->src) &&
  1019. (v1->dst == v2->dst))
  1020. {
  1021. return TRUE;
  1022. }
  1023. return FALSE;
  1024. }
  1025. /* Data-Link-Layer conversation key hash function */
  1026. static guint
  1027. dl_conversation_hash(gconstpointer v)
  1028. {
  1029. const dl_conversation_key_t *key = (const dl_conversation_key_t*)v;
  1030. guint val;
  1031. val = key->conversation + (key->src << 16) + key->dst;
  1032. return val;
  1033. }
  1034. /* ************************************************************************* */
  1035. /* Header values for reassembly */
  1036. /* ************************************************************************* */
  1037. static int hf_dnp3_fragment = -1;
  1038. static int hf_dnp3_fragments = -1;
  1039. static int hf_dnp3_fragment_overlap = -1;
  1040. static int hf_dnp3_fragment_overlap_conflict = -1;
  1041. static int hf_dnp3_fragment_multiple_tails = -1;
  1042. static int hf_dnp3_fragment_too_long_fragment = -1;
  1043. static int hf_dnp3_fragment_error = -1;
  1044. static int hf_dnp3_fragment_count = -1;
  1045. static int hf_dnp3_fragment_reassembled_in = -1;
  1046. static int hf_dnp3_fragment_reassembled_length = -1;
  1047. static gint ett_dnp3_fragment = -1;
  1048. static gint ett_dnp3_fragments = -1;
  1049. static const fragment_items dnp3_frag_items = {
  1050. &ett_dnp3_fragment,
  1051. &ett_dnp3_fragments,
  1052. &hf_dnp3_fragments,
  1053. &hf_dnp3_fragment,
  1054. &hf_dnp3_fragment_overlap,
  1055. &hf_dnp3_fragment_overlap_conflict,
  1056. &hf_dnp3_fragment_multiple_tails,
  1057. &hf_dnp3_fragment_too_long_fragment,
  1058. &hf_dnp3_fragment_error,
  1059. &hf_dnp3_fragment_count,
  1060. &hf_dnp3_fragment_reassembled_in,
  1061. &hf_dnp3_fragment_reassembled_length,
  1062. /* Reassembled data field */
  1063. NULL,
  1064. "DNP 3.0 fragments"
  1065. };
  1066. /* Conversation stuff, used for tracking application message fragments */
  1067. /* the number of entries in the memory chunk array */
  1068. #define dnp3_conv_init_count 50
  1069. /* Conversation structure */
  1070. typedef struct {
  1071. guint conv_seq_number;
  1072. } dnp3_conv_t;
  1073. /* The conversation sequence number */
  1074. static guint seq_number = 0;
  1075. /* Heuristically detect DNP3 over TCP/UDP */
  1076. static gboolean dnp3_heuristics = FALSE;
  1077. /* desegmentation of DNP3 over TCP */
  1078. static gboolean dnp3_desegment = TRUE;
  1079. /* Enum for different quality type fields */
  1080. enum QUALITY_TYPE {
  1081. BIN_IN,
  1082. BIN_OUT,
  1083. ANA_IN,
  1084. ANA_OUT,
  1085. COUNTER
  1086. };
  1087. /*****************************************************************/
  1088. /* */
  1089. /* CRC LOOKUP TABLE */
  1090. /* ================ */
  1091. /* The following CRC lookup table was generated automagically */
  1092. /* by the Rocksoft^tm Model CRC Algorithm Table Generation */
  1093. /* Program V1.0 using the following model parameters: */
  1094. /* */
  1095. /* Width : 2 bytes. */
  1096. /* Poly : 0x3D65 */
  1097. /* Reverse : TRUE. */
  1098. /* */
  1099. /* For more information on the Rocksoft^tm Model CRC Algorithm, */
  1100. /* see the document titled "A Painless Guide to CRC Error */
  1101. /* Detection Algorithms" by Ross Williams */
  1102. /* (ross@guest.adelaide.edu.au.). This document is likely to be */
  1103. /* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */
  1104. /* */
  1105. /*****************************************************************/
  1106. static guint16 crctable[256] =
  1107. {
  1108. 0x0000, 0x365E, 0x6CBC, 0x5AE2, 0xD978, 0xEF26, 0xB5C4, 0x839A,
  1109. 0xFF89, 0xC9D7, 0x9335, 0xA56B, 0x26F1, 0x10AF, 0x4A4D, 0x7C13,
  1110. 0xB26B, 0x8435, 0xDED7, 0xE889, 0x6B13, 0x5D4D, 0x07AF, 0x31F1,
  1111. 0x4DE2, 0x7BBC, 0x215E, 0x1700, 0x949A, 0xA2C4, 0xF826, 0xCE78,
  1112. 0x29AF, 0x1FF1, 0x4513, 0x734D, 0xF0D7, 0xC689, 0x9C6B, 0xAA35,
  1113. 0xD626, 0xE078, 0xBA9A, 0x8CC4, 0x0F5E, 0x3900, 0x63E2, 0x55BC,
  1114. 0x9BC4, 0xAD9A, 0xF778, 0xC126, 0x42BC, 0x74E2, 0x2E00, 0x185E,
  1115. 0x644D, 0x5213, 0x08F1, 0x3EAF, 0xBD35, 0x8B6B, 0xD189, 0xE7D7,
  1116. 0x535E, 0x6500, 0x3FE2, 0x09BC, 0x8A26, 0xBC78, 0xE69A, 0xD0C4,
  1117. 0xACD7, 0x9A89, 0xC06B, 0xF635, 0x75AF, 0x43F1, 0x1913, 0x2F4D,
  1118. 0xE135, 0xD76B, 0x8D89, 0xBBD7, 0x384D, 0x0E13, 0x54F1, 0x62AF,
  1119. 0x1EBC, 0x28E2, 0x7200, 0x445E, 0xC7C4, 0xF19A, 0xAB78, 0x9D26,
  1120. 0x7AF1, 0x4CAF, 0x164D, 0x2013, 0xA389, 0x95D7, 0xCF35, 0xF96B,
  1121. 0x8578, 0xB326, 0xE9C4, 0xDF9A, 0x5C00, 0x6A5E, 0x30BC, 0x06E2,
  1122. 0xC89A, 0xFEC4, 0xA426, 0x9278, 0x11E2, 0x27BC, 0x7D5E, 0x4B00,
  1123. 0x3713, 0x014D, 0x5BAF, 0x6DF1, 0xEE6B, 0xD835, 0x82D7, 0xB489,
  1124. 0xA6BC, 0x90E2, 0xCA00, 0xFC5E, 0x7FC4, 0x499A, 0x1378, 0x2526,
  1125. 0x5935, 0x6F6B, 0x3589, 0x03D7, 0x804D, 0xB613, 0xECF1, 0xDAAF,
  1126. 0x14D7, 0x2289, 0x786B, 0x4E35, 0xCDAF, 0xFBF1, 0xA113, 0x974D,
  1127. 0xEB5E, 0xDD00, 0x87E2, 0xB1BC, 0x3226, 0x0478, 0x5E9A, 0x68C4,
  1128. 0x8F13, 0xB94D, 0xE3AF, 0xD5F1, 0x566B, 0x6035, 0x3AD7, 0x0C89,
  1129. 0x709A, 0x46C4, 0x1C26, 0x2A78, 0xA9E2, 0x9FBC, 0xC55E, 0xF300,
  1130. 0x3D78, 0x0B26, 0x51C4, 0x679A, 0xE400, 0xD25E, 0x88BC, 0xBEE2,
  1131. 0xC2F1, 0xF4AF, 0xAE4D, 0x9813, 0x1B89, 0x2DD7, 0x7735, 0x416B,
  1132. 0xF5E2, 0xC3BC, 0x995E, 0xAF00, 0x2C9A, 0x1AC4, 0x4026, 0x7678,
  1133. 0x0A6B, 0x3C35, 0x66D7, 0x5089, 0xD313, 0xE54D, 0xBFAF, 0x89F1,
  1134. 0x4789, 0x71D7, 0x2B35, 0x1D6B, 0x9EF1, 0xA8AF, 0xF24D, 0xC413,
  1135. 0xB800, 0x8E5E, 0xD4BC, 0xE2E2, 0x6178, 0x5726, 0x0DC4, 0x3B9A,
  1136. 0xDC4D, 0xEA13, 0xB0F1, 0x86AF, 0x0535, 0x336B, 0x6989, 0x5FD7,
  1137. 0x23C4, 0x159A, 0x4F78, 0x7926, 0xFABC, 0xCCE2, 0x9600, 0xA05E,
  1138. 0x6E26, 0x5878, 0x029A, 0x34C4, 0xB75E, 0x8100, 0xDBE2, 0xEDBC,
  1139. 0x91AF, 0xA7F1, 0xFD13, 0xCB4D, 0x48D7, 0x7E89, 0x246B, 0x1235
  1140. };
  1141. /*****************************************************************/
  1142. /* End of CRC Lookup Table */
  1143. /*****************************************************************/
  1144. /* calculates crc given a buffer of characters and a length of buffer */
  1145. static guint16
  1146. calculateCRC(const void *buf, guint len) {
  1147. guint16 crc = 0;
  1148. const guint8 *p = (const guint8 *)buf;
  1149. while (len-- > 0)
  1150. crc = crctable[(crc ^ *p++) & 0xff] ^ (crc >> 8);
  1151. return ~crc;
  1152. }
  1153. /*****************************************************************/
  1154. /* Adds text to item, with trailing "," if required */
  1155. /*****************************************************************/
  1156. static gboolean
  1157. add_item_text(proto_item *item, const gchar *text, gboolean comma_needed)
  1158. {
  1159. if (comma_needed) {
  1160. proto_item_append_text(item, ", ");
  1161. }
  1162. proto_item_append_text(item, "%s", text);
  1163. return TRUE;
  1164. }
  1165. /*****************************************************************/
  1166. /* Application Layer Process Internal Indications (IIN) */
  1167. /*****************************************************************/
  1168. static void
  1169. dnp3_al_process_iin(tvbuff_t *tvb, int offset, proto_tree *al_tree)
  1170. {
  1171. guint16 al_iin;
  1172. proto_item *tiin;
  1173. proto_tree *iin_tree;
  1174. gboolean comma_needed = FALSE;
  1175. al_iin = tvb_get_ntohs(tvb, offset);
  1176. tiin = proto_tree_add_uint_format(al_tree, hf_dnp3_al_iin, tvb, offset, 2, al_iin,
  1177. "Internal Indications: ");
  1178. if (al_iin & AL_IIN_RST) comma_needed = add_item_text(tiin, "Device Restart", comma_needed);
  1179. if (al_iin & AL_IIN_DOL) comma_needed = add_item_text(tiin, "Outputs in Local", comma_needed);
  1180. if (al_iin & AL_IIN_DT) comma_needed = add_item_text(tiin, "Device Trouble", comma_needed);
  1181. if (al_iin & AL_IIN_TSR) comma_needed = add_item_text(tiin, "Time Sync Required", comma_needed);
  1182. if (al_iin & AL_IIN_CLS3D) comma_needed = add_item_text(tiin, "Class 3 Data Available", comma_needed);
  1183. if (al_iin & AL_IIN_CLS2D) comma_needed = add_item_text(tiin, "Class 2 Data Available", comma_needed);
  1184. if (al_iin & AL_IIN_CLS1D) comma_needed = add_item_text(tiin, "Class 1 Data Available", comma_needed);
  1185. if (al_iin & AL_IIN_BMSG) comma_needed = add_item_text(tiin, "Broadcast Message Rx'd", comma_needed);
  1186. if (al_iin & AL_IIN_CC) comma_needed = add_item_text(tiin, "Device Configuration Corrupt", comma_needed);
  1187. if (al_iin & AL_IIN_OAE) comma_needed = add_item_text(tiin, "Operation Already Executing", comma_needed);
  1188. if (al_iin & AL_IIN_EBO) comma_needed = add_item_text(tiin, "Event Buffer Overflow", comma_needed);
  1189. if (al_iin & AL_IIN_PIOOR) comma_needed = add_item_text(tiin, "Parameters Invalid or Out of Range", comma_needed);
  1190. if (al_iin & AL_IIN_OBJU) comma_needed = add_item_text(tiin, "Requested Objects Unknown", comma_needed);
  1191. if (al_iin & AL_IIN_FCNI) /*comma_needed = */add_item_text(tiin, "Function code not implemented", comma_needed);
  1192. proto_item_append_text(tiin, " (0x%04x)", al_iin);
  1193. iin_tree = proto_item_add_subtree(tiin, ett_dnp3_al_iin);
  1194. proto_tree_add_item(iin_tree, hf_dnp3_al_iin_rst, tvb, offset, 2, ENC_BIG_ENDIAN);
  1195. proto_tree_add_item(iin_tree, hf_dnp3_al_iin_dt, tvb, offset, 2, ENC_BIG_ENDIAN);
  1196. proto_tree_add_item(iin_tree, hf_dnp3_al_iin_dol, tvb, offset, 2, ENC_BIG_ENDIAN);
  1197. proto_tree_add_item(iin_tree, hf_dnp3_al_iin_tsr, tvb, offset, 2, ENC_BIG_ENDIAN);
  1198. proto_tree_add_item(iin_tree, hf_dnp3_al_iin_cls3d, tvb, offset, 2, ENC_BIG_ENDIAN);
  1199. proto_tree_add_item(iin_tree, hf_dnp3_al_iin_cls2d, tvb, offset, 2, ENC_BIG_ENDIAN);
  1200. proto_tree_add_item(iin_tree, hf_dnp3_al_iin_cls1d, tvb, offset, 2, ENC_BIG_ENDIAN);
  1201. proto_tree_add_item(iin_tree, hf_dnp3_al_iin_bmsg, tvb, offset, 2, ENC_BIG_ENDIAN);
  1202. proto_tree_add_item(iin_tree, hf_dnp3_al_iin_cc, tvb, offset, 2, ENC_BIG_ENDIAN);
  1203. proto_tree_add_item(iin_tree, hf_dnp3_al_iin_oae, tvb, offset, 2, ENC_BIG_ENDIAN);
  1204. proto_tree_add_item(iin_tree, hf_dnp3_al_iin_ebo, tvb, offset, 2, ENC_BIG_ENDIAN);
  1205. proto_tree_add_item(iin_tree, hf_dnp3_al_iin_pioor, tvb, offset, 2, ENC_BIG_ENDIAN);
  1206. proto_tree_add_item(iin_tree, hf_dnp3_al_iin_obju, tvb, offset, 2, ENC_BIG_ENDIAN);
  1207. proto_tree_add_item(iin_tree, hf_dnp3_al_iin_fcni, tvb, offset, 2, ENC_BIG_ENDIAN);
  1208. }
  1209. /*****************************************************************/
  1210. /* Function to determine Application Layer Object Index size and */
  1211. /* Point address. */
  1212. /*****************************************************************/
  1213. static int
  1214. dnp3_al_obj_procindex(tvbuff_t *tvb, int offset, guint8 al_objq_index, guint32 *al_ptaddr, proto_tree *item_tree)
  1215. {
  1216. int indexbytes = 0;
  1217. proto_item *index_item;
  1218. switch (al_objq_index)
  1219. {
  1220. case AL_OBJQL_IDX_NI: /* No Index */
  1221. indexbytes = 0;
  1222. index_item = proto_tree_add_text(item_tree, tvb, offset, 0, "Point Index: %u", *al_ptaddr);
  1223. PROTO_ITEM_SET_GENERATED(index_item);
  1224. break;
  1225. case AL_OBJQL_IDX_1O:
  1226. *al_ptaddr = tvb_get_guint8(tvb, offset);
  1227. proto_tree_add_item(item_tree, hf_dnp3_al_index8, tvb, offset, 1, ENC_LITTLE_ENDIAN);
  1228. indexbytes = 1;
  1229. break;
  1230. case AL_OBJQL_IDX_2O:
  1231. *al_ptaddr = tvb_get_letohs(tvb, offset);
  1232. proto_tree_add_item(item_tree, hf_dnp3_al_index16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
  1233. indexbytes = 2;
  1234. break;
  1235. case AL_OBJQL_IDX_4O:
  1236. *al_ptaddr = tvb_get_letohl(tvb, offset);
  1237. proto_tree_add_item(item_tree, hf_dnp3_al_index32, tvb, offset, 4, ENC_LITTLE_ENDIAN);
  1238. indexbytes = 4;
  1239. break;
  1240. case AL_OBJQL_IDX_1OS:
  1241. *al_ptaddr = tvb_get_guint8(tvb, offset);
  1242. proto_tree_add_item(item_tree, hf_dnp3_al_size8, tvb, offset, 1, ENC_LITTLE_ENDIAN);
  1243. indexbytes = 1;
  1244. break;
  1245. case AL_OBJQL_IDX_2OS:
  1246. *al_ptaddr = tvb_get_letohs(tvb, offset);
  1247. proto_tree_add_item(item_tree, hf_dnp3_al_size16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
  1248. indexbytes = 2;
  1249. break;
  1250. case AL_OBJQL_IDX_4OS:
  1251. *al_ptaddr = tvb_get_letohl(tvb, offset);
  1252. proto_tree_add_item(item_tree, hf_dnp3_al_size32, tvb, offset, 4, ENC_LITTLE_ENDIAN);
  1253. indexbytes = 4;
  1254. break;
  1255. }
  1256. return indexbytes;
  1257. }
  1258. /*****************************************************************/
  1259. /* Function to add the same string to two separate tree items */
  1260. /*****************************************************************/
  1261. static void
  1262. dnp3_append_2item_text(proto_item *item1, proto_item *item2, const gchar *text)
  1263. {
  1264. proto_item_append_text(item1, "%s", text);
  1265. proto_item_append_text(item2, "%s", text);
  1266. }
  1267. /*****************************************************************/
  1268. /* Function to Determine Application Layer Point Quality Flags & */
  1269. /* add Point Quality Flag Sub-Tree */
  1270. /*****************************************************************/
  1271. static void
  1272. dnp3_al_obj_quality(tvbuff_t *tvb, int offset, guint8 al_ptflags, proto_tree *point_tree, proto_item *point_item, enum QUALITY_TYPE type)
  1273. {
  1274. proto_tree *quality_tree;
  1275. proto_item *quality_item;
  1276. int hf0 = 0, hf1 = 0, hf2 = 0, hf3 = 0, hf4 = 0, hf5 = 0, hf6 = 0, hf7 = 0;
  1277. /* Common code */
  1278. proto_item_append_text(point_item, " (Quality: ");
  1279. quality_item = proto_tree_add_text(point_tree, tvb, offset, 1, "Quality: ");
  1280. quality_tree = proto_item_add_subtree(quality_item, ett_dnp3_al_obj_quality);
  1281. if (al_ptflags & AL_OBJ_BI_FLAG0) {
  1282. dnp3_append_2item_text(point_item, quality_item, "Online");
  1283. }
  1284. else {
  1285. dnp3_append_2item_text(point_item, quality_item, "Offline");
  1286. }
  1287. if (al_ptflags & AL_OBJ_BI_FLAG1) dnp3_append_2item_text(point_item, quality_item, ", Restart");
  1288. if (al_ptflags & AL_OBJ_BI_FLAG2) dnp3_append_2item_text(point_item, quality_item, ", Comm Fail");
  1289. if (al_ptflags & AL_OBJ_BI_FLAG3) dnp3_append_2item_text(point_item, quality_item, ", Remote Force");
  1290. if (al_ptflags & AL_OBJ_BI_FLAG4) dnp3_append_2item_text(point_item, quality_item, ", Local Force");
  1291. switch (type) {
  1292. case BIN_IN: /* Binary Input Quality flags */
  1293. if (al_ptflags & AL_OBJ_BI_FLAG5) dnp3_append_2item_text(point_item, quality_item, ", Chatter Filter");
  1294. hf0 = hf_dnp3_al_biq_b0;
  1295. hf1 = hf_dnp3_al_biq_b1;
  1296. hf2 = hf_dnp3_al_biq_b2;
  1297. hf3 = hf_dnp3_al_biq_b3;
  1298. hf4 = hf_dnp3_al_biq_b4;
  1299. hf5 = hf_dnp3_al_biq_b5;
  1300. hf6 = hf_dnp3_al_biq_b6;
  1301. hf7 = hf_dnp3_al_biq_b7;
  1302. break;
  1303. case BIN_OUT: /* Binary Output Quality flags */
  1304. hf0 = hf_dnp3_al_boq_b0;
  1305. hf1 = hf_dnp3_al_boq_b1;
  1306. hf2 = hf_dnp3_al_boq_b2;
  1307. hf3 = hf_dnp3_al_boq_b3;
  1308. hf4 = hf_dnp3_al_boq_b4;
  1309. hf5 = hf_dnp3_al_boq_b5;
  1310. hf6 = hf_dnp3_al_boq_b6;
  1311. hf7 = hf_dnp3_al_boq_b7;
  1312. break;
  1313. case ANA_IN: /* Analog Input Quality flags */
  1314. if (al_ptflags & AL_OBJ_AI_FLAG5) dnp3_append_2item_text(point_item, quality_item, ", Over-Range");
  1315. if (al_ptflags & AL_OBJ_AI_FLAG6) dnp3_append_2item_text(point_item, quality_item, ", Reference Check");
  1316. hf0 = hf_dnp3_al_aiq_b0;
  1317. hf1 = hf_dnp3_al_aiq_b1;
  1318. hf2 = hf_dnp3_al_aiq_b2;
  1319. hf3 = hf_dnp3_al_aiq_b3;
  1320. hf4 = hf_dnp3_al_aiq_b4;
  1321. hf5 = hf_dnp3_al_aiq_b5;
  1322. hf6 = hf_dnp3_al_aiq_b6;
  1323. hf7 = hf_dnp3_al_aiq_b7;
  1324. break;
  1325. case ANA_OUT: /* Analog Output Quality flags */
  1326. hf0 = hf_dnp3_al_aoq_b0;
  1327. hf1 = hf_dnp3_al_aoq_b1;
  1328. hf2 = hf_dnp3_al_aoq_b2;
  1329. hf3 = hf_dnp3_al_aoq_b3;
  1330. hf4 = hf_dnp3_al_aoq_b4;
  1331. hf5 = hf_dnp3_al_aoq_b5;
  1332. hf6 = hf_dnp3_al_aoq_b6;
  1333. hf7 = hf_dnp3_al_aoq_b7;
  1334. break;
  1335. case COUNTER: /* Counter Quality flags */
  1336. if (al_ptflags & AL_OBJ_CTR_FLAG5) dnp3_append_2item_text(point_item, quality_item, ", Roll-over");
  1337. if (al_ptflags & AL_OBJ_CTR_FLAG6) dnp3_append_2item_text(point_item, quality_item, ", Discontinuity");
  1338. hf0 = hf_dnp3_al_ctrq_b0;
  1339. hf1 = hf_dnp3_al_ctrq_b1;
  1340. hf2 = hf_dnp3_al_ctrq_b2;
  1341. hf3 = hf_dnp3_al_ctrq_b3;
  1342. hf4 = hf_dnp3_al_ctrq_b4;
  1343. hf5 = hf_dnp3_al_ctrq_b5;
  1344. hf6 = hf_dnp3_al_ctrq_b6;
  1345. hf7 = hf_dnp3_al_ctrq_b7;
  1346. break;
  1347. }
  1348. if (quality_tree != NULL) {
  1349. proto_tree_add_item(quality_tree, hf7, tvb, offset, 1, ENC_LITTLE_ENDIAN);
  1350. proto_tree_add_item(quality_tree, hf6, tvb, offset, 1, ENC_LITTLE_ENDIAN);
  1351. proto_tree_add_item(quality_tree, hf5, tvb, offset, 1, ENC_LITTLE_ENDIAN);
  1352. proto_tree_add_item(quality_tree, hf4, tvb, offset, 1, ENC_LITTLE_ENDIAN);
  1353. proto_tree_add_item(quality_tree, hf3, tvb, offset, 1, ENC_LITTLE_ENDIAN);
  1354. proto_tree_add_item(quality_tree, hf2, tvb, offset, 1, ENC_LITTLE_ENDIAN);
  1355. proto_tree_add_item(quality_tree, hf1, tvb, offset, 1, ENC_LITTLE_ENDIAN);
  1356. proto_tree_add_item(quality_tree, hf0, tvb, offset, 1, ENC_LITTLE_ENDIAN);
  1357. }
  1358. proto_item_append_text(point_item, ")");
  1359. }
  1360. /**********************************************************************/
  1361. /* Function to convert DNP3 timestamp to nstime_t value */
  1362. /**********************************************************************/
  1363. /* 48-bit Time Format */
  1364. /* MSB FF EE DD CC BB AA LSB */
  1365. /* ffffffff eeeeeeee dddddddd cccccccc bbbbbbbb aaaaaaaa */
  1366. /* 47 40 39 32 31 24 23 16 15 8 7 0 */
  1367. /* */
  1368. /* Value is ms since 00:00 on 1/1/1970 */
  1369. /**********************************************************************/
  1370. static void
  1371. dnp3_al_get_timestamp(nstime_t *timestamp, tvbuff_t *tvb, int data_pos)
  1372. {
  1373. guint32 hi, lo;
  1374. guint64 time_ms;
  1375. lo = tvb_get_letohs(tvb, data_pos);
  1376. hi = tvb_get_letohl(tvb, data_pos + 2);
  1377. time_ms = (guint64)hi * 0x10000 + lo;
  1378. timestamp->secs = (long)(time_ms / 1000);
  1379. timestamp->nsecs = (int)(time_ms % 1000) * 1000000;
  1380. }
  1381. /*****************************************************************/
  1382. /* Desc: Application Layer Process Object Details */
  1383. /* Returns: New offset pointer into tvb */
  1384. /*****************************************************************/
  1385. static int
  1386. dnp3_al_process_object(tvbuff_t *tvb, packet_info *pinfo, int offset,
  1387. proto_tree *robj_tree, gboolean header_only,
  1388. guint16 *al_objtype, nstime_t *al_cto)
  1389. {
  1390. guint8 al_objq, al_objq_index, al_objq_code, al_oct_len = 0, bitindex;
  1391. guint16 al_obj, temp;
  1392. guint32 al_ptaddr = 0;
  1393. int num_items = 0;
  1394. int orig_offset, rangebytes = 0;
  1395. proto_item *object_item, *qualifier_item, *range_item;
  1396. proto_tree *object_tree, *qualifier_tree, *range_tree;
  1397. orig_offset = offset;
  1398. /* Application Layer Objects in this Message */
  1399. *al_objtype =
  1400. al_obj = tvb_get_ntohs(tvb, offset);
  1401. /* Special handling for Octet string objects as the variation is the length of the string */
  1402. temp = al_obj & 0xFF00;
  1403. if ((temp == AL_OBJ_OCT) || (temp == AL_OBJ_OCT_EVT )) {
  1404. al_oct_len = al_obj & 0xFF;
  1405. al_obj = temp;
  1406. }
  1407. /* Create Data Objects Detail Tree */
  1408. object_item = proto_tree_add_uint_format(robj_tree, hf_dnp3_al_obj, tvb, offset, 2, al_obj,
  1409. "Object(s): %s (0x%04x)",
  1410. val_to_str_ext_const(al_obj, &dnp3_al_obj_vals_ext, "Unknown Object - Abort Decoding..."),
  1411. al_obj);
  1412. object_tree = proto_item_add_subtree(object_item, ett_dnp3_al_obj);
  1413. offset += 2;
  1414. /* Object Qualifier */
  1415. al_objq = tvb_get_guint8(tvb, offset);
  1416. al_objq_index = al_objq & AL_OBJQ_INDEX;
  1417. al_objq_index = al_objq_index >> 4;
  1418. al_objq_code = al_objq & AL_OBJQ_CODE;
  1419. qualifier_item = proto_tree_add_text(object_tree, tvb, offset, 1, "Qualifier Field, Prefix: %s, Code: %s",
  1420. val_to_str_ext_const(al_objq_index, &dnp3_al_objq_index_vals_ext, "Unknown Index Type"),
  1421. val_to_str_ext_const(al_objq_code, &dnp3_al_objq_code_vals_ext, "Unknown Code Type"));
  1422. qualifier_tree = proto_item_add_subtree(qualifier_item, ett_dnp3_al_obj_qualifier);
  1423. proto_tree_add_item(qualifier_tree, hf_dnp3_al_objq_index, tvb, offset, 1, ENC_BIG_ENDIAN);
  1424. proto_tree_add_item(qualifier_tree, hf_dnp3_al_objq_code, tvb, offset, 1, ENC_BIG_ENDIAN);
  1425. offset += 1;
  1426. /* Create (possibly synthesized) number of items and range field tree */
  1427. range_item = proto_tree_add_text(object_tree, tvb, offset, 0, "Number of Items: ");
  1428. range_tree = proto_item_add_subtree(range_item, ett_dnp3_al_obj_range);
  1429. switch (al_objq_code)
  1430. {
  1431. case AL_OBJQL_CODE_SSI8: /* 8-bit Start and Stop Indices in Range Field */
  1432. num_items = ( tvb_get_guint8(tvb, offset+1) - tvb_get_guint8(tvb, offset) + 1);
  1433. PROTO_ITEM_SET_GENERATED(range_item);
  1434. al_ptaddr = tvb_get_guint8(tvb, offset);
  1435. proto_tree_add_item(range_tree, hf_dnp3_al_range_start8, tvb, offset, 1, ENC_LITTLE_ENDIAN);
  1436. proto_tree_add_item(range_tree, hf_dnp3_al_range_stop8, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
  1437. rangebytes = 2;
  1438. break;
  1439. case AL_OBJQL_CODE_SSI16: /* 16-bit Start and Stop Indices in Range Field */
  1440. num_items = ( tvb_get_letohs(tvb, offset+2) - tvb_get_letohs(tvb, (offset)) + 1);
  1441. PROTO_ITEM_SET_GENERATED(range_item);
  1442. al_ptaddr = tvb_get_letohs(tvb, offset);
  1443. proto_tree_add_item(range_tree, hf_dnp3_al_range_start16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
  1444. proto_tree_add_item(range_tree, hf_dnp3_al_range_stop16, tvb, offset + 2, 2, ENC_LITTLE_ENDIAN);
  1445. rangebytes = 4;
  1446. break;
  1447. case AL_OBJQL_CODE_SSI32: /* 32-bit Start and Stop Indices in Range Field */
  1448. num_items = ( tvb_get_letohl(tvb, offset+4) - tvb_get_letohl(tvb, offset) + 1);
  1449. PROTO_ITEM_SET_GENERATED(range_item);
  1450. al_ptaddr = tvb_get_letohl(tvb, offset);
  1451. proto_tree_add_item(range_tree, hf_dnp3_al_range_start32, tvb, offset, 4, ENC_LITTLE_ENDIAN);
  1452. proto_tree_add_item(range_tree, hf_dnp3_al_range_stop32, tvb, offset + 4, 4, ENC_LITTLE_ENDIAN);
  1453. rangebytes = 8;
  1454. break;
  1455. case AL_OBJQL_CODE_AA8: /* 8-bit Absolute Address in Range Field */
  1456. num_items = 1;
  1457. PROTO_ITEM_SET_GENERATED(range_item);
  1458. al_ptaddr = tvb_get_guint8(tvb, offset);
  1459. proto_tree_add_item(range_tree, hf_dnp3_al_range_abs8, tvb, offset, 1, ENC_LITTLE_ENDIAN);
  1460. rangebytes = 1;
  1461. break;
  1462. case AL_OBJQL_CODE_AA16: /* 16-bit Absolute Address in Range Field */
  1463. num_items = 1;
  1464. PROTO_ITEM_SET_GENERATED(range_item);
  1465. al_ptaddr = tvb_get_letohs(tvb, offset);
  1466. proto_tree_add_item(range_tree, hf_dnp3_al_range_abs16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
  1467. rangebytes = 2;
  1468. break;
  1469. case AL_OBJQL_CODE_AA32: /* 32-bit Absolute Address in Range Field */
  1470. num_items = 1;
  1471. PROTO_ITEM_SET_GENERATED(range_item);
  1472. al_ptaddr = tvb_get_letohl(tvb, offset);
  1473. proto_tree_add_item(range_tree, hf_dnp3_al_range_abs32, tvb, offset, 4, ENC_LITTLE_ENDIAN);
  1474. rangebytes = 4;
  1475. break;
  1476. case AL_OBJQL_CODE_SF8: /* 8-bit Single Field Quantity in Range Field */
  1477. num_items = tvb_get_guint8(tvb, offset);
  1478. proto_tree_add_item(range_tree, hf_dnp3_al_range_quant8, tvb, offset, 1, ENC_LITTLE_ENDIAN);
  1479. rangebytes = 1;
  1480. proto_item_set_len(range_item, rangebytes);
  1481. break;
  1482. case AL_OBJQL_CODE_SF16: /* 16-bit Single Field Quantity in Range Field */
  1483. num_items = tvb_get_letohs(tvb, offset);
  1484. proto_tree_add_item(range_tree, hf_dnp3_al_range_quant16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
  1485. rangebytes = 2;
  1486. proto_item_set_len(range_item, rangebytes);
  1487. break;
  1488. case AL_OBJQL_CODE_SF32: /* 32-bit Single Field Quantity in Range Field */
  1489. num_items = tvb_get_letohl(tvb, offset);
  1490. proto_tree_add_item(range_tree, hf_dnp3_al_range_quant32, tvb, offset, 4, ENC_LITTLE_ENDIAN);
  1491. rangebytes = 4;
  1492. proto_item_set_len(range_item, rangebytes);
  1493. break;
  1494. case AL_OBJQL_CODE_FF: /* 8 bit object count in Range Field */
  1495. num_items = tvb_get_guint8(tvb, offset);
  1496. proto_tree_add_item(range_tree, hf_dnp3_al_range_quant8, tvb, offset, 1, ENC_LITTLE_ENDIAN);
  1497. rangebytes = 1;
  1498. proto_item_set_len(range_item, rangebytes);
  1499. }
  1500. if (num_items > 0) {
  1501. proto_item_append_text(object_item, ", %d point%s", num_items, plurality(num_items, "", "s"));
  1502. }
  1503. proto_item_append_text(range_item, "%d", num_items);
  1504. if (num_items < 0) {
  1505. proto_item_append_text(range_item, " (bogus)");
  1506. expert_add_info(pinfo, range_item, &ei_dnp_num_items_neg);
  1507. return tvb_length(tvb);
  1508. }
  1509. offset += rangebytes;
  1510. bitindex = 0; /* Temp variable for cycling through points when object values are encoded into
  1511. bits; primarily objects 0x0101, 0x0301 & 0x1001 */
  1512. /* Only process the point information for replies or items with point index lists */
  1513. if (!header_only || al_objq_index > 0) {
  1514. int item_num;
  1515. int start_offset;
  1516. start_offset = offset;
  1517. for (item_num = 0; item_num < num_items; item_num++)
  1518. {
  1519. proto_item *point_item;
  1520. proto_tree *point_tree;
  1521. guint data_pos;
  1522. int indexbytes;
  1523. /* Create Point item and Process Index */
  1524. if (al_objq_index <= AL_OBJQL_IDX_4O)
  1525. point_item = proto_tree_add_text(object_tree, tvb, offset, -1, "Point Number");
  1526. else
  1527. point_item = proto_tree_add_text(object_tree, tvb, offset, -1, "Object: Size");
  1528. point_tree = proto_item_add_subtree(point_item, ett_dnp3_al_obj_point);
  1529. data_pos = offset;
  1530. indexbytes = dnp3_al_obj_procindex(tvb, offset, al_objq_index, &al_ptaddr, point_tree);
  1531. proto_item_append_text(point_item, " %u", al_ptaddr);
  1532. proto_item_set_len(point_item, indexbytes);
  1533. data_pos += indexbytes;
  1534. if (!header_only || (AL_OBJQL_IDX_1OS <= al_objq_index && al_objq_index <= AL_OBJQL_IDX_4OS)) {
  1535. guint8 al_2bit, al_ptflags, al_ctlobj_count, al_bi_val, al_tcc_code;
  1536. guint16 al_val16, al_ctlobj_stat;
  1537. guint16 al_relms, al_filename_offs, al_filename_len, al_file_ctrl_mode;
  1538. guint32 al_val32, al_ctlobj_on, al_ctlobj_off, file_data_size;
  1539. nstime_t al_reltime, al_abstime;
  1540. gboolean al_bit;
  1541. gfloat al_valflt;
  1542. gdouble al_valdbl;
  1543. const gchar *ctl_status_str;
  1544. switch (al_obj)
  1545. {
  1546. case AL_OBJ_BI_ALL: /* Binary Input Default Variation (Obj:01, Var:Default) */
  1547. case AL_OBJ_BIC_ALL: /* Binary Input Change Default Variation (Obj:02, Var:Default) */
  1548. case AL_OBJ_BOC_ALL: /* Binary Output Event Default Variation (Obj:11, Var:Default) */
  1549. case AL_OBJ_2BI_ALL: /* Double-bit Input Default Variation (Obj:03, Var:Default) */
  1550. case AL_OBJ_CTR_ALL: /* Binary Counter Default Variation (Obj:20, Var:Default) */
  1551. case AL_OBJ_CTRC_ALL: /* Binary Counter Change Default Variation (Obj:22 Var:Default) */
  1552. case AL_OBJ_AI_ALL: /* Analog Input Default Variation (Obj:30, Var:Default) */
  1553. case AL_OBJ_AIC_ALL: /* Analog Input Change Default Variation (Obj:32 Var:Default) */
  1554. case AL_OBJ_AIDB_ALL: /* Analog Input Deadband Default Variation (Obj:34, Var:Default) */
  1555. case AL_OBJ_AOC_ALL: /* Analog Output Event Default Variation (Obj:42 Var:Default) */
  1556. offset = data_pos;
  1557. break;
  1558. case AL_OBJ_BI_1BIT: /* Single-Bit Binary Input (Obj:01, Var:01) */
  1559. case AL_OBJ_BO: /* Binary Output (Obj:10, Var:01) */
  1560. /* Reset bit index if we've gone onto the next byte */
  1561. if (bitindex > 7)
  1562. {
  1563. bitindex = 0;
  1564. offset += (indexbytes + 1);
  1565. }
  1566. /* Extract the bit from the packed byte */
  1567. al_bi_val = tvb_get_guint8(tvb, offset);
  1568. al_bit = (al_bi_val & (1 << bitindex)) > 0;
  1569. proto_item_append_text(point_item, ", Value: %u", al_bit);
  1570. proto_tree_add_boolean(point_tree, hf_dnp3_al_bit, tvb, offset, 1, al_bit);
  1571. proto_item_set_len(point_item, indexbytes + 1);
  1572. /* If we've read the last item, then move the offset past this byte */
  1573. if (item_num == (num_items-1))
  1574. {
  1575. offset += (indexbytes + 1);
  1576. }
  1577. break;
  1578. case AL_OBJ_2BI_NF: /* Double-bit Input No Flags (Obj:03, Var:01) */
  1579. if (bitindex > 3)
  1580. {
  1581. bitindex = 0;
  1582. offset += (indexbytes + 1);
  1583. }
  1584. /* Extract the Double-bit from the packed byte */
  1585. al_bi_val = tvb_get_guint8(tvb, offset);
  1586. al_2bit = ((al_bi_val >> (bitindex << 1)) & 3);
  1587. proto_item_append_text(point_item, ", Value: %u", al_2bit);
  1588. proto_tree_add_uint(point_tree, hf_dnp3_al_2bit, tvb, offset, 1, al_2bit);
  1589. proto_item_set_len(point_item, indexbytes + 1);
  1590. /* If we've read the last item, then move the offset past this byte */
  1591. if (item_num == (num_items-1))
  1592. {
  1593. offset += (indexbytes + 1);
  1594. }
  1595. break;
  1596. case AL_OBJ_BI_STAT: /* Binary Input With Status (Obj:01, Var:02) */
  1597. case AL_OBJ_BIC_NOTIME: /* Binary Input Change Without Time (Obj:02, Var:01) */
  1598. case AL_OBJ_BO_STAT: /* Binary Output Status (Obj:10, Var:02) */
  1599. case AL_OBJ_BOC_NOTIME: /* Binary Output Change Without Time (Obj:11, Var:01) */
  1600. /* Get Point Flags */
  1601. al_ptflags = tvb_get_guint8(tvb, data_pos);
  1602. switch (al_obj) {
  1603. case AL_OBJ_BI_STAT:
  1604. case AL_OBJ_BIC_NOTIME:
  1605. dnp3_al_obj_quality(tvb, data_pos, al_ptflags, point_tree, point_item, BIN_IN);
  1606. break;
  1607. case AL_OBJ_BO_STAT:
  1608. case AL_OBJ_BOC_NOTIME:
  1609. dnp3_al_obj_quality(tvb, data_pos, al_ptflags, point_tree, point_item, BIN_OUT);
  1610. break;
  1611. }
  1612. data_pos += 1;
  1613. al_bit = (al_ptflags & AL_OBJ_BI_FLAG7) > 0;
  1614. proto_item_append_text(point_item, ", Value: %u", al_bit);
  1615. proto_item_set_len(point_item, data_pos - offset);
  1616. offset = data_pos;
  1617. break;
  1618. case AL_OBJ_2BI_STAT: /* Double-bit Input With Status (Obj:03, Var:02) */
  1619. case AL_OBJ_2BIC_NOTIME: /* Double-bit Input Change Without Time (Obj:04, Var:01) */
  1620. /* Get Point Flags */
  1621. al_ptflags = tvb_get_guint8(tvb, data_pos);
  1622. dnp3_al_obj_quality(tvb, data_pos, al_ptflags, point_tree, point_item, BIN_IN);
  1623. data_pos += 1;
  1624. al_2bit = (al_ptflags >> 6) & 3;
  1625. proto_item_append_text(point_item, ", Value: %u", al_2bit);
  1626. proto_item_set_len(point_item, data_pos - offset);
  1627. offset = data_pos;
  1628. break;
  1629. case AL_OBJ_BIC_TIME: /* Binary Input Change w/ Time (Obj:02, Var:02) */
  1630. case AL_OBJ_BOC_TIME: /* Binary Output Change w/ Time (Obj:11, Var:02) */
  1631. /* Get Point Flags */
  1632. al_ptflags = tvb_get_guint8(tvb, data_pos);
  1633. switch (al_obj) {
  1634. case AL_OBJ_BIC_TIME:
  1635. dnp3_al_obj_quality(tvb, data_pos, al_ptflags, point_tree, point_item, BIN_IN);
  1636. break;
  1637. case AL_OBJ_BOC_TIME:
  1638. dnp3_al_obj_quality(tvb, data_pos, al_ptflags, point_tree, point_item, BIN_OUT);
  1639. break;
  1640. }
  1641. data_pos += 1;
  1642. /* Get timestamp */
  1643. dnp3_al_get_timestamp(&al_abstime, tvb, data_pos);
  1644. proto_tree_add_time(point_tree, hf_dnp3_al_timestamp, tvb, data_pos, 6, &al_abstime);
  1645. data_pos += 6;
  1646. al_bit = (al_ptflags & AL_OBJ_BI_FLAG7) >> 7; /* bit shift 1xxxxxxx -> xxxxxxx1 */
  1647. proto_item_append_text(point_item, ", Value: %u, Timestamp: %s",
  1648. al_bit, abs_time_to_str(&al_abstime, ABSOLUTE_TIME_UTC, FALSE));
  1649. proto_item_set_len(point_item, data_pos - offset);
  1650. offset = data_pos;
  1651. break;
  1652. case AL_OBJ_2BIC_TIME: /* Double-bit Input Change w/ Time (Obj:04, Var:02) */
  1653. /* Get Point Flags */
  1654. al_ptflags = tvb_get_guint8(tvb, data_pos);
  1655. dnp3_al_obj_quality(tvb, (offset+indexbytes), al_ptflags, point_tree, point_item, BIN_IN);
  1656. data_pos += 1;
  1657. /* Get timestamp */
  1658. dnp3_al_get_timestamp(&al_abstime, tvb, data_pos);
  1659. proto_tree_add_time(point_tree, hf_dnp3_al_timestamp, tvb, data_pos, 6, &al_abstime);
  1660. data_pos += 6;
  1661. al_2bit = (al_ptflags >> 6) & 3; /* bit shift 11xxxxxx -> 00000011 */
  1662. proto_item_append_text(point_item, ", Value: %u, Timestamp: %s",
  1663. al_2bit, abs_time_to_str(&al_abstime, ABSOLUTE_TIME_UTC, FALSE));
  1664. proto_item_set_len(point_item, data_pos - offset);
  1665. offset = data_pos;
  1666. break;
  1667. case AL_OBJ_BIC_RTIME: /* Binary Input Change w/ Relative Time (Obj:02, Var:03) */
  1668. /* Get Point Flags */
  1669. al_ptflags = tvb_get_guint8(tvb, data_pos);
  1670. dnp3_al_obj_quality(tvb, data_pos, al_ptflags, point_tree, point_item, BIN_IN);
  1671. data_pos += 1;
  1672. /* Get relative time, and convert to ns_time */
  1673. al_relms = tvb_get_letohs(tvb, data_pos);
  1674. al_reltime.secs = al_relms / 1000;
  1675. al_reltime.nsecs = (al_relms % 1000) * 1000;
  1676. /* Now add to CTO time */
  1677. nstime_sum(&al_abstime, al_cto, &al_reltime);
  1678. proto_tree_add_time(point_tree, hf_dnp3_al_rel_timestamp, tvb, data_pos, 2, &al_reltime);
  1679. data_pos += 2;
  1680. al_bit = (al_ptflags & AL_OBJ_BI_FLAG7) >> 7; /* bit shift 1xxxxxxx -> xxxxxxx1 */
  1681. proto_item_append_text(point_item, ", Value: %u, Timestamp: %s",
  1682. al_bit, abs_time_to_str(&al_abstime, ABSOLUTE_TIME_UTC, FALSE));
  1683. proto_item_set_len(point_item, data_pos - offset);
  1684. offset = data_pos;
  1685. break;
  1686. case AL_OBJ_CTLOP_BLK:/* Control Relay Output Block (Obj:12, Var:01) */
  1687. {
  1688. proto_item *tcc_item;
  1689. proto_tree *tcc_tree;
  1690. /* Add a expand/collapse for TCC */
  1691. al_tcc_code = tvb_get_guint8(tvb, data_pos);
  1692. tcc_item = proto_tree_add_text(point_tree, tvb, data_pos, 1, "Control Code [0x%02x]",al_tcc_code);
  1693. tcc_tree = proto_item_add_subtree(tcc_item, ett_dnp3_al_obj_point_tcc);
  1694. /* Add the Control Code to the Point number list for quick visual reference as to the operation */
  1695. proto_item_append_text(point_item, " [%s]", val_to_str_const((al_tcc_code & AL_OBJCTLC_CODE),
  1696. dnp3_al_ctlc_code_vals,
  1697. "Invalid Operation"));
  1698. /* Add Trip/Close qualifier (if applicable) to previously appended quick visual reference */
  1699. proto_item_append_text(point_item, " [%s]", val_to_str_const((al_tcc_code & AL_OBJCTLC_TC) >> 6,
  1700. dnp3_al_ctlc_tc_vals,
  1701. "Invalid Qualifier"));
  1702. /* Control Code 'Operation Type' */
  1703. proto_tree_add_item(tcc_tree, hf_dnp3_ctlobj_code_c, tvb, data_pos, 1, ENC_LITTLE_ENDIAN);
  1704. /* Control Code Misc Values */
  1705. proto_tree_add_item(tcc_tree, hf_dnp3_ctlobj_code_m, tvb, data_pos, 1, ENC_LITTLE_ENDIAN);
  1706. /* Control Code 'Trip Close Code' */
  1707. proto_tree_add_item(tcc_tree, hf_dnp3_ctlobj_code_tc, tvb, data_pos, 1, ENC_LITTLE_ENDIAN);
  1708. data_pos += 1;
  1709. /* Get "Count" Field */
  1710. al_ctlobj_count = tvb_get_guint8(tvb, data_pos);
  1711. data_pos += 1;
  1712. /* Get "On Time" Field */
  1713. al_ctlobj_on = tvb_get_letohl(tvb, data_pos);
  1714. data_pos += 4;
  1715. /* Get "Off Time" Field */
  1716. al_ctlobj_off = tvb_get_letohl(tvb, data_pos);
  1717. data_pos += 4;
  1718. /* Print "Count", "On Time" and "Off Time" to tree */
  1719. proto_tree_add_text(point_tree, tvb, data_pos - 9, 9,
  1720. "[Count: %u] [On-Time: %u] [Off-Time: %u]",
  1721. al_ctlobj_count, al_ctlobj_on, al_ctlobj_off);
  1722. /* Get "Control Status" Field */
  1723. proto_tree_add_item(point_tree, hf_dnp3_al_ctrlstatus, tvb, data_pos, 1, ENC_LITTLE_ENDIAN);
  1724. data_pos += 1;
  1725. proto_item_set_len(point_item, data_pos - offset);
  1726. offset = data_pos;
  1727. break;
  1728. }
  1729. case AL_OBJ_AO_32OPB: /* 32-Bit Analog Output Block (Obj:41, Var:01) */
  1730. case AL_OBJ_AO_16OPB: /* 16-Bit Analog Output Block (Obj:41, Var:02) */
  1731. case AL_OBJ_AO_FLTOPB: /* 32-Bit Floating Point Output Block (Obj:41, Var:03) */
  1732. case AL_OBJ_AO_DBLOPB: /* 64-Bit Floating Point Output Block (Obj:41, Var:04) */
  1733. switch (al_obj)
  1734. {
  1735. case AL_OBJ_AO_32OPB:
  1736. al_val32 = tvb_get_letohl(tvb, data_pos);
  1737. proto_item_append_text(point_item, ", Value: %u", al_val32);
  1738. proto_tree_add_item(point_tree, hf_dnp3_al_anaout32, tvb, data_pos, 4, ENC_LITTLE_ENDIAN);
  1739. data_pos += 4;
  1740. break;
  1741. case AL_OBJ_AO_16OPB:
  1742. al_val32 = tvb_get_letohs(tvb, data_pos);
  1743. proto_item_append_text(point_item, ", Value: %u", al_val32);
  1744. proto_tree_add_item(point_tree, hf_dnp3_al_anaout16, tvb, data_pos, 2, ENC_LITTLE_ENDIAN);
  1745. data_pos += 2;
  1746. break;
  1747. case AL_OBJ_AO_FLTOPB:
  1748. al_valflt = tvb_get_letohieee_float(tvb, data_pos);
  1749. proto_item_append_text(point_item, ", Value: %g", al_valflt);
  1750. proto_tree_add_item(point_tree, hf_dnp3_al_anaoutflt, tvb, data_pos, 4, ENC_LITTLE_ENDIAN);
  1751. data_pos += 4;
  1752. break;
  1753. case AL_OBJ_AO_DBLOPB:
  1754. al_valdbl = tvb_get_letohieee_double(tvb, data_pos);
  1755. proto_item_append_text(point_item, ", Value: %g", al_valdbl);
  1756. proto_tree_add_item(point_tree, hf_dnp3_al_anaoutdbl, tvb, data_pos, 8, ENC_LITTLE_ENDIAN);
  1757. data_pos += 8;
  1758. break;
  1759. }
  1760. /* Get control status */
  1761. al_ctlobj_stat = tvb_get_guint8(tvb, data_pos);
  1762. ctl_status_str = val_to_str_ext(al_ctlobj_stat, &dnp3_al_ctl_status_vals_ext, "Invalid Status (0x%02x)");
  1763. proto_item_append_text(point_item, " [Status: %s (0x%02x)]", ctl_status_str, al_ctlobj_stat);
  1764. proto_tree_add_item(point_tree, hf_dnp3_al_ctrlstatus, tvb, data_pos, 1, ENC_LITTLE_ENDIAN);
  1765. data_pos += 1;
  1766. proto_item_set_len(point_item, data_pos - offset);
  1767. offset = data_pos;
  1768. break;
  1769. case AL_OBJ_CTR_32: /* 32-Bit Binary Counter (Obj:20, Var:01) */
  1770. case AL_OBJ_CTR_16: /* 16-Bit Binary Counter (Obj:20, Var:02) */
  1771. case AL_OBJ_DCTR_32: /* 32-Bit Binary Delta Counter (Obj:20, Var:03) */
  1772. case AL_OBJ_DCTR_16: /* 16-Bit Binary Delta Counter (Obj:20, Var:04) */
  1773. case AL_OBJ_CTR_32NF: /* 32-Bit Binary Counter Without Flag (Obj:20, Var:05) */
  1774. case AL_OBJ_CTR_16NF: /* 16-Bit Binary Counter Without Flag (Obj:20, Var:06) */
  1775. case AL_OBJ_DCTR_32NF: /* 32-Bit Binary Delta Counter Without Flag (Obj:20, Var:07) */
  1776. case AL_OBJ_DCTR_16NF: /* 16-Bit Binary Delta Counter Without Flag (Obj:20, Var:08) */
  1777. case AL_OBJ_FCTR_32: /* 32-Bit Frozen Counter (Obj:21, Var:01) */
  1778. case AL_OBJ_FCTR_16: /* 16-Bit Frozen Counter (Obj:21, Var:02) */
  1779. case AL_OBJ_FDCTR_32: /* 21 03 32-Bit Frozen Delta Counter */
  1780. case AL_OBJ_FDCTR_16: /* 21 04 16-Bit Frozen Delta Counter */
  1781. case AL_OBJ_FCTR_32T: /* 21 05 32-Bit Frozen Counter w/ Time of Freeze */
  1782. case AL_OBJ_FCTR_16T: /* 21 06 16-Bit Frozen Counter w/ Time of Freeze */
  1783. case AL_OBJ_FDCTR_32T: /* 21 07 32-Bit Frozen Delta Counter w/ Time of Freeze */
  1784. case AL_OBJ_FDCTR_16T: /* 21 08 16-Bit Frozen Delta Counter w/ Time of Freeze */
  1785. case AL_OBJ_FCTR_32NF: /* 21 09 32-Bit Frozen Counter Without Flag */
  1786. case AL_OBJ_FCTR_16NF: /* 21 10 16-Bit Frozen Counter Without Flag */
  1787. case AL_OBJ_FDCTR_32NF: /* 21 11 32-Bit Frozen Delta Counter Without Flag */
  1788. case AL_OBJ_FDCTR_16NF: /* 21 12 16-Bit Frozen Delta Counter Without Flag */
  1789. case AL_OBJ_CTRC_32: /* 32-Bit Counter Change Event w/o Time (Obj:22, Var:01) */
  1790. case AL_OBJ_CTRC_16: /* 16-Bit Counter Change Event w/o Time (Obj:22, Var:02) */
  1791. case AL_OBJ_DCTRC_32: /* 32-Bit Delta Counter Change Event w/o Time (Obj:22, Var:03) */
  1792. case AL_OBJ_DCTRC_16: /* 16-Bit Delta Counter Change Event w/o Time (Obj:22, Var:04) */
  1793. case AL_OBJ_CTRC_32T: /* 32-Bit Counter Change Event with Time (Obj:22, Var:05) */
  1794. case AL_OBJ_CTRC_16T: /* 16-Bit Counter Change Event with Time (Obj:22, Var:06) */
  1795. case AL_OBJ_DCTRC_32T: /* 32-Bit Delta Counter Change Event with Time (Obj:22, Var:07) */
  1796. case AL_OBJ_DCTRC_16T: /* 16-Bit Delta Counter Change Event with Time (Obj:22, Var:08) */
  1797. case AL_OBJ_FCTRC_32: /* 21 01 32-Bit Frozen Counter Change Event */
  1798. case AL_OBJ_FCTRC_16: /* 21 02 16-Bit Frozen Counter Change Event */
  1799. case AL_OBJ_FDCTRC_32: /* 21 03 32-Bit Frozen Delta Counter Change Event */
  1800. case AL_OBJ_FDCTRC_16: /* 21 04 16-Bit Frozen Delta Counter Change Event */
  1801. case AL_OBJ_FCTRC_32T: /* 21 05 32-Bit Frozen Counter Change Event w/ Time of Freeze */
  1802. case AL_OBJ_FCTRC_16T: /* 21 06 16-Bit Frozen Counter Change Event w/ Time of Freeze */
  1803. case AL_OBJ_FDCTRC_32T: /* 21 07 32-Bit Frozen Delta Counter Change Event w/ Time of Freeze */
  1804. case AL_OBJ_FDCTRC_16T: /* 21 08 16-Bit Frozen Delta Counter Change Event w/ Time of Freeze */
  1805. /* Get Point Flags for those types that have them, it's easier to block out those that don't have flags */
  1806. switch (al_obj)
  1807. {
  1808. case AL_OBJ_CTR_32NF:
  1809. case AL_OBJ_CTR_16NF:
  1810. case AL_OBJ_DCTR_32NF:
  1811. case AL_OBJ_DCTR_16NF:
  1812. case AL_OBJ_FCTR_32NF:
  1813. case AL_OBJ_FCTR_16NF:
  1814. case AL_OBJ_FDCTR_32NF:
  1815. case AL_OBJ_FDCTR_16NF:
  1816. break;
  1817. default:
  1818. al_ptflags = tvb_get_guint8(tvb, data_pos);
  1819. dnp3_al_obj_quality(tvb, data_pos, al_ptflags, point_tree, point_item, COUNTER);
  1820. data_pos += 1;
  1821. break;
  1822. }
  1823. /* Get Counter values */
  1824. switch (al_obj)
  1825. {
  1826. case AL_OBJ_CTR_32:
  1827. case AL_OBJ_DCTR_32:
  1828. case AL_OBJ_CTR_32NF:
  1829. case AL_OBJ_DCTR_32NF:
  1830. case AL_OBJ_FCTR_32:
  1831. case AL_OBJ_FDCTR_32:
  1832. case AL_OBJ_FCTR_32T:
  1833. case AL_OBJ_FDCTR_32T:
  1834. case AL_OBJ_FCTR_32NF:
  1835. case AL_OBJ_FDCTR_32NF:
  1836. case AL_OBJ_CTRC_32:
  1837. case AL_OBJ_DCTRC_32:
  1838. case AL_OBJ_CTRC_32T:
  1839. case AL_OBJ_DCTRC_32T:
  1840. case AL_OBJ_FCTRC_32:
  1841. case AL_OBJ_FDCTRC_32:
  1842. case AL_OBJ_FCTRC_32T:
  1843. case AL_OBJ_FDCTRC_32T:
  1844. al_val32 = tvb_get_letohl(tvb, data_pos);
  1845. proto_item_append_text(point_item, ", Count: %u", al_val32);
  1846. proto_tree_add_item(point_tree, hf_dnp3_al_cnt32, tvb, data_pos, 4, ENC_LITTLE_ENDIAN);
  1847. data_pos += 4;
  1848. break;
  1849. case AL_OBJ_CTR_16:
  1850. case AL_OBJ_DCTR_16:
  1851. case AL_OBJ_CTR_16NF:
  1852. case AL_OBJ_DCTR_16NF:
  1853. case AL_OBJ_FCTR_16:
  1854. case AL_OBJ_FDCTR_16:
  1855. case AL_OBJ_FCTR_16T:
  1856. case AL_OBJ_FDCTR_16T:
  1857. case AL_OBJ_FCTR_16NF:
  1858. case AL_OBJ_FDCTR_16NF:
  1859. case AL_OBJ_CTRC_16:
  1860. case AL_OBJ_DCTRC_16:
  1861. case AL_OBJ_CTRC_16T:
  1862. case AL_OBJ_DCTRC_16T:
  1863. case AL_OBJ_FCTRC_16:
  1864. case AL_OBJ_FDCTRC_16:
  1865. case AL_OBJ_FCTRC_16T:
  1866. case AL_OBJ_FDCTRC_16T:
  1867. al_val16 = tvb_get_letohs(tvb, data_pos);
  1868. proto_item_append_text(point_item, ", Count: %u", al_val16);
  1869. proto_tree_add_item(point_tree, hf_dnp3_al_cnt16, tvb, data_pos, 2, ENC_LITTLE_ENDIAN);
  1870. data_pos += 2;
  1871. break;
  1872. }
  1873. /* Get the time for those points that have it */
  1874. switch (al_obj)
  1875. {
  1876. case AL_OBJ_FCTR_32T:
  1877. case AL_OBJ_FCTR_16T:
  1878. case AL_OBJ_FDCTR_32T:
  1879. case AL_OBJ_FDCTR_16T:
  1880. case AL_OBJ_CTRC_32T:
  1881. case AL_OBJ_CTRC_16T:
  1882. case AL_OBJ_DCTRC_32T:
  1883. case AL_OBJ_DCTRC_16T:
  1884. case AL_OBJ_FCTRC_32T:
  1885. case AL_OBJ_FCTRC_16T:
  1886. case AL_OBJ_FDCTRC_32T:
  1887. case AL_OBJ_FDCTRC_16T:
  1888. dnp3_al_get_timestamp(&al_abstime, tvb, data_pos);
  1889. proto_item_append_text(point_item, ", Timestamp: %s", abs_time_to_str(&al_abstime, ABSOLUTE_TIME_UTC, FALSE));
  1890. proto_tree_add_time(point_tree, hf_dnp3_al_timestamp, tvb, data_pos, 6, &al_abstime);
  1891. data_pos += 6;
  1892. break;
  1893. }
  1894. proto_item_set_len(point_item, data_pos - offset);
  1895. offset = data_pos;
  1896. break;
  1897. case AL_OBJ_AI_32: /* 32-Bit Analog Input (Obj:30, Var:01) */
  1898. case AL_OBJ_AI_16: /* 16-Bit Analog Input (Obj:30, Var:02) */
  1899. case AL_OBJ_AI_32NF: /* 32-Bit Analog Input Without Flag (Obj:30, Var:03) */
  1900. case AL_OBJ_AI_16NF: /* 16-Bit Analog Input Without Flag (Obj:30, Var:04) */
  1901. case AL_OBJ_AI_FLT: /* 32-Bit Floating Point Input (Obj:30, Var:05) */
  1902. case AL_OBJ_AI_DBL: /* 64-Bit Floating Point Input (Obj:30, Var:06) */
  1903. case AL_OBJ_AIF_FLT: /* 32-Bit Frozen Floating Point Input (Obj:31, Var:07) */
  1904. case AL_OBJ_AIF_DBL: /* 64-Bit Frozen Floating Point Input (Obj:31, Var:08) */
  1905. case AL_OBJ_AIC_32NT: /* 32-Bit Analog Change Event w/o Time (Obj:32, Var:01) */
  1906. case AL_OBJ_AIC_16NT: /* 16-Bit Analog Change Event w/o Time (Obj:32, Var:02) */
  1907. case AL_OBJ_AIC_32T: /* 32-Bit Analog Change Event with Time (Obj:32, Var:03) */
  1908. case AL_OBJ_AIC_16T: /* 16-Bit Analog Change Event with Time (Obj:32, Var:04) */
  1909. case AL_OBJ_AIC_FLTNT: /* 32-Bit Floating Point Change Event w/o Time (Obj:32, Var:05) */
  1910. case AL_OBJ_AIC_DBLNT: /* 64-Bit Floating Point Change Event w/o Time (Obj:32, Var:06) */
  1911. case AL_OBJ_AIC_FLTT: /* 32-Bit Floating Point Change Event w/ Time (Obj:32, Var:07) */
  1912. case AL_OBJ_AIC_DBLT: /* 64-Bit Floating Point Change Event w/ Time (Obj:32, Var:08) */
  1913. case AL_OBJ_AIFC_FLTNT: /* 32-Bit Floating Point Frozen Change Event w/o Time (Obj:33, Var:05) */
  1914. case AL_OBJ_AIFC_DBLNT: /* 64-Bit Floating Point Frozen Change Event w/o Time (Obj:33, Var:06) */
  1915. case AL_OBJ_AIFC_FLTT: /* 32-Bit Floating Point Frozen Change Event w/ Time (Obj:33, Var:07) */
  1916. case AL_OBJ_AIFC_DBLT: /* 64-Bit Floating Point Frozen Change Event w/ Time (Obj:33, Var:08) */
  1917. case AL_OBJ_AIDB_16: /* 16-Bit Analog Input Deadband (Obj:34, Var:01) */
  1918. case AL_OBJ_AIDB_32: /* 32-Bit Analog Input Deadband (Obj:34, Var:02) */
  1919. case AL_OBJ_AIDB_FLT: /* 32-Bit Floating Point Analog Input Deadband (Obj:34, Var:03) */
  1920. /* Get Point Flags for those types that have them */
  1921. switch (al_obj)
  1922. {
  1923. case AL_OBJ_AI_32NF:
  1924. case AL_OBJ_AI_16NF:
  1925. case AL_OBJ_AIDB_16:
  1926. case AL_OBJ_AIDB_32:
  1927. case AL_OBJ_AIDB_FLT:
  1928. break;
  1929. default:
  1930. al_ptflags = tvb_get_guint8(tvb, data_pos);
  1931. dnp3_al_obj_quality(tvb, data_pos, al_ptflags, point_tree, point_item, ANA_IN);
  1932. data_pos += 1;
  1933. break;
  1934. }
  1935. switch (al_obj)
  1936. {
  1937. case AL_OBJ_AI_32:
  1938. case AL_OBJ_AI_32NF:
  1939. case AL_OBJ_AIC_32NT:
  1940. case AL_OBJ_AIC_32T:
  1941. case AL_OBJ_AIDB_32:
  1942. al_val32 = tvb_get_letohl(tvb, data_pos);
  1943. proto_item_append_text(point_item, ", Value: %u", al_val32);
  1944. proto_tree_add_item(point_tree, hf_dnp3_al_ana32, tvb, data_pos, 4, ENC_LITTLE_ENDIAN);
  1945. data_pos += 4;
  1946. break;
  1947. case AL_OBJ_AI_16:
  1948. case AL_OBJ_AI_16NF:
  1949. case AL_OBJ_AIC_16NT:
  1950. case AL_OBJ_AIC_16T:
  1951. case AL_OBJ_AIDB_16:
  1952. al_val16 = tvb_get_letohs(tvb, data_pos);
  1953. proto_item_append_text(point_item, ", Value: %u", al_val16);
  1954. proto_tree_add_item(point_tree, hf_dnp3_al_ana16, tvb, data_pos, 2, ENC_LITTLE_ENDIAN);
  1955. data_pos += 2;
  1956. break;
  1957. case AL_OBJ_AI_FLT:
  1958. case AL_OBJ_AIF_FLT:
  1959. case AL_OBJ_AIC_FLTNT:
  1960. case AL_OBJ_AIC_FLTT:
  1961. case AL_OBJ_AIFC_FLTNT:
  1962. case AL_OBJ_AIFC_FLTT:
  1963. case AL_OBJ_AIDB_FLT:
  1964. al_valflt = tvb_get_letohieee_float(tvb, data_pos);
  1965. proto_item_append_text(point_item, ", Value: %g", al_valflt);
  1966. proto_tree_add_item(point_tree, hf_dnp3_al_anaflt, tvb, data_pos, 4, ENC_LITTLE_ENDIAN);
  1967. data_pos += 4;
  1968. break;
  1969. case AL_OBJ_AI_DBL:
  1970. case AL_OBJ_AIF_DBL:
  1971. case AL_OBJ_AIC_DBLNT:
  1972. case AL_OBJ_AIC_DBLT:
  1973. case AL_OBJ_AIFC_DBLNT:
  1974. case AL_OBJ_AIFC_DBLT:
  1975. al_valdbl = tvb_get_letohieee_double(tvb, data_pos);
  1976. proto_item_append_text(point_item, ", Value: %g", al_valdbl);
  1977. proto_tree_add_item(point_tree, hf_dnp3_al_anadbl, tvb, data_pos, 8, ENC_LITTLE_ENDIAN);
  1978. data_pos += 8;
  1979. break;
  1980. }
  1981. /* Get timestamp */
  1982. switch (al_obj)
  1983. {
  1984. case AL_OBJ_AIC_32T:
  1985. case AL_OBJ_AIC_16T:
  1986. case AL_OBJ_AIC_FLTT:
  1987. case AL_OBJ_AIC_DBLT:
  1988. case AL_OBJ_AIFC_FLTT:
  1989. case AL_OBJ_AIFC_DBLT:
  1990. dnp3_al_get_timestamp(&al_abstime, tvb, data_pos);
  1991. proto_item_append_text(point_item, ", Timestamp: %s", abs_time_to_str(&al_abstime, ABSOLUTE_TIME_UTC, FALSE));
  1992. proto_tree_add_time(point_tree, hf_dnp3_al_timestamp, tvb, data_pos, 6, &al_abstime);
  1993. data_pos += 6;
  1994. break;
  1995. }
  1996. proto_item_set_len(point_item, data_pos - offset);
  1997. offset = data_pos;
  1998. break;
  1999. case AL_OBJ_AO_32: /* 32-Bit Analog Output Status (Obj:40, Var:01) */
  2000. case AL_OBJ_AO_16: /* 16-Bit Analog Output Status (Obj:40, Var:02) */
  2001. case AL_OBJ_AO_FLT: /* 32-Bit Floating Point Output Status (Obj:40, Var:03) */
  2002. case AL_OBJ_AO_DBL: /* 64-Bit Floating Point Output Status (Obj:40, Var:04) */
  2003. case AL_OBJ_AOC_32NT: /* 32-Bit Analog Output Event w/o Time (Obj:42, Var:01) */
  2004. case AL_OBJ_AOC_16NT: /* 16-Bit Analog Output Event w/o Time (Obj:42, Var:02) */
  2005. case AL_OBJ_AOC_32T: /* 32-Bit Analog Output Event with Time (Obj:42, Var:03) */
  2006. case AL_OBJ_AOC_16T: /* 16-Bit Analog Output Event with Time (Obj:42, Var:04) */
  2007. case AL_OBJ_AOC_FLTNT: /* 32-Bit Floating Point Output Event w/o Time (Obj:42, Var:05) */
  2008. case AL_OBJ_AOC_DBLNT: /* 64-Bit Floating Point Output Event w/o Time (Obj:42, Var:06) */
  2009. case AL_OBJ_AOC_FLTT: /* 32-Bit Floating Point Output Event w/ Time (Obj:42, Var:07) */
  2010. case AL_OBJ_AOC_DBLT: /* 64-Bit Floating Point Output Event w/ Time (Obj:42, Var:08) */
  2011. /* Get Point Flags */
  2012. al_ptflags = tvb_get_guint8(tvb, data_pos);
  2013. dnp3_al_obj_quality(tvb, data_pos, al_ptflags, point_tree, point_item, ANA_OUT);
  2014. data_pos += 1;
  2015. switch (al_obj)
  2016. {
  2017. case AL_OBJ_AO_32: /* 32-Bit Analog Output Status (Obj:40, Var:01) */
  2018. case AL_OBJ_AOC_32NT: /* 32-Bit Analog Output Event w/o Time (Obj:42, Var:01) */
  2019. case AL_OBJ_AOC_32T: /* 32-Bit Analog Output Event with Time (Obj:42, Var:03) */
  2020. al_val32 = tvb_get_letohl(tvb, data_pos);
  2021. proto_item_append_text(point_item, ", Value: %u", al_val32);
  2022. proto_tree_add_item(point_tree, hf_dnp3_al_anaout32, tvb, data_pos, 4, ENC_LITTLE_ENDIAN);
  2023. data_pos += 4;
  2024. break;
  2025. case AL_OBJ_AO_16: /* 16-Bit Analog Output Status (Obj:40, Var:02) */
  2026. case AL_OBJ_AOC_16NT: /* 16-Bit Analog Output Event w/o Time (Obj:42, Var:02) */
  2027. case AL_OBJ_AOC_16T: /* 16-Bit Analog Output Event with Time (Obj:42, Var:04) */
  2028. al_val16 = tvb_get_letohs(tvb, data_pos);
  2029. proto_item_append_text(point_item, ", Value: %u", al_val16);
  2030. proto_tree_add_item(point_tree, hf_dnp3_al_anaout16, tvb, data_pos, 2, ENC_LITTLE_ENDIAN);
  2031. data_pos += 2;
  2032. break;
  2033. case AL_OBJ_AO_FLT: /* 32-Bit Floating Point Output Status (Obj:40, Var:03) */
  2034. case AL_OBJ_AOC_FLTNT: /* 32-Bit Floating Point Output Event w/o Time (Obj:42, Var:05) */
  2035. case AL_OBJ_AOC_FLTT: /* 32-Bit Floating Point Output Event w/ Time (Obj:42, Var:07) */
  2036. al_valflt = tvb_get_letohieee_float(tvb, data_pos);
  2037. proto_item_append_text(point_item, ", Value: %g", al_valflt);
  2038. proto_tree_add_item(point_tree, hf_dnp3_al_anaoutflt, tvb, data_pos, 4, ENC_LITTLE_ENDIAN);
  2039. data_pos += 4;
  2040. break;
  2041. case AL_OBJ_AO_DBL: /* 64-Bit Floating Point Output Status (Obj:40, Var:04) */
  2042. case AL_OBJ_AOC_DBLNT: /* 64-Bit Floating Point Output Event w/o Time (Obj:42, Var:06) */
  2043. case AL_OBJ_AOC_DBLT: /* 64-Bit Floating Point Output Event w/ Time (Obj:42, Var:08) */
  2044. al_valdbl = tvb_get_letohieee_double(tvb, data_pos);
  2045. proto_item_append_text(point_item, ", Value: %g", al_valdbl);
  2046. proto_tree_add_item(point_tree, hf_dnp3_al_anaoutdbl, tvb, data_pos, 8, ENC_LITTLE_ENDIAN);
  2047. data_pos += 8;
  2048. break;
  2049. }
  2050. /* Get timestamp */
  2051. switch (al_obj)
  2052. {
  2053. case AL_OBJ_AOC_32T:
  2054. case AL_OBJ_AOC_16T:
  2055. case AL_OBJ_AOC_FLTT:
  2056. case AL_OBJ_AOC_DBLT:
  2057. dnp3_al_get_timestamp(&al_abstime, tvb, data_pos);
  2058. proto_item_append_text(point_item, ", Timestamp: %s", abs_time_to_str(&al_abstime, ABSOLUTE_TIME_UTC, FALSE));
  2059. proto_tree_add_time(point_tree, hf_dnp3_al_timestamp, tvb, data_pos, 6, &al_abstime);
  2060. data_pos += 6;
  2061. break;
  2062. }
  2063. proto_item_set_len(point_item, data_pos - offset);
  2064. offset = data_pos;
  2065. break;
  2066. case AL_OBJ_TD: /* Time and Date (Obj:50, Var:01) */
  2067. case AL_OBJ_TDR: /* Time and Date at Last Recorded Time (Obj:50, Var:03) */
  2068. case AL_OBJ_TDCTO: /* Time and Date CTO (Obj:51, Var:01) */
  2069. dnp3_al_get_timestamp(&al_abstime, tvb, data_pos);
  2070. proto_tree_add_time(object_tree, hf_dnp3_al_timestamp, tvb, data_pos, 6, &al_abstime);
  2071. data_pos += 6;
  2072. proto_item_set_len(point_item, data_pos - offset);
  2073. if (al_obj == AL_OBJ_TDCTO) {
  2074. /* Copy the time object to the CTO for any other relative time objects in this response */
  2075. nstime_copy(al_cto, &al_abstime);
  2076. }
  2077. offset = data_pos;
  2078. break;
  2079. case AL_OBJ_TDELAYF: /* Time Delay - Fine (Obj:52, Var:02) */
  2080. al_val16 = tvb_get_letohs(tvb, data_pos);
  2081. proto_tree_add_text(object_tree, tvb, data_pos, 2, "Time Delay: %u ms", al_val16);
  2082. data_pos += 2;
  2083. proto_item_set_len(point_item, data_pos - offset);
  2084. offset = data_pos;
  2085. break;
  2086. case AL_OBJ_CLASS0: /* Class Data Objects */
  2087. case AL_OBJ_CLASS1:
  2088. case AL_OBJ_CLASS2:
  2089. case AL_OBJ_CLASS3:
  2090. /* No data here */
  2091. offset = data_pos;
  2092. break;
  2093. case AL_OBJ_FILE_CMD: /* File Control - File Command (Obj:70, Var:03) */
  2094. /* File name offset and length */
  2095. al_filename_offs = tvb_get_letohs(tvb, data_pos);
  2096. proto_tree_add_text(point_tree, tvb, data_pos, 2, "File String Offset: %u", al_filename_offs);
  2097. data_pos += 2;
  2098. al_filename_len = tvb_get_letohs(tvb, data_pos);
  2099. proto_tree_add_text(point_tree, tvb, data_pos, 2, "File String Length: %u", al_filename_len);
  2100. data_pos += 2;
  2101. /* Grab the mode as it determines if some of the following fields are relevant */
  2102. al_file_ctrl_mode = tvb_get_letohs(tvb, data_pos + 16);
  2103. /* Creation Time */
  2104. if (al_file_ctrl_mode == AL_OBJ_FILE_MODE_WRITE) {
  2105. dnp3_al_get_timestamp(&al_abstime, tvb, data_pos);
  2106. proto_tree_add_time(point_tree, hf_dnp3_al_timestamp, tvb, data_pos, 6, &al_abstime);
  2107. }
  2108. data_pos += 6;
  2109. /* Perms */
  2110. if (al_file_ctrl_mode == AL_OBJ_FILE_MODE_WRITE) {
  2111. proto_item *perms_item;
  2112. proto_tree *perms_tree;
  2113. perms_item = proto_tree_add_item(point_tree, hf_dnp3_al_file_perms, tvb, offset, 2, ENC_LITTLE_ENDIAN);
  2114. perms_tree = proto_item_add_subtree(perms_item, ett_dnp3_al_obj_point_perms);
  2115. proto_tree_add_item(perms_tree, hf_dnp3_al_file_perms_read_owner, tvb, offset, 2, ENC_LITTLE_ENDIAN);
  2116. proto_tree_add_item(perms_tree, hf_dnp3_al_file_perms_write_owner, tvb, offset, 2, ENC_LITTLE_ENDIAN);
  2117. proto_tree_add_item(perms_tree, hf_dnp3_al_file_perms_exec_owner, tvb, offset, 2, ENC_LITTLE_ENDIAN);
  2118. proto_tree_add_item(perms_tree, hf_dnp3_al_file_perms_read_group, tvb, offset, 2, ENC_LITTLE_ENDIAN);
  2119. proto_tree_add_item(perms_tree, hf_dnp3_al_file_perms_write_group, tvb, offset, 2, ENC_LITTLE_ENDIAN);
  2120. proto_tree_add_item(perms_tree, hf_dnp3_al_file_perms_exec_group, tvb, offset, 2, ENC_LITTLE_ENDIAN);
  2121. proto_tree_add_item(perms_tree, hf_dnp3_al_file_perms_read_world, tvb, offset, 2, ENC_LITTLE_ENDIAN);
  2122. proto_tree_add_item(perms_tree, hf_dnp3_al_file_perms_write_world, tvb, offset, 2, ENC_LITTLE_ENDIAN);
  2123. proto_tree_add_item(perms_tree, hf_dnp3_al_file_perms_exec_world, tvb, offset, 2, ENC_LITTLE_ENDIAN);
  2124. }
  2125. data_pos += 2;
  2126. /* Auth Key */
  2127. proto_tree_add_item(point_tree, hf_dnp3_al_file_auth, tvb, data_pos, 4, ENC_LITTLE_ENDIAN);
  2128. data_pos += 4;
  2129. /* File Size */
  2130. if (al_file_ctrl_mode == AL_OBJ_FILE_MODE_WRITE || al_file_ctrl_mode == AL_OBJ_FILE_MODE_APPEND) {
  2131. proto_tree_add_item(point_tree, hf_dnp3_al_file_size, tvb, data_pos, 4, ENC_LITTLE_ENDIAN);
  2132. }
  2133. data_pos += 4;
  2134. /* Mode */
  2135. proto_tree_add_item(point_tree, hf_dnp3_al_file_mode, tvb, data_pos, 2, ENC_LITTLE_ENDIAN);
  2136. data_pos += 2;
  2137. /* Max Block Size */
  2138. proto_tree_add_item(point_tree, hf_dnp3_al_file_maxblk, tvb, data_pos, 2, ENC_LITTLE_ENDIAN);
  2139. data_pos += 2;
  2140. /* Request ID */
  2141. proto_tree_add_item(point_tree, hf_dnp3_al_file_reqID, tvb, data_pos, 2, ENC_LITTLE_ENDIAN);
  2142. data_pos += 2;
  2143. /* Filename */
  2144. if (al_filename_len > 0) {
  2145. const gchar *al_filename;
  2146. al_filename = tvb_get_ephemeral_string(tvb, data_pos, al_filename_len);
  2147. proto_tree_add_text(point_tree, tvb, data_pos, al_filename_len, "File Name: %s", al_filename);
  2148. }
  2149. data_pos += al_filename_len;
  2150. proto_item_set_len(point_item, data_pos - offset);
  2151. offset = data_pos;
  2152. break;
  2153. case AL_OBJ_FILE_STAT: /* File Control - File Status (Obj:70, Var:04) */
  2154. /* File Handle */
  2155. proto_tree_add_item(point_tree, hf_dnp3_al_file_handle, tvb, data_pos, 4, ENC_LITTLE_ENDIAN);
  2156. data_pos += 4;
  2157. /* File Size */
  2158. proto_tree_add_item(point_tree, hf_dnp3_al_file_size, tvb, data_pos, 4, ENC_LITTLE_ENDIAN);
  2159. data_pos += 4;
  2160. /* Max Block Size */
  2161. proto_tree_add_item(point_tree, hf_dnp3_al_file_maxblk, tvb, data_pos, 2, ENC_LITTLE_ENDIAN);
  2162. data_pos += 2;
  2163. /* Request ID */
  2164. proto_tree_add_item(point_tree, hf_dnp3_al_file_reqID, tvb, data_pos, 2, ENC_LITTLE_ENDIAN);
  2165. data_pos += 2;
  2166. /* Status code */
  2167. proto_tree_add_item(point_tree, hf_dnp3_al_file_status, tvb, data_pos, 1, ENC_LITTLE_ENDIAN);
  2168. data_pos += 1;
  2169. /* Optional text */
  2170. file_data_size = al_ptaddr - (data_pos - offset - indexbytes);
  2171. if ((file_data_size) > 0) {
  2172. proto_tree_add_item(point_tree, hf_dnp3_al_file_data, tvb, data_pos, file_data_size, ENC_NA);
  2173. data_pos += file_data_size;
  2174. }
  2175. proto_item_set_len(point_item, data_pos - offset);
  2176. offset = data_pos;
  2177. break;
  2178. case AL_OBJ_FILE_TRANS: /* File Control - File Transport (Obj:70, Var:05) */
  2179. /* File Handle */
  2180. proto_tree_add_item(point_tree, hf_dnp3_al_file_handle, tvb, data_pos, 4, ENC_LITTLE_ENDIAN);
  2181. data_pos += 4;
  2182. /* File block (bits 0 - 30) and last block flag (bit 31) */
  2183. proto_tree_add_item(point_tree, hf_dnp3_al_file_blocknum, tvb, data_pos, 4, ENC_LITTLE_ENDIAN);
  2184. proto_tree_add_item(point_tree, hf_dnp3_al_file_lastblock, tvb, data_pos, 4, ENC_LITTLE_ENDIAN);
  2185. data_pos += 4;
  2186. /* File data */
  2187. file_data_size = al_ptaddr - (data_pos - offset - indexbytes);
  2188. if ((file_data_size) > 0) {
  2189. proto_tree_add_item(point_tree, hf_dnp3_al_file_data, tvb, data_pos, file_data_size, ENC_NA);
  2190. data_pos += file_data_size;
  2191. }
  2192. proto_item_set_len(point_item, data_pos - offset);
  2193. offset = data_pos;
  2194. break;
  2195. case AL_OBJ_FILE_TRAN_ST: /* File Control Tansport Status (Obj:70, Var:06) */
  2196. /* File Handle */
  2197. proto_tree_add_item(point_tree, hf_dnp3_al_file_handle, tvb, data_pos, 4, ENC_LITTLE_ENDIAN);
  2198. data_pos += 4;
  2199. /* File block (bits 0 - 30) and last block flag (bit 31) */
  2200. proto_tree_add_item(point_tree, hf_dnp3_al_file_blocknum, tvb, data_pos, 4, ENC_LITTLE_ENDIAN);
  2201. proto_tree_add_item(point_tree, hf_dnp3_al_file_lastblock, tvb, data_pos, 4, ENC_LITTLE_ENDIAN);
  2202. data_pos += 4;
  2203. /* Status code */
  2204. proto_tree_add_item(point_tree, hf_dnp3_al_file_status, tvb, data_pos, 1, ENC_LITTLE_ENDIAN);
  2205. data_pos += 1;
  2206. /* Optional text */
  2207. file_data_size = al_ptaddr - (data_pos - offset - indexbytes);
  2208. if ((file_data_size) > 0) {
  2209. proto_tree_add_item(point_tree, hf_dnp3_al_file_data, tvb, data_pos, file_data_size, ENC_NA);
  2210. data_pos += file_data_size;
  2211. }
  2212. proto_item_set_len(point_item, data_pos - offset);
  2213. offset = data_pos;
  2214. break;
  2215. case AL_OBJ_IIN: /* IIN Data Object */
  2216. /* Single byte of data here */
  2217. proto_tree_add_text(object_tree, tvb, data_pos, 1, "Value: %u", tvb_get_guint8(tvb, data_pos));
  2218. data_pos += 1;
  2219. proto_item_set_len(point_item, data_pos - offset);
  2220. offset = data_pos;
  2221. break;
  2222. case AL_OBJ_OCT: /* Octet string */
  2223. case AL_OBJ_OCT_EVT: /* Octet string event */
  2224. /* read the number of bytes defined by the variation */
  2225. if (al_oct_len > 0) {
  2226. proto_tree_add_text(object_tree, tvb, data_pos, al_oct_len, "Octet String (%u bytes)", al_oct_len);
  2227. data_pos += al_oct_len;
  2228. proto_item_set_len(point_item, data_pos - offset);
  2229. }
  2230. offset = data_pos;
  2231. break;
  2232. default: /* In case of unknown object */
  2233. proto_tree_add_text(object_tree, tvb, offset, -1,
  2234. "Unknown Data Chunk, %u Bytes", tvb_reported_length_remaining(tvb, offset));
  2235. offset = tvb_length(tvb); /* Finish decoding if unknown object is encountered... */
  2236. break;
  2237. }
  2238. /* Increment the bit index for next time */
  2239. bitindex++;
  2240. /* And increment the point address, may be overwritten by an index value */
  2241. al_ptaddr++;
  2242. }
  2243. if (start_offset > offset) {
  2244. expert_add_info(pinfo, point_item, &ei_dnp_invalid_length);
  2245. offset = tvb_length(tvb); /* Finish decoding if unknown object is encountered... */
  2246. }
  2247. }
  2248. }
  2249. proto_item_set_len(object_item, offset - orig_offset);
  2250. return offset;
  2251. }
  2252. /*****************************************************************/
  2253. /* Application Layer Dissector */
  2254. /*****************************************************************/
  2255. static int
  2256. dissect_dnp3_al(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
  2257. {
  2258. guint8 al_ctl, al_seq, al_func, al_class = 0, i;
  2259. guint16 bytes, obj_type;
  2260. guint data_len = 0, offset = 0;
  2261. proto_item *ti, *tc, *t_robj;
  2262. proto_tree *al_tree, *field_tree, *robj_tree;
  2263. const gchar *func_code_str;
  2264. nstime_t al_cto;
  2265. nstime_set_zero (&al_cto);
  2266. data_len = tvb_length(tvb);
  2267. /* Handle the control byte and function code */
  2268. al_ctl = tvb_get_guint8(tvb, offset);
  2269. al_seq = al_ctl & DNP3_AL_SEQ;
  2270. al_func = tvb_get_guint8(tvb, (offset+1));
  2271. func_code_str = val_to_str_ext(al_func, &dnp3_al_func_vals_ext, "Unknown function (0x%02x)");
  2272. /* Clear out lower layer info */
  2273. col_clear(pinfo->cinfo, COL_INFO);
  2274. col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "%s", func_code_str);
  2275. col_set_fence(pinfo->cinfo, COL_INFO);
  2276. /* format up the text representation */
  2277. ti = proto_tree_add_text(tree, tvb, offset, data_len, "Application Layer: (");
  2278. if (al_ctl & DNP3_AL_FIR) proto_item_append_text(ti, "FIR, ");
  2279. if (al_ctl & DNP3_AL_FIN) proto_item_append_text(ti, "FIN, ");
  2280. if (al_ctl & DNP3_AL_CON) proto_item_append_text(ti, "CON, ");
  2281. if (al_ctl & DNP3_AL_UNS) proto_item_append_text(ti, "UNS, ");
  2282. proto_item_append_text(ti, "Sequence %u, %s)", al_seq, func_code_str);
  2283. /* Add the al tree branch */
  2284. al_tree = proto_item_add_subtree(ti, ett_dnp3_al);
  2285. /* Application Layer control byte subtree */
  2286. tc = proto_tree_add_uint_format(al_tree, hf_dnp3_al_ctl, tvb, offset, 1, al_ctl,
  2287. "Control: 0x%02x (", al_ctl);
  2288. if (al_ctl & DNP3_AL_FIR) proto_item_append_text(tc, "FIR, ");
  2289. if (al_ctl & DNP3_AL_FIN) proto_item_append_text(tc, "FIN, ");
  2290. if (al_ctl & DNP3_AL_CON) proto_item_append_text(tc, "CON, ");
  2291. if (al_ctl & DNP3_AL_UNS) proto_item_append_text(tc, "UNS, ");
  2292. proto_item_append_text(tc, "Sequence %u)", al_seq);
  2293. field_tree = proto_item_add_subtree(tc, ett_dnp3_al_ctl);
  2294. proto_tree_add_boolean(field_tree, hf_dnp3_al_fir, tvb, offset, 1, al_ctl);
  2295. proto_tree_add_boolean(field_tree, hf_dnp3_al_fin, tvb, offset, 1, al_ctl);
  2296. proto_tree_add_boolean(field_tree, hf_dnp3_al_con, tvb, offset, 1, al_ctl);
  2297. proto_tree_add_boolean(field_tree, hf_dnp3_al_uns, tvb, offset, 1, al_ctl);
  2298. proto_tree_add_item(field_tree, hf_dnp3_al_seq, tvb, offset, 1, ENC_BIG_ENDIAN);
  2299. offset += 1;
  2300. #if 0
  2301. /* If this packet is NOT the final Application Layer Message, exit and continue
  2302. processing the remaining data in the fragment. */
  2303. if (!(al_ctl & DNP3_AL_FIN)) {
  2304. t_robj = proto_tree_add_text(al_tree, tvb, offset, -1, "Buffering User Data Until Final Frame is Received..");
  2305. return 1;
  2306. }
  2307. #endif
  2308. /* Application Layer Function Code Byte */
  2309. proto_tree_add_uint_format(al_tree, hf_dnp3_al_func, tvb, offset, 1, al_func,
  2310. "Function Code: %s (0x%02x)", func_code_str, al_func);
  2311. offset += 1;
  2312. switch (al_func)
  2313. {
  2314. case AL_FUNC_READ: /* Read Function Code 0x01 */
  2315. /* Create Read Request Data Objects Tree */
  2316. t_robj = proto_tree_add_text(al_tree, tvb, offset, -1, "READ Request Data Objects");
  2317. robj_tree = proto_item_add_subtree(t_robj, ett_dnp3_al_objdet);
  2318. /* Process Data Object Details */
  2319. while (offset <= (data_len-2)) { /* 2 octet object code + CRC32 */
  2320. offset = dnp3_al_process_object(tvb, pinfo, offset, robj_tree, TRUE, &obj_type, &al_cto);
  2321. /* Update class type for each object that was a class read */
  2322. switch(obj_type) {
  2323. case AL_OBJ_CLASS0:
  2324. case AL_OBJ_CLASS1:
  2325. case AL_OBJ_CLASS2:
  2326. case AL_OBJ_CLASS3:
  2327. al_class |= (1 << ((obj_type & 0x0f) - 1));
  2328. break;
  2329. default:
  2330. break;
  2331. }
  2332. }
  2333. /* Update the col info if there were class reads */
  2334. if (al_class != 0) {
  2335. col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Class ");
  2336. for (i = 0; i < 4; i++) {
  2337. if (al_class & (1 << i)) {
  2338. col_append_fstr(pinfo->cinfo, COL_INFO, "%u", i);
  2339. }
  2340. }
  2341. }
  2342. /* For reads for specific object types, bit-mask out the first byte and use that to determine the column info to add */
  2343. switch(obj_type & 0xFF00) {
  2344. case AL_OBJ_BI_ALL: col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Binary Input"); break;
  2345. case AL_OBJ_BIC_ALL: col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Binary Input Change"); break;
  2346. case AL_OBJ_2BI_ALL: col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Double-bit Input"); break;
  2347. case AL_OBJ_BO_ALL: col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Binary Output"); break;
  2348. case AL_OBJ_CTR_ALL: col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Counter"); break;
  2349. case AL_OBJ_FCTR_ALL: col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Frozen Counter"); break;
  2350. case AL_OBJ_CTRC_ALL: col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Counter Change"); break;
  2351. case AL_OBJ_FCTRC_ALL: col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Frozen Counter Change"); break;
  2352. case AL_OBJ_AI_ALL: col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Analog Input"); break;
  2353. case AL_OBJ_AIC_ALL: col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Analog Input Change"); break;
  2354. case AL_OBJ_AO_ALL: col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Analog Output"); break;
  2355. case AL_OBJ_AOC_ALL: col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Analog Output Change"); break;
  2356. default: break;
  2357. }
  2358. break;
  2359. case AL_FUNC_WRITE: /* Write Function Code 0x02 */
  2360. /* Create Write Request Data Objects Tree */
  2361. t_robj = proto_tree_add_text(al_tree, tvb, offset, -1, "WRITE Request Data Objects");
  2362. robj_tree = proto_item_add_subtree(t_robj, ett_dnp3_al_objdet);
  2363. /* Process Data Object Details */
  2364. while (offset <= (data_len-2)) { /* 2 octet object code + CRC32 */
  2365. offset = dnp3_al_process_object(tvb, pinfo, offset, robj_tree, FALSE, &obj_type, &al_cto);
  2366. }
  2367. break;
  2368. case AL_FUNC_SELECT: /* Select Function Code 0x03 */
  2369. /* Create Select Request Data Objects Tree */
  2370. t_robj = proto_tree_add_text(al_tree, tvb, offset, -1, "SELECT Request Data Objects");
  2371. robj_tree = proto_item_add_subtree(t_robj, ett_dnp3_al_objdet);
  2372. /* Process Data Object Details */
  2373. while (offset <= (data_len-2)) { /* 2 octet object code + CRC32 */
  2374. offset = dnp3_al_process_object(tvb, pinfo, offset, robj_tree, FALSE, &obj_type, &al_cto);
  2375. }
  2376. break;
  2377. case AL_FUNC_OPERATE: /* Operate Function Code 0x04 */
  2378. /* Functionally identical to 'SELECT' Function Code */
  2379. /* Create Operate Request Data Objects Tree */
  2380. t_robj = proto_tree_add_text(al_tree, tvb, offset, -1, "OPERATE Request Data Objects");
  2381. robj_tree = proto_item_add_subtree(t_robj, ett_dnp3_al_objdet);
  2382. /* Process Data Object Details */
  2383. while (offset <= (data_len-2)) { /* 2 octet object code + CRC32 */
  2384. offset = dnp3_al_process_object(tvb, pinfo, offset, robj_tree, FALSE, &obj_type, &al_cto);
  2385. }
  2386. break;
  2387. case AL_FUNC_DIROP: /* Direct Operate Function Code 0x05 */
  2388. /* Functionally identical to 'SELECT' Function Code */
  2389. /* Create Direct Operate Request Data Objects Tree */
  2390. t_robj = proto_tree_add_text(al_tree, tvb, offset, -1, "DIRECT OPERATE Request Data Objects");
  2391. robj_tree = proto_item_add_subtree(t_robj, ett_dnp3_al_objdet);
  2392. /* Process Data Object Details */
  2393. while (offset <= (data_len-2)) { /* 2 octet object code + CRC32 */
  2394. offset = dnp3_al_process_object(tvb, pinfo, offset, robj_tree, FALSE, &obj_type, &al_cto);
  2395. }
  2396. break;
  2397. case AL_FUNC_ENSPMSG: /* Enable Spontaneous Messages Function Code 0x14 */
  2398. /* Create Enable Spontaneous Messages Data Objects Tree */
  2399. t_robj = proto_tree_add_text(al_tree, tvb, offset, -1, "Enable Spontaneous Msg's Data Objects");
  2400. robj_tree = proto_item_add_subtree(t_robj, ett_dnp3_al_objdet);
  2401. /* Process Data Object Details */
  2402. while (offset <= (data_len-2)) { /* 2 octet object code + CRC32 */
  2403. offset = dnp3_al_process_object(tvb, pinfo, offset, robj_tree, FALSE, &obj_type, &al_cto);
  2404. }
  2405. break;
  2406. case AL_FUNC_DISSPMSG: /* Disable Spontaneous Messages Function Code 0x15 */
  2407. /* Create Disable Spontaneous Messages Data Objects Tree */
  2408. t_robj = proto_tree_add_text(al_tree, tvb, offset, -1, "Disable Spontaneous Msg's Data Objects");
  2409. robj_tree = proto_item_add_subtree(t_robj, ett_dnp3_al_objdet);
  2410. /* Process Data Object Details */
  2411. while (offset <= (data_len-2)) { /* 2 octet object code + CRC32 */
  2412. offset = dnp3_al_process_object(tvb, pinfo, offset, robj_tree, FALSE, &obj_type, &al_cto);
  2413. }
  2414. break;
  2415. case AL_FUNC_DELAYMST: /* Delay Measurement Function Code 0x17 */
  2416. break;
  2417. case AL_FUNC_OPENFILE: /* Open File Function Code 0x19 */
  2418. case AL_FUNC_CLOSEFILE: /* Close File Function Code 0x1A */
  2419. case AL_FUNC_DELETEFILE: /* Delete File Function Code 0x1B */
  2420. /* Create File Data Objects Tree */
  2421. t_robj = proto_tree_add_text(al_tree, tvb, offset, -1, "File Data Objects");
  2422. robj_tree = proto_item_add_subtree(t_robj, ett_dnp3_al_objdet);
  2423. /* Process Data Object Details */
  2424. while (offset <= (data_len-2)) { /* 2 octet object code + CRC32 */
  2425. offset = dnp3_al_process_object(tvb, pinfo, offset, robj_tree, FALSE, &obj_type, &al_cto);
  2426. }
  2427. break;
  2428. case AL_FUNC_RESPON: /* Response Function Code 0x81 */
  2429. case AL_FUNC_UNSOLI: /* Unsolicited Response Function Code 0x82 */
  2430. /* Application Layer IIN bits req'd if message is a response */
  2431. dnp3_al_process_iin(tvb, offset, al_tree);
  2432. offset += 2;
  2433. /* Ensure there is actual data remaining in the message.
  2434. A response will not contain data following the IIN bits,
  2435. if there is none available */
  2436. bytes = tvb_reported_length_remaining(tvb, offset);
  2437. if (bytes > 0)
  2438. {
  2439. /* Create Response Data Objects Tree */
  2440. t_robj = proto_tree_add_text(al_tree, tvb, offset, -1,"RESPONSE Data Objects");
  2441. robj_tree = proto_item_add_subtree(t_robj, ett_dnp3_al_objdet);
  2442. /* Process Data Object Details */
  2443. while (offset <= (data_len-2)) { /* 2 octet object code + CRC32 */
  2444. offset = dnp3_al_process_object(tvb, pinfo, offset, robj_tree, FALSE, &obj_type, &al_cto);
  2445. }
  2446. break;
  2447. }
  2448. default: /* Unknown Function */
  2449. break;
  2450. }
  2451. return 0;
  2452. }
  2453. /*****************************************************************/
  2454. /* Data Link and Transport layer dissector */
  2455. /*****************************************************************/
  2456. static void
  2457. dissect_dnp3_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
  2458. {
  2459. proto_item *ti, *tdl, *tc;
  2460. proto_tree *dnp3_tree, *dl_tree, *field_tree;
  2461. int offset = 0, temp_offset = 0;
  2462. gboolean dl_prm;
  2463. guint8 dl_len, dl_ctl, dl_func;
  2464. const gchar *func_code_str;
  2465. guint16 dl_dst, dl_src, dl_crc, calc_dl_crc;
  2466. /* Make entries in Protocol column and Info column on summary display */
  2467. col_set_str(pinfo->cinfo, COL_PROTOCOL, "DNP 3.0");
  2468. col_clear(pinfo->cinfo, COL_INFO);
  2469. /* Skip "0x0564" header bytes */
  2470. temp_offset += 2;
  2471. dl_len = tvb_get_guint8(tvb, temp_offset);
  2472. temp_offset += 1;
  2473. dl_ctl = tvb_get_guint8(tvb, temp_offset);
  2474. temp_offset += 1;
  2475. dl_dst = tvb_get_letohs(tvb, temp_offset);
  2476. temp_offset += 2;
  2477. dl_src = tvb_get_letohs(tvb, temp_offset);
  2478. dl_func = dl_ctl & DNP3_CTL_FUNC;
  2479. dl_prm = dl_ctl & DNP3_CTL_PRM;
  2480. func_code_str = val_to_str(dl_func, dl_prm ? dnp3_ctl_func_pri_vals : dnp3_ctl_func_sec_vals,
  2481. "Unknown function (0x%02x)");
  2482. /* Make sure source and dest are always in the info column */
  2483. col_append_fstr(pinfo->cinfo, COL_INFO, "from %u to %u", dl_src, dl_dst);
  2484. col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "len=%u, %s", dl_len, func_code_str);
  2485. /* create display subtree for the protocol */
  2486. ti = proto_tree_add_item(tree, proto_dnp3, tvb, offset, -1, ENC_NA);
  2487. dnp3_tree = proto_item_add_subtree(ti, ett_dnp3);
  2488. /* Create Subtree for Data Link Layer */
  2489. tdl = proto_tree_add_text(dnp3_tree, tvb, offset, DNP_HDR_LEN,
  2490. "Data Link Layer, Len: %u, From: %u, To: %u, ", dl_len, dl_src, dl_dst);
  2491. if (dl_prm) {
  2492. if (dl_ctl & DNP3_CTL_DIR) proto_item_append_text(tdl, "DIR, ");
  2493. if (dl_ctl & DNP3_CTL_PRM) proto_item_append_text(tdl, "PRM, ");
  2494. if (dl_ctl & DNP3_CTL_FCB) proto_item_append_text(tdl, "FCB, ");
  2495. if (dl_ctl & DNP3_CTL_FCV) proto_item_append_text(tdl, "FCV, ");
  2496. }
  2497. else {
  2498. if (dl_ctl & DNP3_CTL_DIR) proto_item_append_text(tdl, "DIR, ");
  2499. if (dl_ctl & DNP3_CTL_PRM) proto_item_append_text(tdl, "PRM, ");
  2500. if (dl_ctl & DNP3_CTL_RES) proto_item_append_text(tdl, "RES, ");
  2501. if (dl_ctl & DNP3_CTL_DFC) proto_item_append_text(tdl, "DFC, ");
  2502. }
  2503. proto_item_append_text(tdl, "%s", func_code_str);
  2504. dl_tree = proto_item_add_subtree(tdl, ett_dnp3_dl);
  2505. /* start bytes */
  2506. proto_tree_add_item(dl_tree, hf_dnp3_start, tvb, offset, 2, ENC_BIG_ENDIAN);
  2507. offset += 2;
  2508. /* add length field */
  2509. proto_tree_add_item(dl_tree, hf_dnp3_len, tvb, offset, 1, ENC_BIG_ENDIAN);
  2510. offset += 1;
  2511. /* Add Control Byte Subtree */
  2512. tc = proto_tree_add_uint_format(dl_tree, hf_dnp3_ctl, tvb, offset, 1, dl_ctl,
  2513. "Control: 0x%02x (", dl_ctl);
  2514. /* Add Text to Control Byte Subtree Header */
  2515. if (dl_prm) {
  2516. if (dl_ctl & DNP3_CTL_DIR) proto_item_append_text(tc, "DIR, ");
  2517. if (dl_ctl & DNP3_CTL_PRM) proto_item_append_text(tc, "PRM, ");
  2518. if (dl_ctl & DNP3_CTL_FCB) proto_item_append_text(tc, "FCB, ");
  2519. if (dl_ctl & DNP3_CTL_FCV) proto_item_append_text(tc, "FCV, ");
  2520. }
  2521. else {
  2522. if (dl_ctl & DNP3_CTL_DIR) proto_item_append_text(tc, "DIR, ");
  2523. if (dl_ctl & DNP3_CTL_PRM) proto_item_append_text(tc, "PRM, ");
  2524. if (dl_ctl & DNP3_CTL_RES) proto_item_append_text(tc, "RES, ");
  2525. if (dl_ctl & DNP3_CTL_DFC) proto_item_append_text(tc, "DFC, ");
  2526. }
  2527. proto_item_append_text(tc, "%s)", func_code_str );
  2528. field_tree = proto_item_add_subtree(tc, ett_dnp3_dl_ctl);
  2529. /* Add Control Byte Subtree Items */
  2530. if (dl_prm) {
  2531. proto_tree_add_item(field_tree, hf_dnp3_ctl_dir, tvb, offset, 1, ENC_LITTLE_ENDIAN);
  2532. proto_tree_add_item(field_tree, hf_dnp3_ctl_prm, tvb, offset, 1, ENC_LITTLE_ENDIAN);
  2533. proto_tree_add_item(field_tree, hf_dnp3_ctl_fcb, tvb, offset, 1, ENC_LITTLE_ENDIAN);
  2534. proto_tree_add_item(field_tree, hf_dnp3_ctl_fcv, tvb, offset, 1, ENC_LITTLE_ENDIAN);
  2535. proto_tree_add_item(field_tree, hf_dnp3_ctl_prifunc, tvb, offset, 1, ENC_BIG_ENDIAN);
  2536. }
  2537. else {
  2538. proto_tree_add_item(field_tree, hf_dnp3_ctl_dir, tvb, offset, 1, ENC_LITTLE_ENDIAN);
  2539. proto_tree_add_item(field_tree, hf_dnp3_ctl_prm, tvb, offset, 1, ENC_LITTLE_ENDIAN);
  2540. proto_tree_add_item(field_tree, hf_dnp3_ctl_dfc, tvb, offset, 1, ENC_LITTLE_ENDIAN);
  2541. proto_tree_add_item(field_tree, hf_dnp3_ctl_secfunc, tvb, offset, 1, ENC_BIG_ENDIAN);
  2542. }
  2543. offset += 1;
  2544. /* add destination and source addresses */
  2545. proto_tree_add_item(dl_tree, hf_dnp3_dst, tvb, offset, 2, ENC_LITTLE_ENDIAN);
  2546. offset += 2;
  2547. proto_tree_add_item(dl_tree, hf_dnp3_src, tvb, offset, 2, ENC_LITTLE_ENDIAN);
  2548. offset += 2;
  2549. /* and header CRC */
  2550. dl_crc = tvb_get_letohs(tvb, offset);
  2551. calc_dl_crc = calculateCRC(tvb_get_ptr(tvb, 0, DNP_HDR_LEN - 2), DNP_HDR_LEN - 2);
  2552. if (dl_crc == calc_dl_crc)
  2553. proto_tree_add_uint_format(dl_tree, hf_dnp_hdr_CRC, tvb, offset, 2,
  2554. dl_crc, "CRC: 0x%04x [correct]", dl_crc);
  2555. else
  2556. {
  2557. proto_item *hidden_item;
  2558. hidden_item = proto_tree_add_boolean(dl_tree, hf_dnp_hdr_CRC_bad, tvb,
  2559. offset, 2, TRUE);
  2560. PROTO_ITEM_SET_HIDDEN(hidden_item);
  2561. proto_tree_add_uint_format(dl_tree, hf_dnp_hdr_CRC, tvb, offset, 2,
  2562. dl_crc, "CRC: 0x%04x [incorrect, should be 0x%04x]",
  2563. dl_crc, calc_dl_crc);
  2564. }
  2565. offset += 2;
  2566. /* If the DataLink function is 'Request Link Status' or 'Status of Link',
  2567. or 'Reset Link' we don't expect any Transport or Application Layer Data
  2568. NOTE: This code should probably check what DOES have TR or AL data */
  2569. if ((dl_func != DL_FUNC_LINK_STAT) && (dl_func != DL_FUNC_STAT_LINK) &&
  2570. (dl_func != DL_FUNC_RESET_LINK) && (dl_func != DL_FUNC_ACK))
  2571. {
  2572. proto_tree *tr_tree, *al_tree;
  2573. proto_item *al_chunks;
  2574. guint8 tr_ctl, tr_seq;
  2575. gboolean tr_fir, tr_fin;
  2576. guint8 *tmp, *tmp_ptr;
  2577. guint8 data_len;
  2578. int data_offset;
  2579. gboolean crc_OK = FALSE;
  2580. tvbuff_t *next_tvb;
  2581. guint i;
  2582. /* get the transport layer byte */
  2583. tr_ctl = tvb_get_guint8(tvb, offset);
  2584. tr_seq = tr_ctl & DNP3_TR_SEQ;
  2585. tr_fir = tr_ctl & DNP3_TR_FIR;
  2586. tr_fin = tr_ctl & DNP3_TR_FIN;
  2587. /* Add Transport Layer Tree */
  2588. tc = proto_tree_add_uint_format(dnp3_tree, hf_dnp3_tr_ctl, tvb, offset, 1, tr_ctl,
  2589. "Transport Layer: 0x%02x (", tr_ctl);
  2590. if (tr_fir) proto_item_append_text(tc, "FIR, ");
  2591. if (tr_fin) proto_item_append_text(tc, "FIN, ");
  2592. proto_item_append_text(tc, "Sequence %u)", tr_seq);
  2593. tr_tree = proto_item_add_subtree(tc, ett_dnp3_tr_ctl);
  2594. proto_tree_add_boolean(tr_tree, hf_dnp3_tr_fin, tvb, offset, 1, tr_ctl);
  2595. proto_tree_add_boolean(tr_tree, hf_dnp3_tr_fir, tvb, offset, 1, tr_ctl);
  2596. proto_tree_add_item(tr_tree, hf_dnp3_tr_seq, tvb, offset, 1, ENC_BIG_ENDIAN);
  2597. /* Allocate AL chunk tree */
  2598. al_chunks = proto_tree_add_text(tr_tree, tvb, offset + 1, -1, "Application data chunks");
  2599. al_tree = proto_item_add_subtree(al_chunks, ett_dnp3_al_data);
  2600. /* extract the application layer data, validating the CRCs */
  2601. /* XXX - check for dl_len <= 5 */
  2602. data_len = dl_len - 5;
  2603. tmp = (guint8 *)wmem_alloc(pinfo->pool, data_len);
  2604. tmp_ptr = tmp;
  2605. i = 0;
  2606. data_offset = 1; /* skip the transport layer byte when assembling chunks */
  2607. while (data_len > 0)
  2608. {
  2609. guint8 chk_size;
  2610. const guint8 *chk_ptr;
  2611. guint16 calc_crc, act_crc;
  2612. chk_size = MIN(data_len, AL_MAX_CHUNK_SIZE);
  2613. chk_ptr = tvb_get_ptr(tvb, offset, chk_size);
  2614. memcpy(tmp_ptr, chk_ptr + data_offset, chk_size - data_offset);
  2615. calc_crc = calculateCRC(chk_ptr, chk_size);
  2616. offset += chk_size;
  2617. tmp_ptr += chk_size - data_offset;
  2618. act_crc = tvb_get_letohs(tvb, offset);
  2619. offset += 2;
  2620. crc_OK = calc_crc == act_crc;
  2621. if (crc_OK)
  2622. {
  2623. proto_tree_add_text(al_tree, tvb, offset - (chk_size + 2), chk_size + 2,
  2624. "Application Chunk %u Len: %u CRC 0x%04x",
  2625. i, chk_size, act_crc);
  2626. data_len -= chk_size;
  2627. }
  2628. else
  2629. {
  2630. proto_tree_add_text(al_tree, tvb, offset - (chk_size + 2), chk_size + 2,
  2631. "Application Chunk %u Len: %u Bad CRC got 0x%04x expected 0x%04x",
  2632. i, chk_size, act_crc, calc_crc);
  2633. break;
  2634. }
  2635. i++;
  2636. data_offset = 0; /* copy all of the rest of the chunks */
  2637. }
  2638. /* if all crc OK, set up new tvb */
  2639. if (crc_OK)
  2640. {
  2641. tvbuff_t *al_tvb;
  2642. gboolean save_fragmented;
  2643. al_tvb = tvb_new_child_real_data(tvb, tmp, (guint) (tmp_ptr-tmp), (gint) (tmp_ptr-tmp));
  2644. /* Check for fragmented packet */
  2645. save_fragmented = pinfo->fragmented;
  2646. if (! (tr_fir && tr_fin))
  2647. {
  2648. guint conv_seq_number;
  2649. fragment_head *frag_msg;
  2650. conversation_t *conversation;
  2651. dnp3_conv_t *conv_data_ptr;
  2652. dl_conversation_key_t dl_conversation_key;
  2653. /* A fragmented packet */
  2654. pinfo->fragmented = TRUE;
  2655. /* Look up the conversation to get the fragment reassembly id */
  2656. conversation = find_or_create_conversation(pinfo);
  2657. /*
  2658. * The TCP/UDP conversation is not sufficient to identify a conversation
  2659. * on a multi-drop DNP network. Lookup conversation data based on TCP/UDP
  2660. * conversation and the DNP src and dst addresses
  2661. */
  2662. dl_conversation_key.conversation = conversation->index;
  2663. dl_conversation_key.src = dl_src;
  2664. dl_conversation_key.dst = dl_dst;
  2665. conv_data_ptr = (dnp3_conv_t*)g_hash_table_lookup(dl_conversation_table, &dl_conversation_key);
  2666. if (!pinfo->fd->flags.visited && conv_data_ptr == NULL)
  2667. {
  2668. dl_conversation_key_t* new_dl_conversation_key = NULL;
  2669. new_dl_conversation_key = se_new(dl_conversation_key_t);
  2670. *new_dl_conversation_key = dl_conversation_key;
  2671. conv_data_ptr = se_new(dnp3_conv_t);
  2672. /*** Increment static global fragment reassembly id ***/
  2673. conv_data_ptr->conv_seq_number = seq_number++;
  2674. g_hash_table_insert(dl_conversation_table, new_dl_conversation_key, conv_data_ptr);
  2675. }
  2676. conv_seq_number = conv_data_ptr->conv_seq_number;
  2677. /*
  2678. * Add the frame to
  2679. * whatever reassembly is in progress, if any, and see
  2680. * if it's done.
  2681. */
  2682. frag_msg = fragment_add_seq_next(&al_reassembly_table,
  2683. al_tvb, 0, pinfo, conv_seq_number, NULL,
  2684. tvb_reported_length(al_tvb), /* As this is a constructed tvb, all of it is ok */
  2685. !tr_fin);
  2686. next_tvb = process_reassembled_data(al_tvb, 0, pinfo,
  2687. "Reassembled DNP 3.0 Application Layer message", frag_msg, &dnp3_frag_items,
  2688. NULL, tr_tree);
  2689. if (next_tvb) /* Reassembled */
  2690. {
  2691. /* We have the complete payload, zap the info column as the AL info takes precedence */
  2692. col_clear(pinfo->cinfo, COL_INFO);
  2693. }
  2694. else
  2695. {
  2696. /* We don't have the complete reassembled payload. */
  2697. col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "TL fragment %u ", tr_seq);
  2698. }
  2699. }
  2700. else
  2701. {
  2702. /* No reassembly required */
  2703. next_tvb = al_tvb;
  2704. add_new_data_source(pinfo, next_tvb, "DNP 3.0 Application Layer message");
  2705. col_clear(pinfo->cinfo, COL_INFO);
  2706. }
  2707. pinfo->fragmented = save_fragmented;
  2708. }
  2709. else
  2710. {
  2711. /* CRC error - throw away the data. */
  2712. next_tvb = NULL;
  2713. proto_tree_add_text(dnp3_tree, tvb, 11, -1, "CRC failed, %u chunks", i);
  2714. }
  2715. /* Dissect any completed AL message */
  2716. if (next_tvb)
  2717. {
  2718. /* As a complete AL message will have cleared the info column,
  2719. make sure source and dest are always in the info column */
  2720. col_append_fstr(pinfo->cinfo, COL_INFO, "from %u to %u", dl_src, dl_dst);
  2721. col_set_fence(pinfo->cinfo, COL_INFO);
  2722. dissect_dnp3_al(next_tvb, pinfo, dnp3_tree);
  2723. }
  2724. else
  2725. {
  2726. /* Lock any column info set by the DL and TL */
  2727. col_set_fence(pinfo->cinfo, COL_INFO);
  2728. }
  2729. }
  2730. }
  2731. static guint
  2732. get_dnp3_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
  2733. {
  2734. guint16 message_len; /* need 16 bits as total can exceed 255 */
  2735. guint16 data_crc; /* No. of user data CRC bytes */
  2736. message_len = tvb_get_guint8(tvb, offset + 2);
  2737. /* Add in 2 bytes for header start octets,
  2738. 1 byte for len itself,
  2739. 2 bytes for header CRC
  2740. data CRC bytes (2 bytes per 16 bytes of data
  2741. */
  2742. data_crc = (guint16)(ceil((message_len - 5) / 16.0)) * 2;
  2743. message_len += 2 + 1 + 2 + data_crc;
  2744. return message_len;
  2745. }
  2746. static gboolean
  2747. dissect_dnp3_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
  2748. {
  2749. gint length = tvb_length(tvb);
  2750. /* Check for a dnp packet. It should begin with 0x0564 */
  2751. if ((length < 2) || (tvb_get_ntohs(tvb, 0) != 0x0564)) {
  2752. /* Not a DNP 3.0 packet, just happened to use the same port */
  2753. return FALSE;
  2754. }
  2755. tcp_dissect_pdus(tvb, pinfo, tree, TRUE, DNP_HDR_LEN,
  2756. get_dnp3_message_len, dissect_dnp3_message);
  2757. return TRUE;
  2758. }
  2759. static gboolean
  2760. dissect_dnp3_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
  2761. {
  2762. gint length = tvb_length(tvb);
  2763. /* Check for a dnp packet. It should begin with 0x0564 */
  2764. if ((length < 2) || (tvb_get_ntohs(tvb, 0) != 0x0564)) {
  2765. /* Not a DNP 3.0 packet, just happened to use the same port */
  2766. return FALSE;
  2767. }
  2768. dissect_dnp3_message(tvb, pinfo, tree);
  2769. return TRUE;
  2770. }
  2771. static void
  2772. dnp3_init(void)
  2773. {
  2774. if (dl_conversation_table)
  2775. {
  2776. g_hash_table_destroy(dl_conversation_table);
  2777. }
  2778. dl_conversation_table = g_hash_table_new(dl_conversation_hash, dl_conversation_equal);
  2779. reassembly_table_init(&al_reassembly_table,
  2780. &addresses_reassembly_table_functions);
  2781. }
  2782. /* Register the protocol with Wireshark */
  2783. void
  2784. proto_register_dnp3(void)
  2785. {
  2786. /* Setup list of header fields */
  2787. static hf_register_info hf[] = {
  2788. { &hf_dnp3_start,
  2789. { "Start Bytes", "dnp3.start",
  2790. FT_UINT16, BASE_HEX, NULL, 0x0,
  2791. NULL, HFILL }
  2792. },
  2793. { &hf_dnp3_len,
  2794. { "Length", "dnp3.len",
  2795. FT_UINT8, BASE_DEC, NULL, 0x0,
  2796. "Frame Data Length", HFILL }
  2797. },
  2798. { &hf_dnp3_ctl,
  2799. { "Control", "dnp3.ctl",
  2800. FT_UINT8, BASE_HEX, NULL, 0x0,
  2801. "Frame Control Byte", HFILL }
  2802. },
  2803. { &hf_dnp3_ctl_prifunc,
  2804. { "Control Function Code", "dnp3.ctl.prifunc",
  2805. FT_UINT8, BASE_DEC, VALS(dnp3_ctl_func_pri_vals), DNP3_CTL_FUNC,
  2806. "Frame Control Function Code", HFILL }
  2807. },
  2808. { &hf_dnp3_ctl_secfunc,
  2809. { "Control Function Code", "dnp3.ctl.secfunc",
  2810. FT_UINT8, BASE_DEC, VALS(dnp3_ctl_func_sec_vals), DNP3_CTL_FUNC,
  2811. "Frame Control Function Code", HFILL }
  2812. },
  2813. { &hf_dnp3_ctlobj_code_c,
  2814. { "Operation Type", "dnp3.ctl.op",
  2815. FT_UINT8, BASE_DEC, VALS(dnp3_al_ctlc_code_vals), AL_OBJCTLC_CODE,
  2816. "Control Code, Operation Type", HFILL }
  2817. },
  2818. { &hf_dnp3_ctlobj_code_m,
  2819. { "Queue / Clear Field", "dnp3.ctl.clr",
  2820. FT_UINT8, BASE_DEC, VALS(dnp3_al_ctlc_misc_vals), AL_OBJCTLC_MISC,
  2821. "Control Code, Clear Field", HFILL }
  2822. },
  2823. { &hf_dnp3_ctlobj_code_tc,
  2824. { "Trip Control Code", "dnp3.ctl.trip",
  2825. FT_UINT8, BASE_DEC, VALS(dnp3_al_ctlc_tc_vals), AL_OBJCTLC_TC,
  2826. "Control Code, Trip Close Control", HFILL }
  2827. },
  2828. { &hf_dnp3_ctl_dir,
  2829. { "Direction", "dnp3.ctl.dir",
  2830. FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_CTL_DIR,
  2831. NULL, HFILL }
  2832. },
  2833. { &hf_dnp3_ctl_prm,
  2834. { "Primary", "dnp3.ctl.prm",
  2835. FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_CTL_PRM,
  2836. NULL, HFILL }
  2837. },
  2838. { &hf_dnp3_ctl_fcb,
  2839. { "Frame Count Bit", "dnp3.ctl.fcb",
  2840. FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_CTL_FCB,
  2841. NULL, HFILL }
  2842. },
  2843. { &hf_dnp3_ctl_fcv,
  2844. { "Frame Count Valid", "dnp3.ctl.fcv",
  2845. FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_CTL_FCV,
  2846. NULL, HFILL }
  2847. },
  2848. { &hf_dnp3_ctl_dfc,
  2849. { "Data Flow Control", "dnp3.ctl.dfc",
  2850. FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_CTL_DFC,
  2851. NULL, HFILL }
  2852. },
  2853. { &hf_dnp3_dst,
  2854. { "Destination", "dnp3.dst",
  2855. FT_UINT16, BASE_DEC, NULL, 0x0,
  2856. "Destination Address", HFILL }
  2857. },
  2858. { &hf_dnp3_src,
  2859. { "Source", "dnp3.src",
  2860. FT_UINT16, BASE_DEC, NULL, 0x0,
  2861. "Source Address", HFILL }
  2862. },
  2863. { &hf_dnp_hdr_CRC,
  2864. { "CRC", "dnp3.hdr.CRC",
  2865. FT_UINT16, BASE_HEX, NULL, 0x0,
  2866. NULL, HFILL }
  2867. },
  2868. { &hf_dnp_hdr_CRC_bad,
  2869. { "Bad CRC", "dnp3.hdr.CRC_bad",
  2870. FT_BOOLEAN, BASE_NONE, NULL, 0x0,
  2871. NULL, HFILL }
  2872. },
  2873. { &hf_dnp3_tr_ctl,
  2874. { "Transport Control", "dnp3.tr.ctl",
  2875. FT_UINT8, BASE_HEX, NULL, 0x0,
  2876. "Transport Layer Control Byte", HFILL }
  2877. },
  2878. { &hf_dnp3_tr_fin,
  2879. { "Final", "dnp3.tr.fin",
  2880. FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_TR_FIN,
  2881. NULL, HFILL }
  2882. },
  2883. { &hf_dnp3_tr_fir,
  2884. { "First", "dnp3.tr.fir",
  2885. FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_TR_FIR,
  2886. NULL, HFILL }
  2887. },
  2888. { &hf_dnp3_tr_seq,
  2889. { "Sequence", "dnp3.tr.seq",
  2890. FT_UINT8, BASE_DEC, NULL, DNP3_TR_SEQ,
  2891. "Frame Sequence Number", HFILL }
  2892. },
  2893. { &hf_dnp3_al_ctl,
  2894. { "Application Control", "dnp3.al.ctl",
  2895. FT_UINT8, BASE_HEX, NULL, 0x0,
  2896. "Application Layer Control Byte", HFILL }
  2897. },
  2898. { &hf_dnp3_al_fir,
  2899. { "First", "dnp3.al.fir",
  2900. FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_AL_FIR,
  2901. NULL, HFILL }
  2902. },
  2903. { &hf_dnp3_al_fin,
  2904. { "Final", "dnp3.al.fin",
  2905. FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_AL_FIN,
  2906. NULL, HFILL }
  2907. },
  2908. { &hf_dnp3_al_con,
  2909. { "Confirm", "dnp3.al.con",
  2910. FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_AL_CON,
  2911. NULL, HFILL }
  2912. },
  2913. { &hf_dnp3_al_uns,
  2914. { "Unsolicited", "dnp3.al.uns",
  2915. FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_AL_UNS,
  2916. NULL, HFILL }
  2917. },
  2918. { &hf_dnp3_al_seq,
  2919. { "Sequence", "dnp3.al.seq",
  2920. FT_UINT8, BASE_DEC, NULL, DNP3_AL_SEQ,
  2921. "Frame Sequence Number", HFILL }
  2922. },
  2923. { &hf_dnp3_al_func,
  2924. { "Application Layer Function Code", "dnp3.al.func",
  2925. FT_UINT8, BASE_DEC|BASE_EXT_STRING, &dnp3_al_func_vals_ext, DNP3_AL_FUNC,
  2926. "Application Function Code", HFILL }
  2927. },
  2928. { &hf_dnp3_al_iin,
  2929. { "Application Layer IIN bits", "dnp3.al.iin",
  2930. FT_UINT16, BASE_DEC, NULL, 0x0,
  2931. "Application Layer IIN", HFILL }
  2932. },
  2933. { &hf_dnp3_al_iin_bmsg,
  2934. { "Broadcast Msg Rx", "dnp3.al.iin.bmsg",
  2935. FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_BMSG,
  2936. NULL, HFILL }
  2937. },
  2938. { &hf_dnp3_al_iin_cls1d,
  2939. { "Class 1 Data Available", "dnp3.al.iin.cls1d",
  2940. FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_CLS1D,
  2941. NULL, HFILL }
  2942. },
  2943. { &hf_dnp3_al_iin_cls2d,
  2944. { "Class 2 Data Available", "dnp3.al.iin.cls2d",
  2945. FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_CLS2D,
  2946. NULL, HFILL }
  2947. },
  2948. { &hf_dnp3_al_iin_cls3d,
  2949. { "Class 3 Data Available", "dnp3.al.iin.cls3d",
  2950. FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_CLS3D,
  2951. NULL, HFILL }
  2952. },
  2953. { &hf_dnp3_al_iin_tsr,
  2954. { "Time Sync Required", "dnp3.al.iin.tsr",
  2955. FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_TSR,
  2956. NULL, HFILL }
  2957. },
  2958. { &hf_dnp3_al_iin_dol,
  2959. { "Digital Outputs in Local", "dnp3.al.iin.dol",
  2960. FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_DOL,
  2961. NULL, HFILL }
  2962. },
  2963. { &hf_dnp3_al_iin_dt,
  2964. { "Device Trouble", "dnp3.al.iin.dt",
  2965. FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_DT,
  2966. NULL, HFILL }
  2967. },
  2968. { &hf_dnp3_al_iin_rst,
  2969. { "Device Restart", "dnp3.al.iin.rst",
  2970. FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_RST,
  2971. NULL, HFILL }
  2972. },
  2973. { &hf_dnp3_al_iin_fcni,
  2974. { "Function Code not implemented", "dnp3.al.iin.fcni",
  2975. FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_FCNI,
  2976. NULL, HFILL }
  2977. },
  2978. { &hf_dnp3_al_iin_obju,
  2979. { "Requested Objects Unknown", "dnp3.al.iin.obju",
  2980. FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_OBJU,
  2981. NULL, HFILL }
  2982. },
  2983. { &hf_dnp3_al_iin_pioor,
  2984. { "Parameters Invalid or Out of Range", "dnp3.al.iin.pioor",
  2985. FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_PIOOR,
  2986. NULL, HFILL }
  2987. },
  2988. { &hf_dnp3_al_iin_ebo,
  2989. { "Event Buffer Overflow", "dnp3.al.iin.ebo",
  2990. FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_EBO,
  2991. NULL, HFILL }
  2992. },
  2993. { &hf_dnp3_al_iin_oae,
  2994. { "Operation Already Executing", "dnp3.al.iin.oae",
  2995. FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_OAE,
  2996. NULL, HFILL }
  2997. },
  2998. { &hf_dnp3_al_iin_cc,
  2999. { "Configuration Corrupt", "dnp3.al.iin.cc",
  3000. FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_CC,
  3001. NULL, HFILL }
  3002. },
  3003. { &hf_dnp3_al_obj,
  3004. { "Object", "dnp3.al.obj",
  3005. FT_UINT16, BASE_HEX|BASE_EXT_STRING, &dnp3_al_obj_vals_ext, 0x0,
  3006. "Application Layer Object", HFILL }
  3007. },
  3008. { &hf_dnp3_al_objq_index,
  3009. { "Index Prefix", "dnp3.al.objq.index",
  3010. FT_UINT8, BASE_DEC|BASE_EXT_STRING, &dnp3_al_objq_index_vals_ext, AL_OBJQ_INDEX,
  3011. "Object Index Prefixing", HFILL }
  3012. },
  3013. { &hf_dnp3_al_objq_code,
  3014. { "Qualifier Code", "dnp3.al.objq.code",
  3015. FT_UINT8, BASE_DEC|BASE_EXT_STRING, &dnp3_al_objq_code_vals_ext, AL_OBJQ_CODE,
  3016. "Object Qualifier Code", HFILL }
  3017. },
  3018. { &hf_dnp3_al_range_start8,
  3019. { "Start (8 bit)", "dnp3.al.range.start",
  3020. FT_UINT8, BASE_DEC, NULL, 0x0,
  3021. "Object Start Index", HFILL }
  3022. },
  3023. { &hf_dnp3_al_range_stop8,
  3024. { "Stop (8 bit)", "dnp3.al.range.stop",
  3025. FT_UINT8, BASE_DEC, NULL, 0x0,
  3026. "Object Stop Index", HFILL }
  3027. },
  3028. { &hf_dnp3_al_range_start16,
  3029. { "Start (16 bit)", "dnp3.al.range.start",
  3030. FT_UINT16, BASE_DEC, NULL, 0x0,
  3031. "Object Start Index", HFILL }
  3032. },
  3033. { &hf_dnp3_al_range_stop16,
  3034. { "Stop (16 bit)", "dnp3.al.range.stop",
  3035. FT_UINT16, BASE_DEC, NULL, 0x0,
  3036. "Object Stop Index", HFILL }
  3037. },
  3038. { &hf_dnp3_al_range_start32,
  3039. { "Start (32 bit)", "dnp3.al.range.start",
  3040. FT_UINT32, BASE_DEC, NULL, 0x0,
  3041. "Object Start Index", HFILL }
  3042. },
  3043. { &hf_dnp3_al_range_stop32,
  3044. { "Stop (32 bit)", "dnp3.al.range.stop",
  3045. FT_UINT32, BASE_DEC, NULL, 0x0,
  3046. "Object Stop Index", HFILL }
  3047. },
  3048. { &hf_dnp3_al_range_abs8,
  3049. { "Address (8 bit)", "dnp3.al.range.abs",
  3050. FT_UINT8, BASE_DEC, NULL, 0x0,
  3051. "Object Absolute Address", HFILL }
  3052. },
  3053. { &hf_dnp3_al_range_abs16,
  3054. { "Address (16 bit)", "dnp3.al.range.abs",
  3055. FT_UINT16, BASE_DEC, NULL, 0x0,
  3056. "Object Absolute Address", HFILL }
  3057. },
  3058. { &hf_dnp3_al_range_abs32,
  3059. { "Address (32 bit)", "dnp3.al.range.abs",
  3060. FT_UINT32, BASE_DEC, NULL, 0x0,
  3061. "Object Absolute Address", HFILL }
  3062. },
  3063. { &hf_dnp3_al_range_quant8,
  3064. { "Quantity (8 bit)", "dnp3.al.range.quantity",
  3065. FT_UINT8, BASE_DEC, NULL, 0x0,
  3066. "Object Quantity", HFILL }
  3067. },
  3068. { &hf_dnp3_al_range_quant16,
  3069. { "Quantity (16 bit)", "dnp3.al.range.quantity",
  3070. FT_UINT16, BASE_DEC, NULL, 0x0,
  3071. "Object Quantity", HFILL }
  3072. },
  3073. { &hf_dnp3_al_range_quant32,
  3074. { "Quantity (32 bit)", "dnp3.al.range.quantity",
  3075. FT_UINT32, BASE_DEC, NULL, 0x0,
  3076. "Object Quantity", HFILL }
  3077. },
  3078. { &hf_dnp3_al_index8,
  3079. { "Index (8 bit)", "dnp3.al.index",
  3080. FT_UINT8, BASE_DEC, NULL, 0x0,
  3081. "Object Index", HFILL }
  3082. },
  3083. { &hf_dnp3_al_index16,
  3084. { "Index (16 bit)", "dnp3.al.index",
  3085. FT_UINT16, BASE_DEC, NULL, 0x0,
  3086. "Object Index", HFILL }
  3087. },
  3088. { &hf_dnp3_al_index32,
  3089. { "Index (32 bit)", "dnp3.al.index",
  3090. FT_UINT32, BASE_DEC, NULL, 0x0,
  3091. "Object Index", HFILL }
  3092. },
  3093. #if 0
  3094. { &hf_dnp3_al_ptnum,
  3095. { "Object Point Number", "dnp3.al.ptnum",
  3096. FT_UINT16, BASE_DEC, NULL, 0x0,
  3097. NULL, HFILL }
  3098. },
  3099. #endif
  3100. { &hf_dnp3_al_size8,
  3101. { "Size (8 bit)", "dnp3.al.size",
  3102. FT_UINT8, BASE_DEC, NULL, 0x0,
  3103. "Object Size", HFILL }
  3104. },
  3105. { &hf_dnp3_al_size16,
  3106. { "Size (16 bit)", "dnp3.al.size",
  3107. FT_UINT16, BASE_DEC, NULL, 0x0,
  3108. "Object Size", HFILL }
  3109. },
  3110. { &hf_dnp3_al_size32,
  3111. { "Size (32 bit)", "dnp3.al.size",
  3112. FT_UINT32, BASE_DEC, NULL, 0x0,
  3113. "Object Size", HFILL }
  3114. },
  3115. { &hf_dnp3_al_bit,
  3116. { "Value (bit)", "dnp3.al.bit",
  3117. FT_BOOLEAN, 8, TFS(&tfs_on_off), 0x1,
  3118. "Digital Value (1 bit)", HFILL }
  3119. },
  3120. { &hf_dnp3_al_2bit,
  3121. { "Value (two bit)", "dnp3.al.2bit",
  3122. FT_UINT8, BASE_DEC, NULL, 0x0,
  3123. "Digital Value (2 bit)", HFILL }
  3124. },
  3125. { &hf_dnp3_al_ana16,
  3126. { "Value (16 bit)", "dnp3.al.ana",
  3127. FT_UINT16, BASE_DEC, NULL, 0x0,
  3128. "Analog Value (16 bit)", HFILL }
  3129. },
  3130. { &hf_dnp3_al_ana32,
  3131. { "Value (32 bit)", "dnp3.al.ana",
  3132. FT_UINT32, BASE_DEC, NULL, 0x0,
  3133. "Analog Value (32 bit)", HFILL }
  3134. },
  3135. { &hf_dnp3_al_anaflt,
  3136. { "Value (float)", "dnp3.al.ana",
  3137. FT_FLOAT, BASE_NONE, NULL, 0x0,
  3138. "Analog Value (float)", HFILL }
  3139. },
  3140. { &hf_dnp3_al_anadbl,
  3141. { "Value (double)", "dnp3.al.ana",
  3142. FT_DOUBLE, BASE_NONE, NULL, 0x0,
  3143. "Analog Value (double)", HFILL }
  3144. },
  3145. { &hf_dnp3_al_anaout16,
  3146. { "Output Value (16 bit)", "dnp3.al.anaout",
  3147. FT_UINT16, BASE_DEC, NULL, 0x0,
  3148. NULL, HFILL }
  3149. },
  3150. { &hf_dnp3_al_anaout32,
  3151. { "Output Value (32 bit)", "dnp3.al.anaout",
  3152. FT_UINT32, BASE_DEC, NULL, 0x0,
  3153. NULL, HFILL }
  3154. },
  3155. { &hf_dnp3_al_anaoutflt,
  3156. { "Output Value (float)", "dnp3.al.anaout",
  3157. FT_FLOAT, BASE_NONE, NULL, 0x0,
  3158. NULL, HFILL }
  3159. },
  3160. { &hf_dnp3_al_anaoutdbl,
  3161. { "Output (double)", "dnp3.al.anaout",
  3162. FT_DOUBLE, BASE_NONE, NULL, 0x0,
  3163. "Output Value (double)", HFILL }
  3164. },
  3165. { &hf_dnp3_al_cnt16,
  3166. { "Counter (16 bit)", "dnp3.al.cnt",
  3167. FT_UINT16, BASE_DEC, NULL, 0x0,
  3168. "Counter Value (16 bit)", HFILL }
  3169. },
  3170. { &hf_dnp3_al_cnt32,
  3171. { "Counter (32 bit)", "dnp3.al.cnt",
  3172. FT_UINT32, BASE_DEC, NULL, 0x0,
  3173. "Counter Value (32 bit)", HFILL }
  3174. },
  3175. { &hf_dnp3_al_ctrlstatus,
  3176. { "Control Status", "dnp3.al.ctrlstatus",
  3177. FT_UINT8, BASE_DEC|BASE_EXT_STRING, &dnp3_al_ctl_status_vals_ext, 0xff,
  3178. NULL, HFILL }
  3179. },
  3180. { &hf_dnp3_al_file_mode,
  3181. { "File Control Mode", "dnp3.al.file.mode",
  3182. FT_UINT16, BASE_DEC, VALS(dnp3_al_file_mode_vals), 0x0,
  3183. NULL, HFILL }
  3184. },
  3185. { &hf_dnp3_al_file_auth,
  3186. { "File Authentication Key", "dnp3.al.file.auth",
  3187. FT_UINT32, BASE_HEX, NULL, 0x0,
  3188. NULL, HFILL }
  3189. },
  3190. { &hf_dnp3_al_file_size,
  3191. { "File Size", "dnp3.al.file.size",
  3192. FT_UINT32, BASE_HEX, NULL, 0x0,
  3193. NULL, HFILL }
  3194. },
  3195. { &hf_dnp3_al_file_maxblk,
  3196. { "File Max Block Size", "dnp3.al.file.maxblock",
  3197. FT_UINT16, BASE_DEC, NULL, 0x0,
  3198. NULL, HFILL }
  3199. },
  3200. { &hf_dnp3_al_file_reqID,
  3201. { "File Request Identifier", "dnp3.al.file.reqID",
  3202. FT_UINT16, BASE_DEC, NULL, 0x0,
  3203. NULL, HFILL }
  3204. },
  3205. { &hf_dnp3_al_file_status,
  3206. { "File Control Status", "dnp3.al.file.status",
  3207. FT_UINT8, BASE_DEC|BASE_EXT_STRING, &dnp3_al_file_status_vals_ext, 0x0,
  3208. NULL, HFILL }
  3209. },
  3210. { &hf_dnp3_al_file_handle,
  3211. { "File Handle", "dnp3.al.file.handle",
  3212. FT_UINT32, BASE_HEX, NULL, 0x0,
  3213. NULL, HFILL }
  3214. },
  3215. { &hf_dnp3_al_file_blocknum,
  3216. { "File Block Number", "dnp3.al.file.blocknum",
  3217. FT_UINT32, BASE_HEX, NULL, 0x7fffffff,
  3218. NULL, HFILL }
  3219. },
  3220. { &hf_dnp3_al_file_lastblock,
  3221. { "File Last Block", "dnp3.al.file.lastblock",
  3222. FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x80000000,
  3223. NULL, HFILL }
  3224. },
  3225. { &hf_dnp3_al_file_data,
  3226. { "File Data", "dnp3.al.file.data",
  3227. FT_BYTES, BASE_NONE, NULL, 0x0,
  3228. NULL, HFILL }
  3229. },
  3230. { &hf_dnp3_al_biq_b0,
  3231. { "Online", "dnp3.al.biq.b0",
  3232. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG0,
  3233. NULL, HFILL }
  3234. },
  3235. { &hf_dnp3_al_biq_b1,
  3236. { "Restart", "dnp3.al.biq.b1",
  3237. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG1,
  3238. NULL, HFILL }
  3239. },
  3240. { &hf_dnp3_al_biq_b2,
  3241. { "Comm Fail", "dnp3.al.biq.b2",
  3242. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG2,
  3243. NULL, HFILL }
  3244. },
  3245. { &hf_dnp3_al_biq_b3,
  3246. { "Remote Force", "dnp3.al.biq.b3",
  3247. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG3,
  3248. NULL, HFILL }
  3249. },
  3250. { &hf_dnp3_al_biq_b4,
  3251. { "Local Force", "dnp3.al.biq.b4",
  3252. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG4,
  3253. NULL, HFILL }
  3254. },
  3255. { &hf_dnp3_al_biq_b5,
  3256. { "Chatter Filter", "dnp3.al.biq.b5",
  3257. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG5,
  3258. NULL, HFILL }
  3259. },
  3260. { &hf_dnp3_al_biq_b6,
  3261. { "Reserved", "dnp3.al.biq.b6",
  3262. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG6,
  3263. NULL, HFILL }
  3264. },
  3265. { &hf_dnp3_al_biq_b7,
  3266. { "Point Value", "dnp3.al.biq.b7",
  3267. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG7,
  3268. NULL, HFILL }
  3269. },
  3270. { &hf_dnp3_al_boq_b0,
  3271. { "Online", "dnp3.al.boq.b0",
  3272. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG0,
  3273. NULL, HFILL }
  3274. },
  3275. { &hf_dnp3_al_boq_b1,
  3276. { "Restart", "dnp3.al.boq.b1",
  3277. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG1,
  3278. NULL, HFILL }
  3279. },
  3280. { &hf_dnp3_al_boq_b2,
  3281. { "Comm Fail", "dnp3.al.boq.b2",
  3282. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG2,
  3283. NULL, HFILL }
  3284. },
  3285. { &hf_dnp3_al_boq_b3,
  3286. { "Remote Force", "dnp3.al.boq.b3",
  3287. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG3,
  3288. NULL, HFILL }
  3289. },
  3290. { &hf_dnp3_al_boq_b4,
  3291. { "Local Force", "dnp3.al.boq.b4",
  3292. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG4,
  3293. NULL, HFILL }
  3294. },
  3295. { &hf_dnp3_al_boq_b5,
  3296. { "Reserved", "dnp3.al.boq.b5",
  3297. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG5,
  3298. NULL, HFILL }
  3299. },
  3300. { &hf_dnp3_al_boq_b6,
  3301. { "Reserved", "dnp3.al.boq.b6",
  3302. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG6,
  3303. NULL, HFILL }
  3304. },
  3305. { &hf_dnp3_al_boq_b7,
  3306. { "Point Value", "dnp3.al.boq.b7",
  3307. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG7,
  3308. NULL, HFILL }
  3309. },
  3310. { &hf_dnp3_al_ctrq_b0,
  3311. { "Online", "dnp3.al.ctrq.b0",
  3312. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG0,
  3313. NULL, HFILL }
  3314. },
  3315. { &hf_dnp3_al_ctrq_b1,
  3316. { "Restart", "dnp3.al.ctrq.b1",
  3317. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG1,
  3318. NULL, HFILL }
  3319. },
  3320. { &hf_dnp3_al_ctrq_b2,
  3321. { "Comm Fail", "dnp3.al.ctrq.b2",
  3322. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG2,
  3323. NULL, HFILL }
  3324. },
  3325. { &hf_dnp3_al_ctrq_b3,
  3326. { "Remote Force", "dnp3.al.ctrq.b3",
  3327. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG3,
  3328. NULL, HFILL }
  3329. },
  3330. { &hf_dnp3_al_ctrq_b4,
  3331. { "Local Force", "dnp3.al.ctrq.b4",
  3332. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG4,
  3333. NULL, HFILL }
  3334. },
  3335. { &hf_dnp3_al_ctrq_b5,
  3336. { "Roll-Over", "dnp3.al.ctrq.b5",
  3337. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG5,
  3338. NULL, HFILL }
  3339. },
  3340. { &hf_dnp3_al_ctrq_b6,
  3341. { "Discontinuity", "dnp3.al.ctrq.b6",
  3342. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG6,
  3343. NULL, HFILL }
  3344. },
  3345. { &hf_dnp3_al_ctrq_b7,
  3346. { "Reserved", "dnp3.al.ctrq.b7",
  3347. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG7,
  3348. NULL, HFILL }
  3349. },
  3350. { &hf_dnp3_al_aiq_b0,
  3351. { "Online", "dnp3.al.aiq.b0",
  3352. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG0,
  3353. NULL, HFILL }
  3354. },
  3355. { &hf_dnp3_al_aiq_b1,
  3356. { "Restart", "dnp3.al.aiq.b1",
  3357. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG1,
  3358. NULL, HFILL }
  3359. },
  3360. { &hf_dnp3_al_aiq_b2,
  3361. { "Comm Fail", "dnp3.al.aiq.b2",
  3362. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG2,
  3363. NULL, HFILL }
  3364. },
  3365. { &hf_dnp3_al_aiq_b3,
  3366. { "Remote Force", "dnp3.al.aiq.b3",
  3367. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG3,
  3368. NULL, HFILL }
  3369. },
  3370. { &hf_dnp3_al_aiq_b4,
  3371. { "Local Force", "dnp3.al.aiq.b4",
  3372. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG4,
  3373. NULL, HFILL }
  3374. },
  3375. { &hf_dnp3_al_aiq_b5,
  3376. { "Over-Range", "dnp3.al.aiq.b5",
  3377. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG5,
  3378. NULL, HFILL }
  3379. },
  3380. { &hf_dnp3_al_aiq_b6,
  3381. { "Reference Check", "dnp3.al.aiq.b6",
  3382. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG6,
  3383. NULL, HFILL }
  3384. },
  3385. { &hf_dnp3_al_aiq_b7,
  3386. { "Reserved", "dnp3.al.aiq.b7",
  3387. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG7,
  3388. NULL, HFILL }
  3389. },
  3390. { &hf_dnp3_al_aoq_b0,
  3391. { "Online", "dnp3.al.aoq.b0",
  3392. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG0,
  3393. NULL, HFILL }
  3394. },
  3395. { &hf_dnp3_al_aoq_b1,
  3396. { "Restart", "dnp3.al.aoq.b1",
  3397. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG1,
  3398. NULL, HFILL }
  3399. },
  3400. { &hf_dnp3_al_aoq_b2,
  3401. { "Comm Fail", "dnp3.al.aoq.b2",
  3402. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG2,
  3403. NULL, HFILL }
  3404. },
  3405. { &hf_dnp3_al_aoq_b3,
  3406. { "Remote Force", "dnp3.al.aoq.b3",
  3407. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG3,
  3408. NULL, HFILL }
  3409. },
  3410. { &hf_dnp3_al_aoq_b4,
  3411. { "Local Force", "dnp3.al.aoq.b4",
  3412. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG4,
  3413. NULL, HFILL }
  3414. },
  3415. { &hf_dnp3_al_aoq_b5,
  3416. { "Reserved", "dnp3.al.aoq.b5",
  3417. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG5,
  3418. NULL, HFILL }
  3419. },
  3420. { &hf_dnp3_al_aoq_b6,
  3421. { "Reserved", "dnp3.al.aoq.b6",
  3422. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG6,
  3423. NULL, HFILL }
  3424. },
  3425. { &hf_dnp3_al_aoq_b7,
  3426. { "Reserved", "dnp3.al.aoq.b7",
  3427. FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG7,
  3428. NULL, HFILL }
  3429. },
  3430. { &hf_dnp3_al_timestamp,
  3431. { "Timestamp", "dnp3.al.timestamp",
  3432. FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0,
  3433. "Object Timestamp", HFILL }
  3434. },
  3435. { &hf_dnp3_al_file_perms,
  3436. { "Permissions", "dnp3.al.file.perms",
  3437. FT_UINT16, BASE_OCT, NULL, 0x0,
  3438. NULL, HFILL }
  3439. },
  3440. { &hf_dnp3_al_file_perms_read_owner,
  3441. { "Read permission for owner", "dnp3.al.file.perms.read_owner",
  3442. FT_BOOLEAN, 16, TFS(&tfs_yes_no), 0400,
  3443. NULL, HFILL }
  3444. },
  3445. { &hf_dnp3_al_file_perms_write_owner,
  3446. { "Write permission for owner", "dnp3.al.file.perms.write_owner",
  3447. FT_BOOLEAN, 16, TFS(&tfs_yes_no), 0200,
  3448. NULL, HFILL }
  3449. },
  3450. { &hf_dnp3_al_file_perms_exec_owner,
  3451. { "Execute permission for owner", "dnp3.al.file.perms.exec_owner",
  3452. FT_BOOLEAN, 16, TFS(&tfs_yes_no), 0100,
  3453. NULL, HFILL }
  3454. },
  3455. { &hf_dnp3_al_file_perms_read_group,
  3456. { "Read permission for group", "dnp3.al.file.perms.read_group",
  3457. FT_BOOLEAN, 16, TFS(&tfs_yes_no), 040,
  3458. NULL, HFILL }
  3459. },
  3460. { &hf_dnp3_al_file_perms_write_group,
  3461. { "Write permission for group", "dnp3.al.file.perms.write_group",
  3462. FT_BOOLEAN, 16, TFS(&tfs_yes_no), 020,
  3463. NULL, HFILL }
  3464. },
  3465. { &hf_dnp3_al_file_perms_exec_group,
  3466. { "Execute permission for group", "dnp3.al.file.perms.exec_group",
  3467. FT_BOOLEAN, 16, TFS(&tfs_yes_no), 010,
  3468. NULL, HFILL }
  3469. },
  3470. { &hf_dnp3_al_file_perms_read_world,
  3471. { "Read permission for world", "dnp3.al.file.perms.read_world",
  3472. FT_BOOLEAN, 16, TFS(&tfs_yes_no), 04,
  3473. NULL, HFILL }
  3474. },
  3475. { &hf_dnp3_al_file_perms_write_world,
  3476. { "Write permission for world", "dnp3.al.file.perms.write_world",
  3477. FT_BOOLEAN, 16, TFS(&tfs_yes_no), 02,
  3478. NULL, HFILL }
  3479. },
  3480. { &hf_dnp3_al_file_perms_exec_world,
  3481. { "Execute permission for world", "dnp3.al.file.perms.exec_world",
  3482. FT_BOOLEAN, 16, TFS(&tfs_yes_no), 01,
  3483. NULL, HFILL }
  3484. },
  3485. { &hf_dnp3_al_rel_timestamp,
  3486. { "Relative Timestamp", "dnp3.al.reltimestamp",
  3487. FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
  3488. "Object Relative Timestamp", HFILL }
  3489. },
  3490. { &hf_dnp3_fragment,
  3491. { "DNP 3.0 AL Fragment", "dnp3.al.fragment",
  3492. FT_FRAMENUM, BASE_NONE, NULL, 0x0,
  3493. "DNP 3.0 Application Layer Fragment", HFILL }
  3494. },
  3495. { &hf_dnp3_fragments,
  3496. { "DNP 3.0 AL Fragments", "dnp3.al.fragments",
  3497. FT_NONE, BASE_NONE, NULL, 0x0,
  3498. "DNP 3.0 Application Layer Fragments", HFILL }
  3499. },
  3500. { &hf_dnp3_fragment_overlap,
  3501. { "Fragment overlap", "dnp3.al.fragment.overlap",
  3502. FT_BOOLEAN, BASE_NONE, NULL, 0x0,
  3503. "Fragment overlaps with other fragments", HFILL }
  3504. },
  3505. { &hf_dnp3_fragment_overlap_conflict,
  3506. { "Conflicting data in fragment overlap", "dnp3.al.fragment.overlap.conflict",
  3507. FT_BOOLEAN, BASE_NONE, NULL, 0x0,
  3508. "Overlapping fragments contained conflicting data", HFILL }
  3509. },
  3510. { &hf_dnp3_fragment_multiple_tails,
  3511. { "Multiple tail fragments found", "dnp3.al.fragment.multipletails",
  3512. FT_BOOLEAN, BASE_NONE, NULL, 0x0,
  3513. "Several tails were found when defragmenting the packet", HFILL }
  3514. },
  3515. { &hf_dnp3_fragment_too_long_fragment,
  3516. { "Fragment too long", "dnp3.al.fragment.toolongfragment",
  3517. FT_BOOLEAN, BASE_NONE, NULL, 0x0,
  3518. "Fragment contained data past end of packet", HFILL }
  3519. },
  3520. { &hf_dnp3_fragment_error,
  3521. { "Defragmentation error", "dnp3.al.fragment.error",
  3522. FT_FRAMENUM, BASE_NONE, NULL, 0x0,
  3523. "Defragmentation error due to illegal fragments", HFILL }
  3524. },
  3525. { &hf_dnp3_fragment_count,
  3526. { "Fragment count", "dnp3.al.fragment.count",
  3527. FT_UINT32, BASE_DEC, NULL, 0x0,
  3528. NULL, HFILL }
  3529. },
  3530. { &hf_dnp3_fragment_reassembled_in,
  3531. { "Reassembled PDU In Frame", "dnp3.al.fragment.reassembled_in",
  3532. FT_FRAMENUM, BASE_NONE, NULL, 0x0,
  3533. "This PDU is reassembled in this frame", HFILL }
  3534. },
  3535. { &hf_dnp3_fragment_reassembled_length,
  3536. { "Reassembled DNP length", "dnp3.al.fragment.reassembled.length",
  3537. FT_UINT32, BASE_DEC, NULL, 0x0,
  3538. "The total length of the reassembled payload", HFILL }
  3539. }
  3540. };
  3541. /* Setup protocol subtree array */
  3542. static gint *ett[] = {
  3543. &ett_dnp3,
  3544. &ett_dnp3_dl,
  3545. &ett_dnp3_dl_ctl,
  3546. &ett_dnp3_tr_ctl,
  3547. &ett_dnp3_al_data,
  3548. &ett_dnp3_al,
  3549. &ett_dnp3_al_ctl,
  3550. &ett_dnp3_al_obj_point_tcc,
  3551. &ett_dnp3_al_iin,
  3552. &ett_dnp3_al_obj,
  3553. &ett_dnp3_al_obj_qualifier,
  3554. &ett_dnp3_al_obj_range,
  3555. &ett_dnp3_al_objdet,
  3556. &ett_dnp3_al_obj_quality,
  3557. &ett_dnp3_al_obj_point,
  3558. &ett_dnp3_al_obj_point_perms,
  3559. &ett_dnp3_fragment,
  3560. &ett_dnp3_fragments
  3561. };
  3562. static ei_register_info ei[] = {
  3563. { &ei_dnp_num_items_neg, { "dnp3.num_items_neg", PI_MALFORMED, PI_ERROR, "Negative number of items", EXPFILL }},
  3564. { &ei_dnp_invalid_length, { "dnp3.invalid_length", PI_MALFORMED, PI_ERROR, "Invalid length", EXPFILL }},
  3565. };
  3566. module_t *dnp3_module;
  3567. expert_module_t* expert_dnp3;
  3568. /* Register protocol init routine */
  3569. register_init_routine(&dnp3_init);
  3570. /* Register the protocol name and description */
  3571. proto_dnp3 = proto_register_protocol("Distributed Network Protocol 3.0",
  3572. "DNP 3.0", "dnp3");
  3573. /* Register the dissector so it may be used as a User DLT payload protocol */
  3574. new_register_dissector("dnp3.udp", dissect_dnp3_udp, proto_dnp3);
  3575. /* Required function calls to register the header fields and subtrees used */
  3576. proto_register_field_array(proto_dnp3, hf, array_length(hf));
  3577. proto_register_subtree_array(ett, array_length(ett));
  3578. expert_dnp3 = expert_register_protocol(proto_dnp3);
  3579. expert_register_field_array(expert_dnp3, ei, array_length(ei));
  3580. dnp3_module = prefs_register_protocol(proto_dnp3, NULL);
  3581. prefs_register_bool_preference(dnp3_module, "heuristics",
  3582. "Try to detect DNP 3 heuristically",
  3583. "Whether the DNP3 dissector should try to find DNP 3 packets heuristically.",
  3584. &dnp3_heuristics);
  3585. prefs_register_bool_preference(dnp3_module, "desegment",
  3586. "Reassemble DNP3 messages spanning multiple TCP segments",
  3587. "Whether the DNP3 dissector should reassemble messages spanning multiple TCP segments."
  3588. " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
  3589. &dnp3_desegment);
  3590. }
  3591. void
  3592. proto_reg_handoff_dnp3(void)
  3593. {
  3594. dissector_handle_t dnp3_tcp_handle;
  3595. dissector_handle_t dnp3_udp_handle;
  3596. /* register as heuristic dissector for both TCP and UDP */
  3597. if (dnp3_heuristics) {
  3598. heur_dissector_add("tcp", dissect_dnp3_tcp, proto_dnp3);
  3599. heur_dissector_add("udp", dissect_dnp3_udp, proto_dnp3);
  3600. } else {
  3601. heur_dissector_delete("tcp", dissect_dnp3_tcp, proto_dnp3);
  3602. heur_dissector_delete("udp", dissect_dnp3_udp, proto_dnp3);
  3603. }
  3604. dnp3_tcp_handle = new_create_dissector_handle(dissect_dnp3_tcp, proto_dnp3);
  3605. dnp3_udp_handle = new_create_dissector_handle(dissect_dnp3_udp, proto_dnp3);
  3606. dissector_add_uint("tcp.port", TCP_PORT_DNP, dnp3_tcp_handle);
  3607. dissector_add_uint("udp.port", UDP_PORT_DNP, dnp3_udp_handle);
  3608. }
  3609. /*
  3610. * Editor modelines
  3611. *
  3612. * Local Variables:
  3613. * c-basic-offset: 2
  3614. * tab-width: 8
  3615. * indent-tabs-mode: nil
  3616. * End:
  3617. *
  3618. * ex: set shiftwidth=2 tabstop=8 expandtab:
  3619. * :indentSize=2:tabSize=8:noTabs=true:
  3620. */