aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors
diff options
context:
space:
mode:
authorGraham Bloice <graham.bloice@trihedral.com>2007-01-31 13:58:55 +0000
committerGraham Bloice <graham.bloice@trihedral.com>2007-01-31 13:58:55 +0000
commit773a04c9e4dde384979d80272c54b5d4e5f9ba62 (patch)
tree0a1a7aac6f5bfcad4eeae502f3f242dae5de1418 /epan/dissectors
parenta9c08b914e727af8244f60653aa82ec59e110524 (diff)
Major upgrades to dissector: Added defragmentation of tcp pdus, fixed defragmention of application layer fragments, many more object types decoded thanks to Chris Bontje
svn path=/trunk/; revision=20651
Diffstat (limited to 'epan/dissectors')
-rw-r--r--epan/dissectors/packet-dnp.c1513
1 files changed, 943 insertions, 570 deletions
diff --git a/epan/dissectors/packet-dnp.c b/epan/dissectors/packet-dnp.c
index fc29ee2db2..6811bbda21 100644
--- a/epan/dissectors/packet-dnp.c
+++ b/epan/dissectors/packet-dnp.c
@@ -1,10 +1,12 @@
-/* packet-dnp3.c
+/* packet-dnp.c
* Routines for DNP dissection
- * Copyright 2003, Graham Bloice <graham.bloice@trihedral.com>
+ * Copyright 2003, 2006, 2007, Graham Bloice <graham.bloice@trihedral.com>
*
* DNP3.0 Application Layer Object dissection added by Chris Bontje (chrisbontje@shaw.ca)
* Copyright 2005
*
+ * Major updates: tcp and application layer defragmentation, more object dissections by Graham Bloice
+ *
* $Id$
*
* Wireshark - Network traffic analyzer
@@ -40,6 +42,9 @@
#include <epan/packet.h>
#include <epan/prefs.h>
#include <epan/reassemble.h>
+#include <epan/emem.h>
+#include <epan/dissectors/packet-tcp.h>
+#include <epan/conversation.h>
/*
* See
@@ -54,7 +59,7 @@
*
* Application Layer Decoding based on information available in
* DNP3 Basic 4 Documentation Set, specifically the document:
- * "DNP V3.00 Application Layer" v0.03 P009-0PD.APP
+ * "DNP V3.00 Application Layer" v0.03 P009-0PD.APP & Technical Bulletins
*/
/***************************************************************************/
@@ -215,6 +220,14 @@
#define AL_OBJ_BIC_TIME 0x0202 /* 02 02 Binary Input Change With Time */
#define AL_OBJ_BIC_RTIME 0x0203 /* 02 03 Binary Input Change With Relative Time */
+/* Double-bit Input Objects */
+#define AL_OBJ_2BI_ALL 0x0300 /* 03 00 Double-bit Input All Variations */
+#define AL_OBJ_2BI_NF 0x0301 /* 03 01 Double-bit Input No Flags */
+#define AL_OBJ_2BI_STAT 0x0302 /* 03 02 Double-bit Input With Status */
+#define AL_OBJ_2BIC_NOTIME 0x0401 /* 04 01 Double-bit Input Change Without Time */
+#define AL_OBJ_2BIC_TIME 0x0402 /* 04 02 Double-bit Input Change With Time */
+#define AL_OBJ_2BIC_RTIME 0x0403 /* 04 03 Double-bit Input Change With Relative Time */
+
/* Binary Input Quality Flags */
#define AL_OBJ_BI_FLAG0 0x0001 /* Point Online (0=Offline; 1=Online) */
#define AL_OBJ_BI_FLAG1 0x0002 /* Restart (0=Normal; 1=Restart) */
@@ -222,8 +235,8 @@
#define AL_OBJ_BI_FLAG3 0x0008 /* Remote Force (0=Normal; 1=Forced) */
#define AL_OBJ_BI_FLAG4 0x0010 /* Local Force (0=Normal; 1=Forced) */
#define AL_OBJ_BI_FLAG5 0x0020 /* Chatter Filter (0=Normal; 1=Filter On) */
-#define AL_OBJ_BI_FLAG6 0x0040 /* Reserved */
-#define AL_OBJ_BI_FLAG7 0x0080 /* Point State (0=Off; 1=On) */
+#define AL_OBJ_BI_FLAG6 0x0040 /* Double-bit LSB (0=Off; 1=On) */
+#define AL_OBJ_BI_FLAG7 0x0080 /* Point State (0=Off; 1=On) or Double-bit MSB */
/***************************************************************************/
/* Binary Output Objects */
@@ -258,6 +271,10 @@
#define AL_OBJCTL_STAT4 0x04 /* Control Operation Not Supported for this point */
#define AL_OBJCTL_STAT5 0x05 /* Request Not Accepted; Ctrl Queue full or pt. active */
#define AL_OBJCTL_STAT6 0x06 /* Request Not Accepted; Ctrl HW Problems */
+#define AL_OBJCTL_STAT7 0x07 /* Request Not Accepted; Local/Remote switch in Local*/
+#define AL_OBJCTL_STAT8 0x08 /* Request Not Accepted; Too many operations requested */
+#define AL_OBJCTL_STAT9 0x09 /* Request Not Accepted; Insufficient authorization */
+#define AL_OBJCTL_STAT10 0x0A /* Request Not Accepted; Local automation proc active */
/* Binary Output Quality Flags */
#define AL_OBJ_BO_FLAG0 0x0001 /* Point Online (0=Offline; 1=Online) */
@@ -312,7 +329,7 @@
#define AL_OBJ_CTR_FLAG3 0x0008 /* Remote Force (0=Normal; 1=Forced) */
#define AL_OBJ_CTR_FLAG4 0x0010 /* Local Force (0=Normal; 1=Forced) */
#define AL_OBJ_CTR_FLAG5 0x0020 /* Roll-over (0=Normal; 1=Roll-Over) */
-#define AL_OBJ_CTR_FLAG6 0x0040 /* Reserved */
+#define AL_OBJ_CTR_FLAG6 0x0040 /* Discontinuity (0=Normal; 1=Discontinuity) */
#define AL_OBJ_CTR_FLAG7 0x0080 /* Reserved */
/***************************************************************************/
@@ -322,21 +339,34 @@
#define AL_OBJ_AI_16 0x1E02 /* 30 02 16-Bit Analog Input */
#define AL_OBJ_AI_32NF 0x1E03 /* 30 03 32-Bit Analog Input Without Flag */
#define AL_OBJ_AI_16NF 0x1E04 /* 30 04 16-Bit Analog Input Without Flag */
+#define AL_OBJ_AI_FLT 0x1E05 /* 30 05 32-Bit Floating Point Input */
+#define AL_OBJ_AI_DBL 0x1E06 /* 30 06 64-Bit Floating Point Input */
/* 0x1F01 31 01 32-Bit Frozen Analog Input */
/* 0x1F02 31 02 16-Bit Frozen Analog Input */
/* 0x1F03 31 03 32-Bit Frozen Analog Input w/ Time of Freeze */
/* 0x1F04 31 04 16-Bit Frozen Analog Input w/ Time of Freeze */
/* 0x1F05 31 05 32-Bit Frozen Analog Input Without Flag */
/* 0x1F06 31 06 16-Bit Frozen Analog Input Without Flag */
+#define AL_OBJ_AIF_FLT 0x1F07 /* 31 07 32-Bit Frozen Floating Point Input */
+#define AL_OBJ_AIF_DBL 0x1F08 /* 31 08 64-Bit Frozen Floating Point Input */
#define AL_OBJ_AIC_ALL 0x2000 /* 32 00 Analog Input Change All Variations */
#define AL_OBJ_AIC_32NT 0x2001 /* 32 01 32-Bit Analog Change Event w/o Time */
#define AL_OBJ_AIC_16NT 0x2002 /* 32 02 16-Bit Analog Change Event w/o Time */
#define AL_OBJ_AIC_32T 0x2003 /* 32 03 32-Bit Analog Change Event w/ Time */
#define AL_OBJ_AIC_16T 0x2004 /* 32 04 16-Bit Analog Change Event w/ Time */
+#define AL_OBJ_AIC_FLTNT 0x2005 /* 32 05 32-Bit Floating Point Change Event w/o Time*/
+#define AL_OBJ_AIC_DBLNT 0x2006 /* 32 06 64-Bit Floating Point Change Event w/o Time*/
+#define AL_OBJ_AIC_FLTT 0x2007 /* 32 07 32-Bit Floating Point Change Event w/ Time*/
+#define AL_OBJ_AIC_DBLT 0x2008 /* 32 08 64-Bit Floating Point Change Event w/ Time*/
/* 0x2101 33 01 32-Bit Frozen Analog Event w/o Time */
/* 0x2102 33 02 16-Bit Frozen Analog Event w/o Time */
/* 0x2103 33 03 32-Bit Frozen Analog Event w/ Time */
/* 0x2104 33 04 16-Bit Frozen Analog Event w/ Time */
+#define AL_OBJ_AIFC_FLTNT 0x2105 /* 33 05 32-Bit Floating Point Frozen Change Event w/o Time*/
+#define AL_OBJ_AIFC_DBLNT 0x2106 /* 33 06 64-Bit Floating Point Frozen Change Event w/o Time*/
+#define AL_OBJ_AIFC_FLTT 0x2107 /* 33 07 32-Bit Floating Point Frozen Change Event w/ Time*/
+#define AL_OBJ_AIFC_DBLT 0x2108 /* 33 08 64-Bit Floating Point Frozen Change Event w/ Time*/
+
/* Analog Input Quality Flags */
#define AL_OBJ_AI_FLAG0 0x0001 /* Point Online (0=Offline; 1=Online) */
@@ -352,15 +382,19 @@
/* Analog Output Objects */
#define AL_OBJ_AO_32 0x2801 /* 40 01 32-Bit Analog Output Status */
#define AL_OBJ_AO_16 0x2802 /* 40 02 16-Bit Analog Output Status */
+#define AL_OBJ_AO_FLT 0x2803 /* 40 03 32-Bit Floating Point Output Status */
+#define AL_OBJ_AO_DBL 0x2804 /* 40 04 64-Bit Floating Point Output Status */
#define AL_OBJ_AO_32OPB 0x2901 /* 41 01 32-Bit Analog Output Block */
#define AL_OBJ_AO_16OPB 0x2902 /* 41 02 16-Bit Analog Output Block */
+#define AL_OBJ_AO_FLTOPB 0x2903 /* 41 03 32-Bit Floating Point Output Block */
+#define AL_OBJ_AO_DBLOPB 0x2904 /* 41 04 64-Bit Floating Point Output Block */
/* Analog Output Quality Flags */
#define AL_OBJ_AO_FLAG0 0x0001 /* Point Online (0=Offline; 1=Online) */
#define AL_OBJ_AO_FLAG1 0x0002 /* Restart (0=Normal; 1=Restart) */
#define AL_OBJ_AO_FLAG2 0x0004 /* Comms Lost (0=Normal; 1=Lost) */
#define AL_OBJ_AO_FLAG3 0x0008 /* Remote Force (0=Normal; 1=Forced) */
-#define AL_OBJ_AO_FLAG4 0x0010 /* Reserved */
+#define AL_OBJ_AO_FLAG4 0x0010 /* Local Force (0=Normal; 1=Forced) */
#define AL_OBJ_AO_FLAG5 0x0020 /* Reserved */
#define AL_OBJ_AO_FLAG6 0x0040 /* Reserved */
#define AL_OBJ_AO_FLAG7 0x0080 /* Reserved */
@@ -445,6 +479,10 @@ static int hf_dnp3_al_range_abs32 = -1;
static int hf_dnp3_al_range_quant8 = -1;
static int hf_dnp3_al_range_quant16 = -1;
static int hf_dnp3_al_range_quant32 = -1;
+static int hf_dnp3_al_index8 = -1;
+static int hf_dnp3_al_index16 = -1;
+static int hf_dnp3_al_index32 = -1;
+
/*static int hf_dnp3_al_objq = -1;
static int hf_dnp3_al_nobj = -1; */
static int hf_dnp3_al_ptnum = -1;
@@ -488,18 +526,21 @@ static int hf_dnp3_al_aoq_b4 = -1;
static int hf_dnp3_al_aoq_b5 = -1;
static int hf_dnp3_al_aoq_b6 = -1;
static int hf_dnp3_al_aoq_b7 = -1;
-
-/* ************************************************************************* */
-/* Header values for reassembly */
-/* ************************************************************************* */
-static int hf_fragments = -1;
-static int hf_fragment = -1;
-static int hf_fragment_overlap = -1;
-static int hf_fragment_overlap_conflict = -1;
-static int hf_fragment_multiple_tails = -1;
-static int hf_fragment_too_long_fragment = -1;
-static int hf_fragment_error = -1;
-static int hf_fragment_reassembled_in = -1;
+static int hf_dnp3_al_timestamp = -1;
+static int hf_dnp3_al_rel_timestamp = -1;
+static int hf_dnp3_al_ana16 = -1;
+static int hf_dnp3_al_ana32 = -1;
+static int hf_dnp3_al_anaflt = -1;
+static int hf_dnp3_al_anadbl = -1;
+static int hf_dnp3_al_bit = -1;
+static int hf_dnp3_al_2bit = -1;
+static int hf_dnp3_al_cnt16 = -1;
+static int hf_dnp3_al_cnt32 = -1;
+static int hf_dnp3_al_ctrlstatus = -1;
+static int hf_dnp3_al_anaout16 = -1;
+static int hf_dnp3_al_anaout32 = -1;
+static int hf_dnp3_al_anaoutflt = -1;
+static int hf_dnp3_al_anaoutdbl = -1;
/***************************************************************************/
/* Value String Look-Ups */
@@ -638,6 +679,12 @@ static const value_string dnp3_al_obj_vals[] = {
{ AL_OBJ_BIC_NOTIME, "Binary Input Change Without Time (Obj:02, Var:01)" },
{ AL_OBJ_BIC_TIME, "Binary Input Change With Time (Obj:02, Var:02)" },
{ AL_OBJ_BIC_RTIME, "Binary Input Change With Relative Time (Obj:02, Var:03)" },
+ { AL_OBJ_2BI_ALL, "Double-bit Input All Variations (Obj:03, Var:All)" },
+ { AL_OBJ_2BI_NF, "Double-bit Input No Flags (Obj:03, Var:01)" },
+ { AL_OBJ_2BI_STAT, "Double-bit Input With Status (Obj:03, Var:02)" },
+ { AL_OBJ_2BIC_NOTIME, "Double-bit Input Change Without Time (Obj:04, Var:01)" },
+ { AL_OBJ_2BIC_TIME, "Double-bit Input Change With Time (Obj:04, Var:02)" },
+ { AL_OBJ_2BIC_RTIME, "Double-bit Input Change With Relative Time (Obj:04, Var:03)" },
{ AL_OBJ_BO, "Binary Output (Obj:10, Var:01)" },
{ AL_OBJ_BO_STAT, "Binary Output Status (Obj:10, Var:02)" },
{ AL_OBJ_CTLOP_BLK, "Control Relay Output Block (Obj:12, Var:01)" },
@@ -656,13 +703,33 @@ static const value_string dnp3_al_obj_vals[] = {
{ AL_OBJ_AI_16, "16-Bit Analog Input (Obj:30, Var:02)" },
{ AL_OBJ_AI_32NF, "32-Bit Analog Input Without Flag (Obj:30, Var:03)" },
{ AL_OBJ_AI_16NF, "16-Bit Analog Input Without Flag (Obj:30, Var:04)" },
+ { AL_OBJ_AI_FLT, "32-Bit Floating Point Input (Obj:30, Var:05)" },
+ { AL_OBJ_AI_DBL, "64-Bit Floating Point Input (Obj:30, Var:06)" },
+ { AL_OBJ_AIF_FLT, "32-Bit Frozen Floating Point Input (Obj:31, Var:07)" },
+ { AL_OBJ_AIF_DBL, "64-Bit Frozen Floating Point Input (Obj:31, Var:08)" },
{ AL_OBJ_AIC_ALL, "Analog Input Change All Variations (Obj:32, Var:All)" },
{ AL_OBJ_AIC_32NT, "32-Bit Analog Change Event w/o Time (Obj:32, Var:01)" },
{ AL_OBJ_AIC_16NT, "16-Bit Analog Change Event w/o Time (Obj:32, Var:02)" },
{ AL_OBJ_AIC_32T, "32-Bit Analog Change Event with Time (Obj:32, Var:03)" },
{ AL_OBJ_AIC_16T, "16-Bit Analog Change Event with Time (Obj:32, Var:04)" },
- { AL_OBJ_AO_16, "16-Bit Analog Output Status (Obj:40, Var:02)"},
+ { AL_OBJ_AIC_FLTNT, "32-Bit Floating Point Change Event w/o Time (Obj:32, Var:05)" },
+ { AL_OBJ_AIC_DBLNT, "64-Bit Floating Point Change Event w/o Time (Obj:32, Var:06)" },
+ { AL_OBJ_AIC_FLTT, "32-Bit Floating Point Change Event w/ Time (Obj:32, Var:07)" },
+ { AL_OBJ_AIC_DBLT, "64-Bit Floating Point Change Event w/ Time (Obj:32, Var:08)" },
+ { AL_OBJ_AIFC_FLTNT, "32-Bit Floating Point Frozen Change Event w/o Time (Obj:33, Var:05)" },
+ { AL_OBJ_AIFC_DBLNT, "64-Bit Floating Point Frozen Change Event w/o Time (Obj:33, Var:06)" },
+ { AL_OBJ_AIFC_FLTT, "32-Bit Floating Point Frozen Change Event w/ Time (Obj:33, Var:07)" },
+ { AL_OBJ_AIFC_DBLT, "64-Bit Floating Point Frozen Change Event w/ Time (Obj:33, Var:08)" },
+ { AL_OBJ_AO_32, "32-Bit Analog Output Status (Obj:40, Var:01)" },
+ { AL_OBJ_AO_16, "16-Bit Analog Output Status (Obj:40, Var:02)" },
+ { AL_OBJ_AO_FLT, "32-Bit Floating Point Output Status (Obj:40, Var:03)" },
+ { AL_OBJ_AO_DBL, "64-Bit Floating Point Output Status (Obj:40, Var:04)" },
+ { AL_OBJ_AO_32OPB, "32-Bit Analog Output Block (Obj:41, Var:01)" },
+ { AL_OBJ_AO_16OPB, "16-Bit Analog Output Block (Obj:41, Var:02)" },
+ { AL_OBJ_AO_FLTOPB, "32-Bit Floating Point Output Block (Obj:41, Var:03)" },
+ { AL_OBJ_AO_DBLOPB, "64-Bit Floating Point Output Block (Obj:41, Var:04)" },
{ AL_OBJ_TD, "Time and Date (Obj:50, Var:01)" },
+ { AL_OBJ_TDCTO, "Time and Date CTO (Obj:51, Var:01)" },
{ AL_OBJ_TDELAYF, "Time Delay - Fine (Obj:52, Var:02)" },
{ AL_OBJ_CLASS0, "Class 0 Data (Obj:60, Var:01)" },
{ AL_OBJ_CLASS1, "Class 1 Data (Obj:60, Var:02)" },
@@ -706,6 +773,10 @@ static const value_string dnp3_al_ctl_status_vals[] = {
{ AL_OBJCTL_STAT4, "Ctl Oper. Not Supported For This Point" },
{ AL_OBJCTL_STAT5, "Req. Not Accepted; Ctrl Queue Full/Point Active" },
{ AL_OBJCTL_STAT6, "Req. Not Accepted; Ctrl Hardware Problems" },
+ { AL_OBJCTL_STAT7, "Req. Not Accepted; Local/Remote switch in Local" },
+ { AL_OBJCTL_STAT8, "Req. Not Accepted; Too many operations" },
+ { AL_OBJCTL_STAT9, "Req. Not Accepted; Insufficient authorization" },
+ { AL_OBJCTL_STAT10, "Req. Not Accepted; Local automation proc active" },
{ 0, NULL }
};
@@ -728,6 +799,7 @@ static const value_string dnp3_al_ctrflag_vals[] = {
{ AL_OBJ_CTR_FLAG3, "Remote Forced" },
{ AL_OBJ_CTR_FLAG4, "Locally Forced" },
{ AL_OBJ_CTR_FLAG5, "Roll-Over" },
+ { AL_OBJ_CTR_FLAG6, "Discontinuity" },
{ 0, NULL }
};
@@ -751,8 +823,7 @@ static gint ett_dnp3_tr_ctl = -1;
static gint ett_dnp3_al_data = -1;
static gint ett_dnp3_al = -1;
static gint ett_dnp3_al_ctl = -1;
-static gint ett_fragment = -1;
-static gint ett_fragments = -1;
+
/* Added for Application Layer Decoding */
static gint ett_dnp3_al_iin = -1;
static gint ett_dnp3_al_obj = -1;
@@ -760,25 +831,58 @@ static gint ett_dnp3_al_obj_qualifier = -1;
static gint ett_dnp3_al_obj_range = -1;
static gint ett_dnp3_al_objdet = -1;
static gint ett_dnp3_al_obj_quality = -1;
+static gint ett_dnp3_al_obj_point = -1;
/* Tables for reassembly of fragments. */
static GHashTable *al_fragment_table = NULL;
static GHashTable *al_reassembled_table = NULL;
-static const fragment_items frag_items = {
- &ett_fragment,
- &ett_fragments,
- &hf_fragments,
- &hf_fragment,
- &hf_fragment_overlap,
- &hf_fragment_overlap_conflict,
- &hf_fragment_multiple_tails,
- &hf_fragment_too_long_fragment,
- &hf_fragment_error,
- &hf_fragment_reassembled_in,
- "fragments"
+/* ************************************************************************* */
+/* Header values for reassembly */
+/* ************************************************************************* */
+static int hf_dnp3_fragment = -1;
+static int hf_dnp3_fragments = -1;
+static int hf_dnp3_fragment_overlap = -1;
+static int hf_dnp3_fragment_overlap_conflict = -1;
+static int hf_dnp3_fragment_multiple_tails = -1;
+static int hf_dnp3_fragment_too_long_fragment = -1;
+static int hf_dnp3_fragment_error = -1;
+static int hf_dnp3_fragment_reassembled_in = -1;
+static gint ett_dnp3_fragment = -1;
+static gint ett_dnp3_fragments = -1;
+
+static const fragment_items dnp3_frag_items = {
+ &ett_dnp3_fragment,
+ &ett_dnp3_fragments,
+ &hf_dnp3_fragments,
+ &hf_dnp3_fragment,
+ &hf_dnp3_fragment_overlap,
+ &hf_dnp3_fragment_overlap_conflict,
+ &hf_dnp3_fragment_multiple_tails,
+ &hf_dnp3_fragment_too_long_fragment,
+ &hf_dnp3_fragment_error,
+ &hf_dnp3_fragment_reassembled_in,
+ "DNP 3.0 fragments"
};
+/* Conversation stuff, used for tracking application message fragments */
+/* the number of entries in the memory chunk array */
+#define dnp3_conv_init_count 50
+
+/* define your structure here */
+typedef struct {
+ guint conv_seq_number;
+} dnp3_conv_t;
+
+/* the GMemChunk base structure */
+static GMemChunk *dnp3_conv_vals = NULL;
+
+/* The conversation sequence number */
+static guint seq_number = 0;
+
+/* desegmentation of DNP3 over TCP */
+static gboolean dnp3_desegment = TRUE;
+
/*****************************************************************/
/* */
/* CRC LOOKUP TABLE */
@@ -910,65 +1014,84 @@ dnp3_al_process_iin(tvbuff_t *tvb, int offset, proto_tree *al_tree)
}
/*****************************************************************/
-/* Function to determine Application Layer Object Index size */
+/* Function to determine Application Layer Object Index size and */
+/* Point address. */
/*****************************************************************/
static int
-dnp3_al_obj_procindex(tvbuff_t *tvb, int bitindex, int offset, guint8 al_objq_index, guint32 *al_ptaddr)
+dnp3_al_obj_procindex(tvbuff_t *tvb, int offset, guint8 al_objq_index, guint32 *al_ptaddr, proto_tree *item_tree)
{
int indexbytes = 0;
+ proto_item *index_item;
switch (al_objq_index)
{
case AL_OBJQL_IDX_NI: /* No Index */
- if (bitindex > 0) /* Increment Address by 1 */
- {
- *al_ptaddr += 1;
- }
- indexbytes = 0;
- break;
+ indexbytes = 0;
+ index_item = proto_tree_add_text(item_tree, tvb, offset, 0, "Point Index: %d", *al_ptaddr);
+ PROTO_ITEM_SET_GENERATED(index_item);
+ break;
case AL_OBJQL_IDX_1O:
- *al_ptaddr = tvb_get_guint8(tvb, offset);
- indexbytes = 1;
- break;
+ *al_ptaddr = tvb_get_guint8(tvb, offset);
+ proto_tree_add_item(item_tree, hf_dnp3_al_index8, tvb, offset, 1, TRUE);
+ indexbytes = 1;
+ break;
case AL_OBJQL_IDX_2O:
- *al_ptaddr = tvb_get_letohs(tvb, offset);
- indexbytes = 2;
- break;
+ *al_ptaddr = tvb_get_letohs(tvb, offset);
+ proto_tree_add_item(item_tree, hf_dnp3_al_index16, tvb, offset, 2, TRUE);
+ indexbytes = 2;
+ break;
case AL_OBJQL_IDX_4O:
- *al_ptaddr = tvb_get_letohl(tvb, offset);
- indexbytes = 4;
- break;
+ *al_ptaddr = tvb_get_letohl(tvb, offset);
+ proto_tree_add_item(item_tree, hf_dnp3_al_index32, tvb, offset, 4, TRUE);
+ indexbytes = 4;
+ break;
}
return indexbytes;
}
/*****************************************************************/
+/* Function to add the same string to two separate tree items */
+/*****************************************************************/
+static void
+dnp3_append_2item_text(proto_item *item1, proto_item *item2, const gchar *text)
+{
+ proto_item_append_text(item1, text);
+ proto_item_append_text(item2, text);
+}
+
+/*****************************************************************/
/* Function to Determine Application Layer Point Quality Flags & */
-/* add Point Quality Flag Sub-Tree */
+/* add Point Quality Flag Sub-Tree */
/*****************************************************************/
static void
-dnp3_al_obj_quality(tvbuff_t *tvb, int offset, guint8 al_ptflags, proto_item *t_point, int type)
+dnp3_al_obj_quality(tvbuff_t *tvb, int offset, guint8 al_ptflags, proto_tree *point_tree, proto_item *point_item, int type)
{
proto_tree *quality_tree = NULL;
+ proto_item *quality_item;
int hf0 = 0, hf1 = 0, hf2 = 0, hf3 = 0, hf4 = 0, hf5 = 0, hf6 = 0, hf7 = 0;
- proto_item_append_text(t_point, "(Quality: ");
+ /* Common code */
+ proto_item_append_text(point_item, " (Quality: ");
+ if ((0 <= type) && (type <= 4)) {
+ quality_item = proto_tree_add_text(point_tree, tvb, offset, 1, "Quality: ");
+ quality_tree = proto_item_add_subtree(quality_item, ett_dnp3_al_obj_quality);
+
+ if (al_ptflags & AL_OBJ_BI_FLAG0) {
+ dnp3_append_2item_text(point_item, quality_item, "Online");
+ }
+ else {
+ dnp3_append_2item_text(point_item, quality_item, "Offline");
+ }
+ if (al_ptflags & AL_OBJ_BI_FLAG1) dnp3_append_2item_text(point_item, quality_item, ", Restart");
+ if (al_ptflags & AL_OBJ_BI_FLAG2) dnp3_append_2item_text(point_item, quality_item, ", Comm Fail");
+ if (al_ptflags & AL_OBJ_BI_FLAG3) dnp3_append_2item_text(point_item, quality_item, ", Remote Force");
+ if (al_ptflags & AL_OBJ_BI_FLAG4) dnp3_append_2item_text(point_item, quality_item, ", Local Force");
+ }
+
switch (type) {
case 0: /* Binary Input Quality flags */
- quality_tree = proto_item_add_subtree(t_point, ett_dnp3_al_obj_quality);
-
- if (al_ptflags & AL_OBJ_BI_FLAG0) {
- proto_item_append_text(t_point, "Online");
- }
- else {
- proto_item_append_text(t_point, "Offline");
- }
- if (al_ptflags & AL_OBJ_BI_FLAG1) proto_item_append_text(t_point, ", Restart");
- if (al_ptflags & AL_OBJ_BI_FLAG2) proto_item_append_text(t_point, ", Comm Fail");
- if (al_ptflags & AL_OBJ_BI_FLAG3) proto_item_append_text(t_point, ", Remote Force");
- if (al_ptflags & AL_OBJ_BI_FLAG4) proto_item_append_text(t_point, ", Local Force");
- if (al_ptflags & AL_OBJ_BI_FLAG5) proto_item_append_text(t_point, ", Chatter Filter");
+ if (al_ptflags & AL_OBJ_BI_FLAG5) dnp3_append_2item_text(point_item, quality_item, ", Chatter Filter");
hf0 = hf_dnp3_al_biq_b0;
hf1 = hf_dnp3_al_biq_b1;
@@ -981,19 +1104,6 @@ dnp3_al_obj_quality(tvbuff_t *tvb, int offset, guint8 al_ptflags, proto_item *t_
break;
case 1: /* Binary Output Quality flags */
- quality_tree = proto_item_add_subtree(t_point, ett_dnp3_al_obj_quality);
-
- if (al_ptflags & AL_OBJ_BO_FLAG0) {
- proto_item_append_text(t_point, "Online");
- }
- else {
- proto_item_append_text(t_point, "Offline");
- }
- if (al_ptflags & AL_OBJ_BO_FLAG1) proto_item_append_text(t_point, ", Restart");
- if (al_ptflags & AL_OBJ_BO_FLAG2) proto_item_append_text(t_point, ", Comm Fail");
- if (al_ptflags & AL_OBJ_BO_FLAG3) proto_item_append_text(t_point, ", Remote Force");
- if (al_ptflags & AL_OBJ_BO_FLAG4) proto_item_append_text(t_point, ", Local Force");
-
hf0 = hf_dnp3_al_boq_b0;
hf1 = hf_dnp3_al_boq_b1;
hf2 = hf_dnp3_al_boq_b2;
@@ -1005,19 +1115,8 @@ dnp3_al_obj_quality(tvbuff_t *tvb, int offset, guint8 al_ptflags, proto_item *t_
break;
case 2: /* Counter Quality flags */
- quality_tree = proto_item_add_subtree(t_point, ett_dnp3_al_obj_quality);
-
- if (al_ptflags & AL_OBJ_CTR_FLAG0) {
- proto_item_append_text(t_point, "Online");
- }
- else {
- proto_item_append_text(t_point, "Offline");
- }
- if (al_ptflags & AL_OBJ_CTR_FLAG1) proto_item_append_text(t_point, ", Restart");
- if (al_ptflags & AL_OBJ_CTR_FLAG2) proto_item_append_text(t_point, ", Comm Fail");
- if (al_ptflags & AL_OBJ_CTR_FLAG3) proto_item_append_text(t_point, ", Remote Force");
- if (al_ptflags & AL_OBJ_CTR_FLAG4) proto_item_append_text(t_point, ", Local Force");
- if (al_ptflags & AL_OBJ_CTR_FLAG5) proto_item_append_text(t_point, ", Roll-over");
+ if (al_ptflags & AL_OBJ_CTR_FLAG5) dnp3_append_2item_text(point_item, quality_item, ", Roll-over");
+ if (al_ptflags & AL_OBJ_CTR_FLAG6) dnp3_append_2item_text(point_item, quality_item, ", Discontinuity");
hf0 = hf_dnp3_al_ctrq_b0;
hf1 = hf_dnp3_al_ctrq_b1;
@@ -1030,20 +1129,8 @@ dnp3_al_obj_quality(tvbuff_t *tvb, int offset, guint8 al_ptflags, proto_item *t_
break;
case 3: /* Analog Input Quality flags */
- quality_tree = proto_item_add_subtree(t_point, ett_dnp3_al_obj_quality);
-
- if (al_ptflags & AL_OBJ_AI_FLAG0) {
- proto_item_append_text(t_point, "Online");
- }
- else {
- proto_item_append_text(t_point, "Offline");
- }
- if (al_ptflags & AL_OBJ_AI_FLAG1) proto_item_append_text(t_point, ", Restart");
- if (al_ptflags & AL_OBJ_AI_FLAG2) proto_item_append_text(t_point, ", Comm Fail");
- if (al_ptflags & AL_OBJ_AI_FLAG3) proto_item_append_text(t_point, ", Remote Force");
- if (al_ptflags & AL_OBJ_AI_FLAG4) proto_item_append_text(t_point, ", Local Force");
- if (al_ptflags & AL_OBJ_AI_FLAG5) proto_item_append_text(t_point, ", Over-Range");
- if (al_ptflags & AL_OBJ_AI_FLAG6) proto_item_append_text(t_point, ", Reference Check");
+ if (al_ptflags & AL_OBJ_AI_FLAG5) dnp3_append_2item_text(point_item, quality_item, ", Over-Range");
+ if (al_ptflags & AL_OBJ_AI_FLAG6) dnp3_append_2item_text(point_item, quality_item, ", Reference Check");
hf0 = hf_dnp3_al_aiq_b0;
hf1 = hf_dnp3_al_aiq_b1;
@@ -1056,18 +1143,6 @@ dnp3_al_obj_quality(tvbuff_t *tvb, int offset, guint8 al_ptflags, proto_item *t_
break;
case 4: /* Analog Output Quality flags */
- quality_tree = proto_item_add_subtree(t_point, ett_dnp3_al_obj_quality);
-
- if (al_ptflags & AL_OBJ_AO_FLAG0) {
- proto_item_append_text(t_point, "Online");
- }
- else {
- proto_item_append_text(t_point, "Offline");
- }
- if (al_ptflags & AL_OBJ_AO_FLAG1) proto_item_append_text(t_point, ", Restart");
- if (al_ptflags & AL_OBJ_AO_FLAG2) proto_item_append_text(t_point, ", Comm Fail");
- if (al_ptflags & AL_OBJ_AO_FLAG3) proto_item_append_text(t_point, ", Remote Force");
-
hf0 = hf_dnp3_al_aoq_b0;
hf1 = hf_dnp3_al_aoq_b1;
hf2 = hf_dnp3_al_aoq_b2;
@@ -1089,46 +1164,33 @@ dnp3_al_obj_quality(tvbuff_t *tvb, int offset, guint8 al_ptflags, proto_item *t_
proto_tree_add_item(quality_tree, hf1, tvb, offset, 1, TRUE);
proto_tree_add_item(quality_tree, hf0, tvb, offset, 1, TRUE);
}
- proto_item_append_text(t_point, ")");
+ proto_item_append_text(point_item, ")");
}
/**********************************************************************/
-/* Function to Decode Timestamp From DNP3 Message */
+/* Function to convert DNP3 timestamp to nstime_t value */
/**********************************************************************/
/* 48-bit Time Format */
/* MSB FF EE DD CC BB AA LSB */
/* ffffffff eeeeeeee dddddddd cccccccc bbbbbbbb aaaaaaaa */
/* 47 40 39 32 31 24 23 16 15 8 7 0 */
-/* Final hex no. should be: 0xAABBCCDDEEFF */
-/* Epoch time + ms. dd:mm:yyyy hh:mm:ss.iii */
+/* */
+/* Value is ms since 00:00 on 1/1/1970 */
/**********************************************************************/
-static char *
-dnp3_al_decode_timestamp(tvbuff_t *tvb, int temp_pos, char* buff)
+static void
+dnp3_al_get_timestamp(nstime_t *timestamp, tvbuff_t *tvb, int temp_pos)
{
guint32 hi, lo;
- guint64 al_timestamp, time_ms;
- time_t alts_noms;
- struct tm *ptm;
+ guint64 time_ms;
lo = tvb_get_letohs(tvb, temp_pos);
hi = tvb_get_letohl(tvb, temp_pos + 2);
- al_timestamp = ((gint64)hi * 0x10000 + lo);
-
- time_ms = al_timestamp % 1000; /* Determine ms from timestamp) */
- al_timestamp = al_timestamp / 1000; /* Divide 1000 from raw timestamp to remove ms */
- alts_noms = (const long) al_timestamp;
- ptm = gmtime(&alts_noms);
-
- /*g_snprintf(buff, 25,"%02d/%02d/%4d %02d:%02d:%02d.%03d",(ptm->tm_mon + 1), ptm->tm_mday,
- (ptm->tm_year+1900), ptm->tm_hour, ptm->tm_min, ptm->tm_sec, time_ms); */
- /* Time-stamp in ISO format - perhaps an option should be added for different locales? */
- g_snprintf(buff, 25,"%04d/%02d/%02d %02d:%02d:%02d.%03"PRIu64,(ptm->tm_year+1900),ptm->tm_mday,
- (ptm->tm_mon + 1), ptm->tm_hour, ptm->tm_min, ptm->tm_sec, time_ms);
-
- return buff;
+ time_ms = (guint64)hi * 0x10000 + lo;
+ timestamp->secs = (long)(time_ms / 1000);
+ timestamp->nsecs = (long)(time_ms % 1000) * 1000000;
}
/*****************************************************************/
@@ -1136,38 +1198,42 @@ dnp3_al_decode_timestamp(tvbuff_t *tvb, int temp_pos, char* buff)
/* Returns: New offset pointer into tvb */
/*****************************************************************/
static int
-dnp3_al_process_object(tvbuff_t *tvb, int offset, proto_tree *robj_tree)
+dnp3_al_process_object(tvbuff_t *tvb, int offset, proto_tree *robj_tree, gboolean header_only)
{
- guint8 al_objq, al_objq_index, al_objq_code, al_ptflags, al_ctlobj_code,
+ guint8 al_2bit, al_objq, al_objq_index, al_objq_code, al_ptflags, al_ctlobj_code,
al_ctlobj_code_c, al_ctlobj_code_m, al_ctlobj_code_tc, al_ctlobj_count, al_bi_val, bitindex=0;
- guint16 al_obj, temp16=0, al_val16=0, al_ctlobj_stat;
- guint32 al_val32, num_items=0, al_ptaddr=0, al_ctlobj_on, al_ctlobj_off;
+ guint16 al_obj, al_val16=0, al_ctlobj_stat, al_relms;
+ guint32 item_num, al_val32, num_items=0, al_ptaddr=0, al_ctlobj_on, al_ctlobj_off;
+ nstime_t al_cto, al_reltime, al_abstime;
gboolean al_bit;
guint temp_pos;
- int rangebytes=0, indexbytes=0;
- proto_item *t_objdet = NULL, *t_point = NULL, *qualifier_item = NULL, *range_item = NULL;
- proto_tree *objdet_tree = NULL, *qualifier_tree, *range_tree;
+ gfloat al_valflt;
+ gdouble al_valdbl;
+ int orig_offset, rangebytes=0, indexbytes=0;
+ proto_item *object_item = NULL, *point_item = NULL, *qualifier_item = NULL, *range_item = NULL;
+ proto_tree *object_tree = NULL, *point_tree, *qualifier_tree, *range_tree;
const gchar *ctl_code_str, *ctl_misc_str, *ctl_tc_str, *ctl_status_str;
- gchar buff[25];
+
+ orig_offset = offset;
/* Application Layer Objects in this Message */
al_obj = tvb_get_ntohs(tvb, offset);
/* Create Data Objects Detail Tree */
- t_objdet = proto_tree_add_uint_format(robj_tree, hf_dnp3_al_obj, tvb, offset, 2, al_obj,
+ object_item = proto_tree_add_uint_format(robj_tree, hf_dnp3_al_obj, tvb, offset, 2, al_obj,
"Object(s): %s (0x%04x)", val_to_str(al_obj, dnp3_al_obj_vals, "Unknown Object - Abort Decoding..."), al_obj);
- objdet_tree = proto_item_add_subtree(t_objdet, ett_dnp3_al_obj);
+ object_tree = proto_item_add_subtree(object_item, ett_dnp3_al_obj);
offset += 2;
/* Object Qualifier */
al_objq = tvb_get_guint8(tvb, offset);
al_objq_index = al_objq & AL_OBJQ_INDEX;
- al_objq_index = al_objq_index >> 4; /* bit-shift to the right by 4 (x111xxxx -> xxxxx111) */
+ al_objq_index = al_objq_index >> 4;
al_objq_code = al_objq & AL_OBJQ_CODE;
- qualifier_item = proto_tree_add_text(objdet_tree, tvb, offset, 1, "Qualifier Field, Prefix: %s, Code: %s",
+ qualifier_item = proto_tree_add_text(object_tree, tvb, offset, 1, "Qualifier Field, Prefix: %s, Code: %s",
val_to_str(al_objq_index, dnp3_al_objq_index_vals, "Unknown Index Type"),
val_to_str(al_objq_code, dnp3_al_objq_code_vals, "Unknown Code Type"));
qualifier_tree = proto_item_add_subtree(qualifier_item, ett_dnp3_al_obj_qualifier);
@@ -1177,7 +1243,7 @@ dnp3_al_process_object(tvbuff_t *tvb, int offset, proto_tree *robj_tree)
offset += 1;
/* Create (possibly synthesized) number of items and range field tree */
- range_item = proto_tree_add_text(objdet_tree, tvb, offset, 0, "Number of Items: ");
+ range_item = proto_tree_add_text(object_tree, tvb, offset, 0, "Number of Items: ");
range_tree = proto_item_add_subtree(range_item, ett_dnp3_al_obj_range);
switch (al_objq_code)
@@ -1246,374 +1312,540 @@ dnp3_al_process_object(tvbuff_t *tvb, int offset, proto_tree *robj_tree)
proto_item_set_len(range_item, rangebytes);
break;
}
+ if (num_items)
+ proto_item_append_text(object_item, ", %d points", num_items);
proto_item_append_text(range_item, "%d", num_items);
offset += rangebytes;
- bitindex = 0; /* Temp variable for cycling through points when object values are encoded into
- bits; primarily objects 0x0101 & 0x1001 */
+ if (!header_only) {
+ bitindex = 0; /* Temp variable for cycling through points when object values are encoded into
+ bits; primarily objects 0x0101, 0x0301 & 0x1001 */
- for (temp16 = 0; temp16 < num_items; temp16++)
- {
- switch (al_obj)
+ for (item_num = 0; item_num < num_items; item_num++)
{
+ /* Create Point item and Process Index */
+ point_item = proto_tree_add_text(object_tree, tvb, offset, -1, "Point Number");
+ point_tree = proto_item_add_subtree(point_item, ett_dnp3_al_obj_point);
- case AL_OBJ_BI_ALL: /* Binary Input All Var (Obj:01, Var:All) */
- case AL_OBJ_BIC_ALL: /* Binary Input Change All Var (Obj:02, Var:All) */
- case AL_OBJ_CTR_ALL: /* Binary Counter All Var (Obj:20, Var:All) */
- case AL_OBJ_CTRC_ALL: /* Binary Counter Change All Var (Obj:22 Var:All) */
- case AL_OBJ_AI_ALL: /* Analog Input All Var (Obj:30, Var:All) */
- case AL_OBJ_AIC_ALL: /* Analog Input Change All Var (Obj:32 Var:All) */
+ temp_pos = offset;
+ indexbytes = dnp3_al_obj_procindex(tvb, offset, al_objq_index, &al_ptaddr, point_tree);
+ proto_item_append_text(point_item, " %d", al_ptaddr);
+ temp_pos += indexbytes;
- indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
- offset += indexbytes;
- break;
+ switch (al_obj)
+ {
- case AL_OBJ_BI_1BIT: /* Single-Bit Binary Input (Obj:01, Var:01) */
- case AL_OBJ_BO: /* Binary Output (Obj:10, Var:01) */
+ case AL_OBJ_BI_ALL: /* Binary Input All Var (Obj:01, Var:All) */
+ case AL_OBJ_BIC_ALL: /* Binary Input Change All Var (Obj:02, Var:All) */
+ case AL_OBJ_2BI_ALL: /* Double-bit Input All Var (Obj:03, Var:All) */
+ case AL_OBJ_CTR_ALL: /* Binary Counter All Var (Obj:20, Var:All) */
+ case AL_OBJ_CTRC_ALL: /* Binary Counter Change All Var (Obj:22 Var:All) */
+ case AL_OBJ_AI_ALL: /* Analog Input All Var (Obj:30, Var:All) */
+ case AL_OBJ_AIC_ALL: /* Analog Input Change All Var (Obj:32 Var:All) */
- if (bitindex <= 7)
- {
+ offset += indexbytes;
+ break;
+
+ case AL_OBJ_BI_1BIT: /* Single-Bit Binary Input (Obj:01, Var:01) */
+ case AL_OBJ_BO: /* Binary Output (Obj:10, Var:01) */
+
+ /* Reset bit index if we've gone onto the next byte */
+ if (bitindex > 7)
+ {
+ bitindex = 0;
+ offset += 1;
+ }
+
+ /* Extract the bit from the packed byte */
al_bi_val = tvb_get_guint8(tvb, offset);
- }
- else /* bitindex > 7 */
- {
- offset += 1;
+ al_bit = (al_bi_val & (1 << bitindex)) > 0;
+
+ proto_item_append_text(point_item, ", Value: %d", al_bit);
+ proto_tree_add_boolean(point_tree, hf_dnp3_al_bit, tvb, offset, 1, al_bit);
+ proto_item_set_len(point_item, indexbytes + 1);
+
+ /* If we've read the last item, then move the offset past this byte */
+ if (item_num == (num_items-1))
+ {
+ offset += 1;
+ }
+
+ break;
+
+ case AL_OBJ_2BI_NF: /* Double-bit Input No Flags (Obj:03, Var:01) */
+
+ if (bitindex > 3)
+ {
+ bitindex = 0;
+ offset += 1;
+ }
+
+ /* Extract the Double-bit from the packed byte */
al_bi_val = tvb_get_guint8(tvb, offset);
- bitindex = 0;
- }
+ al_2bit = ((al_bi_val >> (bitindex << 1)) & 3);
+
+ proto_item_append_text(point_item, ", Value: %d", al_2bit);
+ proto_tree_add_uint(point_tree, hf_dnp3_al_2bit, tvb, offset, 1, al_2bit);
+ proto_item_set_len(point_item, indexbytes + 1);
- /* Extract the bit from the packed byte */
- al_bit = (al_bi_val & (1 << bitindex)) > 0;
+ /* If we've read the last item, then move the offset past this byte */
+ if (item_num == (num_items-1))
+ {
+ offset += 1;
+ }
- proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, 1, al_ptaddr,
- "Point Number %d, Value: %d", al_ptaddr, al_bit);
+ break;
- al_ptaddr += 1;
- if (temp16 == (num_items-1))
- {
+ case AL_OBJ_BI_STAT: /* Binary Input With Status (Obj:01, Var:02) */
+ case AL_OBJ_BIC_NOTIME: /* Binary Input Change Without Time (Obj:02, Var:01) */
+ case AL_OBJ_BO_STAT: /* Binary Output Status (Obj:10, Var:02) */
+
+ /* Get Point Flags */
+ al_ptflags = tvb_get_guint8(tvb, offset);
+ al_bit = (al_ptflags & AL_OBJ_BI_FLAG7) > 0;
+
+ switch (al_obj) {
+ case AL_OBJ_BI_STAT:
+ case AL_OBJ_BIC_NOTIME:
+ dnp3_al_obj_quality(tvb, offset, al_ptflags, point_tree, point_item, 0);
+ proto_item_append_text(point_item, ", Value: %d", al_bit);
+ proto_item_set_len(point_item, indexbytes + 1);
+ break;
+ case AL_OBJ_BO_STAT:
+ dnp3_al_obj_quality(tvb, offset, al_ptflags, point_tree, point_item, 1);
+ proto_item_append_text(point_item, ", Value: %d", al_bit);
+ proto_item_set_len(point_item, indexbytes + 1);
+ break;
+ }
+
offset += 1;
- }
+ break;
- break;
+ case AL_OBJ_2BI_STAT: /* Double-bit Input With Status (Obj:03, Var:02) */
+ case AL_OBJ_2BIC_NOTIME: /* Double-bit Input Change Without Time (Obj:04, Var:01) */
- case AL_OBJ_BI_STAT: /* Binary Input With Status (Obj:01, Var:02) */
- case AL_OBJ_BO_STAT: /* Binary Output Status (Obj:10, Var:02) */
-
- /* Get Point Flags */
- al_ptflags = tvb_get_guint8(tvb, offset);
- al_bit = (al_ptflags & AL_OBJ_BI_FLAG7) > 0;
-
- switch (al_obj) {
- case AL_OBJ_BI_STAT:
- t_point = proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, 1, al_ptaddr,
- "Point Number %d ", al_ptaddr);
- dnp3_al_obj_quality(tvb, offset, al_ptflags, t_point, 0);
- proto_item_append_text(t_point, ", Value: %d", al_bit);
- break;
- case AL_OBJ_BO_STAT:
- t_point = proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, 1, al_ptaddr,
- "Point Number %d ", al_ptaddr);
- dnp3_al_obj_quality(tvb, offset, al_ptflags, t_point, 1);
- proto_item_append_text(t_point, ", Value: %d", al_bit);
- break;
- }
+ /* Get Point Flags */
+ al_ptflags = tvb_get_guint8(tvb, offset);
+ al_2bit = (al_ptflags >> 6) & 3;
- al_ptaddr += 1;
- offset += 1;
- break;
+ dnp3_al_obj_quality(tvb, offset, al_ptflags, point_tree, point_item, 0);
+ proto_item_append_text(point_item, ", Value: %d", al_2bit);
+ proto_item_set_len(point_item, indexbytes + 1);
- case AL_OBJ_BIC_TIME: /* Binary Input Change w/ Time (Obj:02, Var:02) */
+ offset += 1;
+ break;
- temp_pos = offset;
- indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
- temp_pos += indexbytes;
+ case AL_OBJ_BIC_TIME: /* Binary Input Change w/ Time (Obj:02, Var:02) */
- /* Get Point Flags */
- al_ptflags = tvb_get_guint8(tvb, temp_pos);
- temp_pos += 1;
+ /* Get Point Flags */
+ al_ptflags = tvb_get_guint8(tvb, temp_pos);
+ temp_pos += 1;
- al_bit = (al_ptflags & AL_OBJ_BI_FLAG7) >> 7; /* bit shift 1xxxxxxx -> xxxxxxx1 */
+ al_bit = (al_ptflags & AL_OBJ_BI_FLAG7) >> 7; /* bit shift 1xxxxxxx -> xxxxxxx1 */
- t_point = proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, (indexbytes + 7), al_ptaddr,
- "Point Number %d ", al_ptaddr);
- dnp3_al_obj_quality(tvb, (offset+indexbytes), al_ptflags, t_point, 0);
- proto_item_append_text(t_point, ", Value: %d, Timestamp: %s", al_bit, dnp3_al_decode_timestamp(tvb, temp_pos, buff));
+ /* Get timestamp */
+ dnp3_al_get_timestamp(&al_abstime, tvb, temp_pos);
- offset += (indexbytes + 7);
+ dnp3_al_obj_quality(tvb, (offset+indexbytes), al_ptflags, point_tree, point_item, 0);
+ proto_item_append_text(point_item, ", Value: %d, Timestamp: %s", al_bit, abs_time_to_str(&al_abstime));
+ proto_tree_add_time(point_tree, hf_dnp3_al_timestamp, tvb, temp_pos, 6, &al_abstime);
+ proto_item_set_len(point_item, indexbytes + 7);
- break;
+ offset += (indexbytes + 7);
- case AL_OBJ_CTLOP_BLK: /* Control Relay Output Block (Obj:12, Var:01) */
+ break;
- /* Process Index */
- temp_pos = offset;
- indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
- temp_pos += indexbytes;
+ case AL_OBJ_2BIC_TIME: /* Double-bit Input Change w/ Time (Obj:04, Var:02) */
- al_ctlobj_code = tvb_get_guint8(tvb, temp_pos);
- temp_pos += 1;
+ /* Get Point Flags */
+ al_ptflags = tvb_get_guint8(tvb, temp_pos);
+ temp_pos += 1;
- /* Bit-Mask xxxx1111 for Control Code 'Code' */
- al_ctlobj_code_c = al_ctlobj_code & AL_OBJCTLC_CODE;
- ctl_code_str = val_to_str(al_ctlobj_code_c, dnp3_al_ctlc_code_vals, "Ctrl Code Invalid (0x%02x)");
+ al_2bit = (al_ptflags >> 6) & 3; /* bit shift 11xxxxxx -> 00000011 */
- /* Bit-Mask xx11xxxx for Control Code Misc Values */
- al_ctlobj_code_m = al_ctlobj_code & AL_OBJCTLC_MISC;
- ctl_misc_str = val_to_str(al_ctlobj_code_m, dnp3_al_ctlc_misc_vals, "");
+ /* Get timestamp */
+ dnp3_al_get_timestamp(&al_abstime, tvb, temp_pos);
- /* Bit-Mask 11xxxxxx for Control Code 'Trip/Close' */
- al_ctlobj_code_tc = al_ctlobj_code & AL_OBJCTLC_TC;
- ctl_tc_str = val_to_str(al_ctlobj_code_tc, dnp3_al_ctlc_tc_vals, "");
+ dnp3_al_obj_quality(tvb, (offset+indexbytes), al_ptflags, point_tree, point_item, 0);
+ proto_item_append_text(point_item, ", Value: %d, Timestamp: %s", al_bit, abs_time_to_str(&al_abstime));
+ proto_tree_add_time(point_tree, hf_dnp3_al_timestamp, tvb, temp_pos, 6, &al_abstime);
+ proto_item_set_len(point_item, indexbytes + 7);
- /* Get "Count" Field */
- al_ctlobj_count = tvb_get_guint8(tvb, temp_pos);
- temp_pos += 1;
+ offset += (indexbytes + 7);
- /* Get "On Time" Field */
- al_ctlobj_on = tvb_get_letohl(tvb, temp_pos);
- temp_pos += 4;
+ break;
- /* Get "Off Time" Field */
- al_ctlobj_off = tvb_get_letohl(tvb, temp_pos);
- temp_pos += 4;
+ case AL_OBJ_BIC_RTIME: /* Binary Input Change w/ Relative Time (Obj:02, Var:03) */
- al_ctlobj_stat = tvb_get_guint8(tvb, temp_pos);
- ctl_status_str = val_to_str(al_ctlobj_stat, dnp3_al_ctl_status_vals, "Invalid Status (0x%02x)");
+ /* Get Point Flags */
+ al_ptflags = tvb_get_guint8(tvb, temp_pos);
+ temp_pos += 1;
- proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, (indexbytes + 11), al_ptaddr,
- "Point Number %d, Control Code: [%s,%s,%s (0x%02x)]",
- al_ptaddr, ctl_code_str, ctl_misc_str, ctl_tc_str, al_ctlobj_code);
+ al_bit = (al_ptflags & AL_OBJ_BI_FLAG7) >> 7; /* bit shift 1xxxxxxx -> xxxxxxx1 */
- proto_tree_add_text(objdet_tree, tvb, offset, (indexbytes+11),
- " [Count: %d] [On-Time: %d] [Off-Time: %d] [Status: %s (0x%02x)]",
- al_ctlobj_count, al_ctlobj_on, al_ctlobj_off, ctl_status_str, al_ctlobj_stat);
+ /* Get relative time, and convert to ns_time */
+ al_relms = tvb_get_letohs(tvb, temp_pos);
+ al_reltime.secs = al_relms / 1000;
+ al_reltime.nsecs = (al_relms % 1000) * 1000;
+ /* Now add to CTO time */
+ nstime_sum(&al_abstime, &al_cto, &al_reltime);
- offset += (indexbytes + 11);
+ dnp3_al_obj_quality(tvb, (offset+indexbytes), al_ptflags, point_tree, point_item, 0);
+ proto_item_append_text(point_item, ", Value: %d, Timestamp: %s", al_bit, abs_time_to_str(&al_abstime));
+ proto_tree_add_time(point_tree, hf_dnp3_al_rel_timestamp, tvb, temp_pos, 2, &al_reltime);
+ proto_item_set_len(point_item, indexbytes + 3);
- break;
+ offset += (indexbytes + 3);
- case AL_OBJ_CTR_32: /* 32-Bit Binary Counter (Obj:20, Var:01) */
- case AL_OBJ_CTR_16: /* 16-Bit Binary Counter (Obj:20, Var:02) */
- case AL_OBJ_FCTR_32: /* 32-Bit Frozen Counter (Obj:21, Var:01) */
- case AL_OBJ_FCTR_16: /* 16-Bit Frozen Counter (Obj:21, Var:02) */
- case AL_OBJ_CTRC_32: /* 32-Bit Counter Change Event w/o Time (Obj:22, Var:01) */
- case AL_OBJ_CTRC_16: /* 16-Bit Counter Change Event w/o Time (Obj:22, Var:02) */
+ break;
- /* Process Index */
- temp_pos = offset;
- indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
- temp_pos += indexbytes;
+ case AL_OBJ_CTLOP_BLK: /* Control Relay Output Block (Obj:12, Var:01) */
- /* Get Point Flags */
- al_ptflags = tvb_get_guint8(tvb, temp_pos);
- temp_pos += 1;
+ al_ctlobj_code = tvb_get_guint8(tvb, temp_pos);
+ temp_pos += 1;
- switch (al_obj)
- {
- case AL_OBJ_CTR_32:
- case AL_OBJ_FCTR_32:
- case AL_OBJ_CTRC_32:
-
- al_val32 = tvb_get_letohl(tvb, temp_pos);
- t_point = proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, (indexbytes + 5), al_ptaddr,
- "Point Number %d ", al_ptaddr);
- dnp3_al_obj_quality(tvb, (offset+indexbytes), al_ptflags, t_point, 2);
- proto_item_append_text(t_point, ", Value: %d", al_val32);
- offset += (indexbytes + 5);
- break;
-
- case AL_OBJ_CTR_16:
- case AL_OBJ_FCTR_16:
- case AL_OBJ_CTRC_16:
-
- al_val16 = tvb_get_letohs(tvb, temp_pos);
- t_point = proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, (indexbytes + 3), al_ptaddr,
- "Point Number %d ", al_ptaddr);
- dnp3_al_obj_quality(tvb, (offset+indexbytes), al_ptflags, t_point, 2);
- proto_item_append_text(t_point, ", Value: %d", al_val16);
- offset += (indexbytes + 3);
- break;
- }
+ /* Bit-Mask xxxx1111 for Control Code 'Code' */
+ al_ctlobj_code_c = al_ctlobj_code & AL_OBJCTLC_CODE;
+ ctl_code_str = val_to_str(al_ctlobj_code_c, dnp3_al_ctlc_code_vals, "Ctrl Code Invalid (0x%02x)");
- break;
+ /* Bit-Mask xx11xxxx for Control Code Misc Values */
+ al_ctlobj_code_m = al_ctlobj_code & AL_OBJCTLC_MISC;
+ ctl_misc_str = val_to_str(al_ctlobj_code_m, dnp3_al_ctlc_misc_vals, "");
- case AL_OBJ_AI_32: /* 32-Bit Analog Input (Obj:30, Var:01) */
- case AL_OBJ_AI_16: /* 16-Bit Analog Input (Obj:30, Var:02) */
- case AL_OBJ_AIC_32NT: /* 32-Bit Analog Change Event w/o Time (Obj:32, Var:01) */
- case AL_OBJ_AIC_16NT: /* 16-Bit Analog Change Event w/o Time (Obj:32, Var:02) */
+ /* Bit-Mask 11xxxxxx for Control Code 'Trip/Close' */
+ al_ctlobj_code_tc = al_ctlobj_code & AL_OBJCTLC_TC;
+ ctl_tc_str = val_to_str(al_ctlobj_code_tc, dnp3_al_ctlc_tc_vals, "");
- /* Process Index */
- temp_pos = offset;
- indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
- temp_pos += indexbytes;
+ /* Get "Count" Field */
+ al_ctlobj_count = tvb_get_guint8(tvb, temp_pos);
+ temp_pos += 1;
- /* Get Point Flags */
- al_ptflags = tvb_get_guint8(tvb, temp_pos);
- temp_pos += 1;
+ /* Get "On Time" Field */
+ al_ctlobj_on = tvb_get_letohl(tvb, temp_pos);
+ temp_pos += 4;
- switch (al_obj)
- {
- case AL_OBJ_AI_32:
- case AL_OBJ_AIC_32NT:
-
- al_val32 = tvb_get_letohl(tvb, temp_pos);
- t_point = proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, (indexbytes + 5), al_ptaddr,
- "Point Number %d ", al_ptaddr);
- dnp3_al_obj_quality(tvb, (offset+indexbytes), al_ptflags, t_point, 3);
- proto_item_append_text(t_point, ", Value: %d", al_val32);
- offset += (indexbytes + 5);
- break;
-
- case AL_OBJ_AI_16:
- case AL_OBJ_AIC_16NT:
-
- al_val16 = tvb_get_letohs(tvb, temp_pos);
- t_point = proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, (indexbytes + 3), al_ptaddr,
- "Point Number %d ", al_ptaddr);
- dnp3_al_obj_quality(tvb, (offset+indexbytes), al_ptflags, t_point, 3);
- proto_item_append_text(t_point, ", Value: %d", al_val16);
- offset += (indexbytes + 3);
- break;
- }
+ /* Get "Off Time" Field */
+ al_ctlobj_off = tvb_get_letohl(tvb, temp_pos);
+ temp_pos += 4;
- break;
+ al_ctlobj_stat = tvb_get_guint8(tvb, temp_pos);
+ proto_tree_add_item(point_item, hf_dnp3_al_ctrlstatus, tvb, temp_pos, 1, TRUE);
+ ctl_status_str = val_to_str(al_ctlobj_stat, dnp3_al_ctl_status_vals, "Invalid Status (0x%02x)");
+ temp_pos += 1;
- case AL_OBJ_CTR_32NF: /* 32-Bit Binary Counter Without Flag (Obj:20, Var:05) */
- case AL_OBJ_CTR_16NF: /* 16-Bit Binary Counter Without Flag (Obj:20, Var:06) */
- case AL_OBJ_AI_32NF: /* 32-Bit Analog Input Without Flag (Obj:30, Var:03) */
- case AL_OBJ_AI_16NF: /* 16-Bit Analog Input Without Flag (Obj:30, Var:04) */
+ proto_item_append_text(point_item, ", Control Code: [%s,%s,%s (0x%02x)]",
+ ctl_code_str, ctl_misc_str, ctl_tc_str, al_ctlobj_code);
- /* Process Index */
- temp_pos = offset;
- indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
- temp_pos += indexbytes;
+ proto_tree_add_text(point_tree, tvb, offset, (indexbytes+11),
+ " [Count: %d] [On-Time: %d] [Off-Time: %d] [Status: %s (0x%02x)]",
+ al_ctlobj_count, al_ctlobj_on, al_ctlobj_off, ctl_status_str, al_ctlobj_stat);
- switch (al_obj)
- {
- case AL_OBJ_CTR_32NF:
- case AL_OBJ_AI_32NF:
-
- al_val32 = tvb_get_letohl(tvb, temp_pos);
- proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, (indexbytes + 4), al_ptaddr,
- "Point Number %d, Value: %d", al_ptaddr, al_val32);
- offset += (indexbytes + 4);
- break;
-
- case AL_OBJ_CTR_16NF:
- case AL_OBJ_AI_16NF:
-
- al_val16 = tvb_get_letohs(tvb, temp_pos);
- proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, (indexbytes + 2), al_ptaddr,
- "Point Number %d, Value: %d", al_ptaddr, al_val16);
- offset += (indexbytes + 2);
- break;
- }
+ proto_item_set_len(point_item, temp_pos - offset);
+ offset = temp_pos;
- break;
+ break;
- case AL_OBJ_AIC_32T: /* 32-Bit Analog Change Event with Time (Obj:32, Var:03) */
- case AL_OBJ_AIC_16T: /* 16-Bit Analog Change Event with Time (Obj:32, Var:04) */
+ case AL_OBJ_AO_32OPB: /* 32-Bit Analog Output Block (Obj:41, Var:01) */
+ case AL_OBJ_AO_16OPB: /* 16-Bit Analog Output Block (Obj:41, Var:02) */
+ case AL_OBJ_AO_FLTOPB: /* 32-Bit Floating Point Output Block (Obj:41, Var:03) */
+ case AL_OBJ_AO_DBLOPB: /* 64-Bit Floating Point Output Block (Obj:41, Var:04) */
+
+ switch (al_obj)
+ {
+ case AL_OBJ_AO_32OPB:
+ al_val32 = tvb_get_letohl(tvb, temp_pos);
+ proto_item_append_text(point_item, ", Value: %d", al_val32);
+ proto_tree_add_item(point_tree, hf_dnp3_al_anaout32, tvb, temp_pos, 4, TRUE);
+ temp_pos += 4;
+ break;
+ case AL_OBJ_AO_16OPB:
+ al_val32 = tvb_get_letohs(tvb, temp_pos);
+ proto_item_append_text(point_item, ", Value: %d", al_val32);
+ proto_tree_add_item(point_tree, hf_dnp3_al_anaout16, tvb, temp_pos, 2, TRUE);
+ temp_pos += 2;
+ break;
+ case AL_OBJ_AO_FLTOPB:
+ al_valflt = tvb_get_letohieee_float(tvb, temp_pos);
+ proto_item_append_text(point_item, ", Value: %g", al_valflt);
+ proto_tree_add_item(point_tree, hf_dnp3_al_anaoutflt, tvb, temp_pos, 4, TRUE);
+ temp_pos += 4;
+ break;
+ case AL_OBJ_AO_DBLOPB:
+ al_valdbl = tvb_get_letohieee_double(tvb, temp_pos);
+ proto_item_append_text(point_item, ", Value: %lg", al_valdbl);
+ proto_tree_add_item(point_tree, hf_dnp3_al_anaoutdbl, tvb, temp_pos, 8, TRUE);
+ temp_pos += 8;
+ break;
+ }
- /* Process Index */
- temp_pos = offset;
- indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
- temp_pos += indexbytes;
+ /* Get control status */
+ al_ctlobj_stat = tvb_get_guint8(tvb, temp_pos);
+ ctl_status_str = val_to_str(al_ctlobj_stat, dnp3_al_ctl_status_vals, "Invalid Status (0x%02x)");
+ proto_item_append_text(point_item, " {Status: %s (0x%02x)]", ctl_status_str, al_ctlobj_stat);
+ proto_tree_add_item(point_tree, hf_dnp3_al_ctrlstatus, tvb, temp_pos, 1, TRUE);
+ temp_pos += 1;
- /* Get Point Flags */
- al_ptflags = tvb_get_guint8(tvb, temp_pos);
- temp_pos += 1;
+ proto_item_set_len(point_item, temp_pos - offset);
+ offset = temp_pos;
- switch (al_obj)
- {
- case AL_OBJ_AIC_32T:
-
- al_val32 = tvb_get_letohl(tvb, temp_pos);
- temp_pos += 4;
- t_point = proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, (indexbytes + 11), al_ptaddr,
- "Point Number %d ", al_ptaddr);
- dnp3_al_obj_quality(tvb, (offset+indexbytes), al_ptflags, t_point, 3);
- proto_item_append_text(t_point, ", Value: %d, Timestamp: %s", al_val32, dnp3_al_decode_timestamp(tvb, temp_pos, buff));
- offset += (indexbytes + 11); /* 1byte quality, 4bytes value, 6bytes timestamp */
- break;
-
- case AL_OBJ_AIC_16T:
-
- al_val16 = tvb_get_letohs(tvb, temp_pos);
- temp_pos += 2;
- t_point = proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, (indexbytes + 9), al_ptaddr,
- "Point Number %d ", al_ptaddr);
- dnp3_al_obj_quality(tvb, (offset+indexbytes), al_ptflags, t_point, 3);
- proto_item_append_text(t_point, ", Value: %d, Timestamp: %s", al_val16, dnp3_al_decode_timestamp(tvb, temp_pos, buff));
- offset += (indexbytes + 9); /* 1byte quality, 2bytes value, 6bytes timestamp */
- break;
- }
+ break;
- break;
+ case AL_OBJ_CTR_32: /* 32-Bit Binary Counter (Obj:20, Var:01) */
+ case AL_OBJ_CTR_16: /* 16-Bit Binary Counter (Obj:20, Var:02) */
+ case AL_OBJ_CTR_32NF: /* 32-Bit Binary Counter Without Flag (Obj:20, Var:05) */
+ case AL_OBJ_CTR_16NF: /* 16-Bit Binary Counter Without Flag (Obj:20, Var:06) */
+ case AL_OBJ_FCTR_32: /* 32-Bit Frozen Counter (Obj:21, Var:01) */
+ case AL_OBJ_FCTR_16: /* 16-Bit Frozen Counter (Obj:21, Var:02) */
+ case AL_OBJ_CTRC_32: /* 32-Bit Counter Change Event w/o Time (Obj:22, Var:01) */
+ case AL_OBJ_CTRC_16: /* 16-Bit Counter Change Event w/o Time (Obj:22, Var:02) */
+
+ /* Get Point Flags for those types that have them */
+ switch (al_obj)
+ {
+ case AL_OBJ_CTR_32NF:
+ case AL_OBJ_CTR_16NF:
+ break;
+
+ default:
+ al_ptflags = tvb_get_guint8(tvb, temp_pos);
+ dnp3_al_obj_quality(tvb, temp_pos, al_ptflags, point_tree, point_item, 2);
+ temp_pos += 1;
+ break;
+ }
- case AL_OBJ_AO_16: /* 16-Bit Analog Output Status (Obj:40, Var:02)" */
+ switch (al_obj)
+ {
+ case AL_OBJ_CTR_32:
+ case AL_OBJ_CTR_32NF:
+ case AL_OBJ_FCTR_32:
+ case AL_OBJ_CTRC_32:
+
+ al_val32 = tvb_get_letohl(tvb, temp_pos);
+ proto_item_append_text(point_item, ", Value: %d", al_val32);
+ proto_tree_add_item(point_tree, hf_dnp3_al_cnt32, tvb, temp_pos, 4, TRUE);
+ temp_pos += 4;
+ break;
+
+ case AL_OBJ_CTR_16:
+ case AL_OBJ_CTR_16NF:
+ case AL_OBJ_FCTR_16:
+ case AL_OBJ_CTRC_16:
+
+ al_val16 = tvb_get_letohs(tvb, temp_pos);
+ proto_item_append_text(point_item, ", Value: %d", al_val16);
+ proto_tree_add_item(point_tree, hf_dnp3_al_cnt16, tvb, temp_pos, 2, TRUE);
+ temp_pos += 2;
+ break;
+ }
+ proto_item_set_len(point_item, temp_pos - offset);
+ offset = temp_pos;
- /* Process Index */
- temp_pos = offset;
- indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
- temp_pos += indexbytes;
+ break;
- /* Get Point Flags */
- al_ptflags = tvb_get_guint8(tvb, temp_pos);
- temp_pos += 1;
+ case AL_OBJ_AI_32: /* 32-Bit Analog Input (Obj:30, Var:01) */
+ case AL_OBJ_AI_16: /* 16-Bit Analog Input (Obj:30, Var:02) */
+ case AL_OBJ_AI_32NF: /* 32-Bit Analog Input Without Flag (Obj:30, Var:03) */
+ case AL_OBJ_AI_16NF: /* 16-Bit Analog Input Without Flag (Obj:30, Var:04) */
+ case AL_OBJ_AI_FLT: /* 32-Bit Floating Point Input (Obj:30, Var:05) */
+ case AL_OBJ_AI_DBL: /* 64-Bit Floating Point Input (Obj:30, Var:06) */
+ case AL_OBJ_AIF_FLT: /* 32-Bit Frozen Floating Point Input (Obj:31, Var:07) */
+ case AL_OBJ_AIF_DBL: /* 64-Bit Frozen Floating Point Input (Obj:31, Var:08) */
+ case AL_OBJ_AIC_32NT: /* 32-Bit Analog Change Event w/o Time (Obj:32, Var:01) */
+ case AL_OBJ_AIC_16NT: /* 16-Bit Analog Change Event w/o Time (Obj:32, Var:02) */
+ case AL_OBJ_AIC_32T: /* 32-Bit Analog Change Event with Time (Obj:32, Var:03) */
+ case AL_OBJ_AIC_16T: /* 16-Bit Analog Change Event with Time (Obj:32, Var:04) */
+ case AL_OBJ_AIC_FLTNT: /* 32-Bit Floating Point Change Event w/o Time (Obj:32, Var:05) */
+ case AL_OBJ_AIC_DBLNT: /* 64-Bit Floating Point Change Event w/o Time (Obj:32, Var:06) */
+ case AL_OBJ_AIC_FLTT: /* 32-Bit Floating Point Change Event w/ Time (Obj:32, Var:07) */
+ case AL_OBJ_AIC_DBLT: /* 64-Bit Floating Point Change Event w/ Time (Obj:32, Var:08) */
+ case AL_OBJ_AIFC_FLTNT: /* 32-Bit Floating Point Frozen Change Event w/o Time (Obj:33, Var:05) */
+ case AL_OBJ_AIFC_DBLNT: /* 64-Bit Floating Point Frozen Change Event w/o Time (Obj:33, Var:06) */
+ case AL_OBJ_AIFC_FLTT: /* 32-Bit Floating Point Frozen Change Event w/ Time (Obj:33, Var:07) */
+ case AL_OBJ_AIFC_DBLT: /* 64-Bit Floating Point Frozen Change Event w/ Time (Obj:33, Var:08) */
+
+ /* Get Point Flags for those types that have them */
+ switch (al_obj)
+ {
+ case AL_OBJ_AI_32NF:
+ case AL_OBJ_AI_16NF:
+ break;
+
+ default:
+ al_ptflags = tvb_get_guint8(tvb, temp_pos);
+ dnp3_al_obj_quality(tvb, temp_pos, al_ptflags, point_tree, point_item, 3);
+ temp_pos += 1;
+ break;
+ }
- al_val16 = tvb_get_letohs(tvb, temp_pos);
- t_point = proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, (indexbytes + 3), al_ptaddr,
- "Point Number %d ", al_ptaddr);
- dnp3_al_obj_quality(tvb, (offset+indexbytes), al_ptflags, t_point, 4);
- proto_item_append_text(t_point, ", Value: %d", al_val16);
+ switch (al_obj)
+ {
+ case AL_OBJ_AI_32:
+ case AL_OBJ_AI_32NF:
+ case AL_OBJ_AIC_32NT:
+ case AL_OBJ_AIC_32T:
+
+ al_val32 = tvb_get_letohl(tvb, temp_pos);
+ proto_item_append_text(point_item, ", Value: %d", al_val32);
+ proto_tree_add_item(point_tree, hf_dnp3_al_ana32, tvb, temp_pos, 4, TRUE);
+ temp_pos += 4;
+ break;
+
+ case AL_OBJ_AI_16:
+ case AL_OBJ_AI_16NF:
+ case AL_OBJ_AIC_16NT:
+ case AL_OBJ_AIC_16T:
+
+ al_val16 = tvb_get_letohs(tvb, temp_pos);
+ proto_item_append_text(point_item, ", Value: %d", al_val16);
+ proto_tree_add_item(point_tree, hf_dnp3_al_ana16, tvb, temp_pos, 2, TRUE);
+ temp_pos += 2;
+ break;
+
+ case AL_OBJ_AI_FLT:
+ case AL_OBJ_AIF_FLT:
+ case AL_OBJ_AIC_FLTNT:
+ case AL_OBJ_AIC_FLTT:
+ case AL_OBJ_AIFC_FLTNT:
+ case AL_OBJ_AIFC_FLTT:
+
+ al_valflt = tvb_get_letohieee_float(tvb, temp_pos);
+ proto_item_append_text(point_item, ", Value: %g", al_valflt);
+ proto_tree_add_item(point_tree, hf_dnp3_al_anaflt, tvb, temp_pos, 4, TRUE);
+ temp_pos += 4;
+ break;
+
+ case AL_OBJ_AI_DBL:
+ case AL_OBJ_AIF_DBL:
+ case AL_OBJ_AIC_DBLNT:
+ case AL_OBJ_AIC_DBLT:
+ case AL_OBJ_AIFC_DBLNT:
+ case AL_OBJ_AIFC_DBLT:
+
+ al_valdbl = tvb_get_letohieee_double(tvb, temp_pos);
+ proto_item_append_text(point_item, ", Value: %lg", al_valdbl);
+ proto_tree_add_item(point_tree, hf_dnp3_al_anadbl, tvb, temp_pos, 8, TRUE);
+ temp_pos += 8;
+ break;
+ }
- offset += (indexbytes + 3);
+ /* Get timestamp */
+ switch (al_obj)
+ {
+ case AL_OBJ_AIC_32T:
+ case AL_OBJ_AIC_16T:
+ case AL_OBJ_AIC_FLTT:
+ case AL_OBJ_AIC_DBLT:
+ case AL_OBJ_AIFC_FLTT:
+ case AL_OBJ_AIFC_DBLT:
+ dnp3_al_get_timestamp(&al_abstime, tvb, temp_pos);
+ proto_item_append_text(point_item, ", Timestamp: %s", abs_time_to_str(&al_abstime));
+ proto_tree_add_time(point_tree, hf_dnp3_al_timestamp, tvb, temp_pos, 6, &al_abstime);
+ temp_pos += 6;
+ break;
+ }
- break;
+ proto_item_set_len(point_item, temp_pos - offset);
+ offset = temp_pos;
- case AL_OBJ_TD: /* Time and Date (Obj:50, Var:01) */
+ break;
- proto_tree_add_text(objdet_tree, tvb, offset, (indexbytes+6),
- "Time: %s", dnp3_al_decode_timestamp(tvb, offset, buff));
- offset += (indexbytes + 6);
- break;
+ case AL_OBJ_AO_32: /* 32-Bit Analog Output Status (Obj:40, Var:01) */
+ case AL_OBJ_AO_16: /* 16-Bit Analog Output Status (Obj:40, Var:02) */
+ case AL_OBJ_AO_FLT: /* 32-Bit Floating Point Output Status (Obj:40, Var:03) */
+ case AL_OBJ_AO_DBL: /* 64-Bit Floating Point Output Status (Obj:40, Var:04) */
+
+ /* Get Point Flags */
+ al_ptflags = tvb_get_guint8(tvb, temp_pos);
+ dnp3_al_obj_quality(tvb, (offset+indexbytes), al_ptflags, point_tree, point_item, 4);
+ temp_pos += 1;
+
+ switch (al_obj)
+ {
+ case AL_OBJ_AO_32: /* 32-Bit Analog Output Status (Obj:40, Var:01) */
+
+ al_val32 = tvb_get_letohl(tvb, temp_pos);
+ proto_item_append_text(point_item, ", Value: %d", al_val32);
+ proto_tree_add_item(point_tree, hf_dnp3_al_anaout32, tvb, temp_pos, 4, TRUE);
+ temp_pos += 4;
+ break;
+
+ case AL_OBJ_AO_16: /* 16-Bit Analog Output Status (Obj:40, Var:02) */
+
+ al_val16 = tvb_get_letohs(tvb, temp_pos);
+ proto_item_append_text(point_item, ", Value: %d", al_val16);
+ proto_tree_add_item(point_tree, hf_dnp3_al_anaout16, tvb, temp_pos, 2, TRUE);
+ temp_pos += 2;
+ break;
+
+ case AL_OBJ_AO_FLT: /* 32-Bit Floating Point Output Status (Obj:40, Var:03) */
+
+ al_valflt = tvb_get_letohieee_float(tvb, temp_pos);
+ proto_item_append_text(point_item, ", Value: %g", al_valflt);
+ proto_tree_add_item(point_tree, hf_dnp3_al_anaoutflt, tvb, temp_pos, 4, TRUE);
+ temp_pos += 4;
+ break;
+
+ case AL_OBJ_AO_DBL: /* 64-Bit Floating Point Output Status (Obj:40, Var:04) */
+
+ al_valdbl = tvb_get_letohieee_double(tvb, temp_pos);
+ proto_item_append_text(point_item, ", Value: %lg", al_valdbl);
+ proto_tree_add_item(point_tree, hf_dnp3_al_anaoutdbl, tvb, temp_pos, 8, TRUE);
+ temp_pos += 8;
+ break;
+ }
- case AL_OBJ_TDELAYF: /* Time Delay - Fine (Obj:52, Var:02) */
+ proto_item_set_len(point_item, temp_pos - offset);
+ offset = temp_pos;
- al_val16 = tvb_get_letohs(tvb, offset);
- proto_tree_add_text(objdet_tree, tvb, offset, (indexbytes + 2),"Time Delay: %d ms", al_val16);
- offset += (indexbytes + 2);
- break;
+ break;
- case AL_OBJ_CLASS0: /* Class Data Objects */
- case AL_OBJ_CLASS1:
- case AL_OBJ_CLASS2:
- case AL_OBJ_CLASS3:
+ case AL_OBJ_TD: /* Time and Date (Obj:50, Var:01) */
+ case AL_OBJ_TDCTO: /* Time and Date CTO (Obj:51, Var:01) */
- /* Process Index */
- indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
- offset += indexbytes;
- break;
+ dnp3_al_get_timestamp(&al_cto, tvb, offset);
+ proto_tree_add_time(object_tree, hf_dnp3_al_timestamp, tvb, offset, 6, &al_cto);
+ offset += (indexbytes + 6);
+ break;
- case AL_OBJ_IIN: /* IIN Data Object */
+ case AL_OBJ_TDELAYF: /* Time Delay - Fine (Obj:52, Var:02) */
- /* Process Index */
- indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
- offset += indexbytes;
- break;
+ al_val16 = tvb_get_letohs(tvb, offset);
+ proto_tree_add_text(object_tree, tvb, offset, (indexbytes + 2),"Time Delay: %d ms", al_val16);
+ offset += (indexbytes + 2);
+ break;
- default: /* In case of unknown object */
+ case AL_OBJ_CLASS0: /* Class Data Objects */
+ case AL_OBJ_CLASS1:
+ case AL_OBJ_CLASS2:
+ case AL_OBJ_CLASS3:
- proto_tree_add_text(objdet_tree, tvb, offset, tvb_reported_length_remaining(tvb, offset),
- "Unknown Data Chunk, %d Bytes", tvb_reported_length_remaining(tvb, offset));
- offset = tvb_length(tvb); /* Finish decoding if unknown object is encountered... */
- break;
- }
+ /* Process Index */
+ offset += indexbytes;
+ break;
+
+ case AL_OBJ_IIN: /* IIN Data Object */
+
+ /* Process Index */
+ offset += indexbytes;
+ break;
- bitindex += 1;
+ default: /* In case of unknown object */
+
+ proto_tree_add_text(object_tree, tvb, offset, tvb_reported_length_remaining(tvb, offset),
+ "Unknown Data Chunk, %d Bytes", tvb_reported_length_remaining(tvb, offset));
+ offset = tvb_length(tvb); /* Finish decoding if unknown object is encountered... */
+ break;
+ }
+ /* Increment the bit index for next time */
+ bitindex++;
+
+ /* And increment the poit address, may be overwritten bu an index value */
+ al_ptaddr++;
+ }
}
+ proto_item_set_len(object_item, offset - orig_offset);
return offset;
@@ -1646,7 +1878,6 @@ dissect_dnp3_al(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
if (tree) {
/* format up the text representation */
-
ti = proto_tree_add_text(tree, tvb, offset, data_len, "Application Layer: (");
if (al_ctl & DNP3_AL_FIR) proto_item_append_text(ti, "FIR, ");
if (al_ctl & DNP3_AL_FIN) proto_item_append_text(ti, "FIN, ");
@@ -1694,7 +1925,7 @@ dissect_dnp3_al(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
/* Process Data Object Details */
while (offset <= (data_len-2)) { /* 2 octet object code + CRC32 */
- offset = dnp3_al_process_object(tvb, offset, robj_tree);
+ offset = dnp3_al_process_object(tvb, offset, robj_tree, TRUE);
}
break;
@@ -1707,7 +1938,7 @@ dissect_dnp3_al(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
/* Process Data Object Details */
while (offset <= (data_len-2)) { /* 2 octet object code + CRC32 */
- offset = dnp3_al_process_object(tvb, offset, robj_tree);
+ offset = dnp3_al_process_object(tvb, offset, robj_tree, FALSE);
}
break;
@@ -1720,7 +1951,7 @@ dissect_dnp3_al(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
/* Process Data Object Details */
while (offset <= (data_len-2)) { /* 2 octet object code + CRC32 */
- offset = dnp3_al_process_object(tvb, offset, robj_tree);
+ offset = dnp3_al_process_object(tvb, offset, robj_tree, FALSE);
}
break;
@@ -1734,7 +1965,7 @@ dissect_dnp3_al(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
/* Process Data Object Details */
while (offset <= (data_len-2)) { /* 2 octet object code + CRC32 */
- offset = dnp3_al_process_object(tvb, offset, robj_tree);
+ offset = dnp3_al_process_object(tvb, offset, robj_tree, FALSE);
}
break;
@@ -1748,7 +1979,7 @@ dissect_dnp3_al(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
/* Process Data Object Details */
while (offset <= (data_len-2)) { /* 2 octet object code + CRC32 */
- offset = dnp3_al_process_object(tvb, offset, robj_tree);
+ offset = dnp3_al_process_object(tvb, offset, robj_tree, FALSE);
}
break;
@@ -1761,7 +1992,7 @@ dissect_dnp3_al(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
/* Process Data Object Details */
while (offset <= (data_len-2)) { /* 2 octet object code + CRC32 */
- offset = dnp3_al_process_object(tvb, offset, robj_tree);
+ offset = dnp3_al_process_object(tvb, offset, robj_tree, FALSE);
}
break;
@@ -1789,7 +2020,7 @@ dissect_dnp3_al(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
/* Process Data Object Details */
while (offset <= (data_len-2)) { /* 2 octet object code + CRC32 */
- offset = dnp3_al_process_object(tvb, offset, robj_tree);
+ offset = dnp3_al_process_object(tvb, offset, robj_tree, FALSE);
}
break;
@@ -1812,11 +2043,11 @@ dissect_dnp3_al(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
/* Data Link and Transport layer dissector */
/*****************************************************************/
static void
-dissect_dnp3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+dissect_dnp3_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
/* Set up structures needed to add the protocol subtree and manage it */
- proto_item *ti = NULL, *tdl, *tc, *al_chunks, *frag_tree_item;
+ proto_item *ti = NULL, *tdl, *tc, *al_chunks;
proto_tree *dnp3_tree = NULL, *dl_tree = NULL, *tr_tree = NULL, *field_tree = NULL, *al_tree = NULL;
int offset = 0, temp_offset = 0, al_result = 0;
gboolean dl_prm, tr_fir, tr_fin;
@@ -1827,9 +2058,16 @@ dissect_dnp3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
guint8 data_len;
int data_offset;
gboolean crc_OK = FALSE;
- tvbuff_t *al_tvb = NULL;
+ tvbuff_t *al_tvb = NULL, *next_tvb;
guint i;
- static guint seq_number = 0;
+ guint conv_seq_number;
+ gboolean save_fragmented;
+ fragment_data *frag_msg;
+ gboolean update_col_info = TRUE;
+ conversation_t *conversation;
+ dnp3_conv_t *conv_data_ptr;
+
+
/* Make entries in Protocol column and Info column on summary display */
if (check_col(pinfo->cinfo, COL_PROTOCOL))
@@ -1993,8 +2231,8 @@ dissect_dnp3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
/* extract the application layer data, validating the CRCs */
/* XXX - check for dl_len <= 5 */
- data_len = dl_len - 5; /* XXX - dl_len - 6, as we're no longer including the transport layer byte? */
- tmp = g_malloc(data_len);
+ data_len = dl_len - 5;
+ tmp = ep_alloc(data_len);
tmp_ptr = tmp;
i = 0;
data_offset = 1; /* skip the transport layer byte when assembling chunks */
@@ -2017,7 +2255,7 @@ dissect_dnp3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
if (tree)
{
- proto_tree_add_text(al_tree, tvb, offset - (chk_size + 2), chk_size,
+ proto_tree_add_text(al_tree, tvb, offset - (chk_size + 2), chk_size + 2,
"Application Chunk %d Len: %d CRC 0x%04x",
i, chk_size, act_crc);
}
@@ -2027,7 +2265,7 @@ dissect_dnp3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
if (tree)
{
- proto_tree_add_text(al_tree, tvb, offset - (chk_size + 2), chk_size,
+ proto_tree_add_text(al_tree, tvb, offset - (chk_size + 2), chk_size + 2,
"Application Chunk %d Len: %d Bad CRC got 0x%04x expected 0x%04x",
i, chk_size, act_crc, calc_crc);
}
@@ -2042,21 +2280,36 @@ dissect_dnp3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
if (crc_OK)
{
al_tvb = tvb_new_real_data(tmp, tmp_ptr-tmp, tmp_ptr-tmp);
- tvb_set_free_cb(al_tvb, g_free);
tvb_set_child_real_data_tvbuff(tvb, al_tvb);
/* Check for fragmented packet */
+ save_fragmented = pinfo->fragmented;
if (! (tr_fir && tr_fin))
{
/* A fragmented packet */
+ pinfo->fragmented = TRUE;
- fragment_data *fd_head;
+ /* look up the conversation */
+ conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
- /* if first fragment, update sequence id */
- if (tr_fir)
- {
- seq_number++;
+ /* if conversation found get the data pointer that you stored */
+ if (conversation && (!tr_fir || (conversation->setup_frame == pinfo->fd->num)))
+ conv_data_ptr = (dnp3_conv_t*)conversation_get_proto_data(conversation, proto_dnp3);
+
+ else {
+ /* new conversation create local data structure */
+ conv_data_ptr = g_mem_chunk_alloc(dnp3_conv_vals);
+
+ /*** Increment static global ***/
+ conv_data_ptr->conv_seq_number = seq_number++;
+
+ /* create the conversation with your data pointer */
+ conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
+ pinfo->srcport, pinfo->destport, 0);
+ conversation_add_proto_data(conversation, proto_dnp3, (void *)conv_data_ptr);
}
+ conv_seq_number = conv_data_ptr->conv_seq_number;
/*
* If we've already seen this frame, look it up in the
@@ -2064,54 +2317,107 @@ dissect_dnp3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
* whatever reassembly is in progress, if any, and see
* if it's done.
*/
- fd_head = fragment_add_seq_check(al_tvb, 0, pinfo, seq_number,
+ frag_msg = fragment_add_seq_check(al_tvb, 0, pinfo, conv_seq_number,
al_fragment_table,
al_reassembled_table,
tr_seq,
- tvb_reported_length(al_tvb),
+ tvb_reported_length(al_tvb), /* As this is a constructed tvb, all of it is ok */
!tr_fin);
- if (fd_head != NULL)
- {
- /* We have the complete payload */
- al_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
- tvb_set_child_real_data_tvbuff(tvb, al_tvb);
- add_new_data_source(pinfo, al_tvb, "Reassembled DNP 3.0 Application Layer message");
- if (tree)
- /* Show all fragments. */
- show_fragment_seq_tree(fd_head, &frag_items, tr_tree, pinfo, al_tvb, &frag_tree_item);
+ next_tvb = process_reassembled_data(al_tvb, 0, pinfo,
+ "Reassembled DNP 3.0 Application Layer message", frag_msg, &dnp3_frag_items,
+ &update_col_info, tr_tree);
+
+ if (frag_msg) { /* Reassembled */
+ /* We have the complete payload */
+ if (check_col (pinfo->cinfo, COL_INFO))
+ col_append_str (pinfo->cinfo, COL_INFO,
+ " (Application Layer Message reassembled)");
}
else
{
/* We don't have the complete reassembled payload. */
- al_tvb = NULL;
+ next_tvb = NULL;
if (check_col (pinfo->cinfo, COL_INFO))
- col_append_str (pinfo->cinfo, COL_INFO,
- " (Application Layer Message unreassembled)");
+ col_append_fstr (pinfo->cinfo, COL_INFO,
+ " (Application Layer Message %u unreassembled)", tr_seq);
}
}
else
{
/* No reassembly required */
- add_new_data_source(pinfo, al_tvb, "DNP 3.0 Application Layer message");
+ next_tvb = al_tvb;
+ add_new_data_source(pinfo, next_tvb, "DNP 3.0 Application Layer message");
}
+ pinfo->fragmented = save_fragmented;
}
else
{
/* CRC error - throw away the data. */
- g_free(tmp);
+ next_tvb = NULL;
if (tree)
proto_tree_add_text(dnp3_tree, tvb, 11, -1, "CRC failed, %d chunks", i);
}
- if (al_tvb)
+ if (next_tvb)
{
- al_result = dissect_dnp3_al(al_tvb, pinfo, dnp3_tree);
+ al_result = dissect_dnp3_al(next_tvb, pinfo, dnp3_tree);
}
}
}
+static guint
+get_dnp3_message_len(packet_info *pinfo, tvbuff_t *tvb, int offset)
+{
+ guint16 message_len; /* need 16 bits as total can exceed 255 */
+ guint16 data_crc; /* No. of user data CRC bytes */
+ message_len = tvb_get_guint8(tvb, offset + 2);
+
+ /* Add in 2 bytes for header start octets,
+ 1 byte for len itself,
+ 2 bytes for header CRC
+ data CRC bytes (2 bytes per 16 bytes of data
+ */
+
+ data_crc = (guint16)(ceil((message_len - 5) / 16.0)) * 2;
+ message_len += 2 + 1 + 2 + data_crc;
+ return message_len;
+}
+
+static int
+dissect_dnp3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ gint length = tvb_length_remaining(tvb, 0);
+
+ /* Check for a dnp packet. It should begin with 0x0564 */
+ if(length < DNP_HDR_LEN || tvb_get_ntohs(tvb, 0) != 0x0564) {
+ /* Not a DNP 3.0 packet, just happened to use the same port */
+ return 0;
+ }
+
+ tcp_dissect_pdus(tvb, pinfo, tree, TRUE, DNP_HDR_LEN,
+ get_dnp3_message_len, dissect_dnp3_message);
+
+ return tvb_length(tvb);
+}
+
+static void
+dnp3_init(void)
+{
+ /* destroy memory chunks if needed */
+
+ if (dnp3_conv_vals)
+ g_mem_chunk_destroy(dnp3_conv_vals);
+
+ /* now create memory chunks */
+
+ dnp3_conv_vals = g_mem_chunk_new("dnp3_proto_vals",
+ sizeof(dnp3_conv_t),
+ dnp3_conv_init_count * sizeof(dnp3_conv_t),
+ G_ALLOC_AND_FREE);
+}
+
static void
al_defragment_init(void)
{
@@ -2145,19 +2451,19 @@ proto_register_dnp3(void)
VALS(dnp3_ctl_func_sec_vals), DNP3_CTL_FUNC, "Frame Control Function Code", HFILL }},
{ &hf_dnp3_ctl_dir,
- { "Direction", "dnp3.ctl.dir", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_CTL_DIR, "", HFILL }},
+ { "Direction", "dnp3.ctl.dir", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_CTL_DIR, "", HFILL }},
{ &hf_dnp3_ctl_prm,
- { "Primary", "dnp3.ctl.prm", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_CTL_PRM, "", HFILL }},
+ { "Primary", "dnp3.ctl.prm", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_CTL_PRM, "", HFILL }},
{ &hf_dnp3_ctl_fcb,
- { "Frame Count Bit", "dnp3.ctl.fcb", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_CTL_FCB, "", HFILL }},
+ { "Frame Count Bit", "dnp3.ctl.fcb", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_CTL_FCB, "", HFILL }},
{ &hf_dnp3_ctl_fcv,
- { "Frame Count Valid", "dnp3.ctl.fcv", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_CTL_FCV, "", HFILL }},
+ { "Frame Count Valid", "dnp3.ctl.fcv", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_CTL_FCV, "", HFILL }},
{ &hf_dnp3_ctl_dfc,
- { "Data Flow Control", "dnp3.ctl.dfc", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_CTL_DFC, "", HFILL }},
+ { "Data Flow Control", "dnp3.ctl.dfc", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_CTL_DFC, "", HFILL }},
{ &hf_dnp3_dst,
{ "Destination", "dnp3.dst", FT_UINT16, BASE_DEC, NULL, 0x0, "Destination Address", HFILL }},
@@ -2175,10 +2481,10 @@ proto_register_dnp3(void)
{ "Transport Control", "dnp3.tr.ctl", FT_UINT8, BASE_HEX, NULL, 0x0, "Tranport Layer Control Byte", HFILL }},
{ &hf_dnp3_tr_fin,
- { "Final", "dnp3.tr.fin", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_TR_FIN, "", HFILL }},
+ { "Final", "dnp3.tr.fin", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_TR_FIN, "", HFILL }},
{ &hf_dnp3_tr_fir,
- { "First", "dnp3.tr.fir", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_TR_FIR, "", HFILL }},
+ { "First", "dnp3.tr.fir", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_TR_FIR, "", HFILL }},
{ &hf_dnp3_tr_seq,
{ "Sequence", "dnp3.tr.seq", FT_UINT8, BASE_DEC, NULL, DNP3_TR_SEQ, "Frame Sequence Number", HFILL }},
@@ -2187,13 +2493,13 @@ proto_register_dnp3(void)
{ "Application Control", "dnp3.al.ctl", FT_UINT8, BASE_HEX, NULL, 0x0, "Application Layer Control Byte", HFILL }},
{ &hf_dnp3_al_fir,
- { "First", "dnp3.al.fir", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_AL_FIR, "", HFILL }},
+ { "First", "dnp3.al.fir", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_AL_FIR, "", HFILL }},
{ &hf_dnp3_al_fin,
- { "Final", "dnp3.al.fin", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_AL_FIN, "", HFILL }},
+ { "Final", "dnp3.al.fin", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_AL_FIN, "", HFILL }},
{ &hf_dnp3_al_con,
- { "Confirm", "dnp3.al.con", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_AL_CON, "", HFILL }},
+ { "Confirm", "dnp3.al.con", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_AL_CON, "", HFILL }},
{ &hf_dnp3_al_seq,
{ "Sequence", "dnp3.al.seq", FT_UINT8, BASE_DEC, NULL, DNP3_AL_SEQ, "Frame Sequence Number", HFILL }},
@@ -2206,43 +2512,43 @@ proto_register_dnp3(void)
{ "Application Layer IIN bits", "dnp3.al.iin", FT_UINT16, BASE_DEC, NULL, 0x0, "Application Layer IIN", HFILL }},
{ &hf_dnp3_al_iin_bmsg,
- { "Broadcast Msg Rx", "dnp3.al.iin.bmsg", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_BMSG, "", HFILL }},
+ { "Broadcast Msg Rx", "dnp3.al.iin.bmsg", FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_BMSG, "", HFILL }},
{ &hf_dnp3_al_iin_cls1d,
- { "Class 1 Data Available", "dnp3.al.iin.cls1d", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_CLS1D, "", HFILL }},
+ { "Class 1 Data Available", "dnp3.al.iin.cls1d", FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_CLS1D, "", HFILL }},
{ &hf_dnp3_al_iin_cls2d,
- { "Class 2 Data Available", "dnp3.al.iin.cls2d", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_CLS2D, "", HFILL }},
+ { "Class 2 Data Available", "dnp3.al.iin.cls2d", FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_CLS2D, "", HFILL }},
{ &hf_dnp3_al_iin_cls3d,
- { "Class 3 Data Available", "dnp3.al.iin.cls3d", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_CLS3D, "", HFILL }},
+ { "Class 3 Data Available", "dnp3.al.iin.cls3d", FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_CLS3D, "", HFILL }},
{ &hf_dnp3_al_iin_tsr,
- { "Time Sync Required", "dnp3.al.iin.tsr", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_TSR, "", HFILL }},
+ { "Time Sync Required", "dnp3.al.iin.tsr", FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_TSR, "", HFILL }},
{ &hf_dnp3_al_iin_dol,
- { "Digital Outputs in Local", "dnp3.al.iin.dol", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_DOL, "", HFILL }},
+ { "Digital Outputs in Local", "dnp3.al.iin.dol", FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_DOL, "", HFILL }},
{ &hf_dnp3_al_iin_dt,
- { "Device Trouble", "dnp3.al.iin.dt", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_DT, "", HFILL }},
+ { "Device Trouble", "dnp3.al.iin.dt", FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_DT, "", HFILL }},
{ &hf_dnp3_al_iin_rst,
- { "Device Restart", "dnp3.al.iin.rst", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_RST, "", HFILL }},
+ { "Device Restart", "dnp3.al.iin.rst", FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_RST, "", HFILL }},
{ &hf_dnp3_al_iin_obju,
- { "Requested Objects Unknown", "dnp3.al.iin.obju", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_OBJU, "", HFILL }},
+ { "Requested Objects Unknown", "dnp3.al.iin.obju", FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_OBJU, "", HFILL }},
{ &hf_dnp3_al_iin_pioor,
- { "Parameters Invalid or Out of Range", "dnp3.al.iin.pioor", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_PIOOR, "", HFILL }},
+ { "Parameters Invalid or Out of Range", "dnp3.al.iin.pioor", FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_PIOOR, "", HFILL }},
{ &hf_dnp3_al_iin_ebo,
- { "Event Buffer Overflow", "dnp3.al.iin.ebo", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_EBO, "", HFILL }},
+ { "Event Buffer Overflow", "dnp3.al.iin.ebo", FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_EBO, "", HFILL }},
{ &hf_dnp3_al_iin_oae,
- { "Operation Already Executing", "dnp3.al.iin.oae", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_OAE, "", HFILL }},
+ { "Operation Already Executing", "dnp3.al.iin.oae", FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_OAE, "", HFILL }},
{ &hf_dnp3_al_iin_cc,
- { "Configuration Corrupt", "dnp3.al.iin.cc", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_CC, "", HFILL }},
+ { "Configuration Corrupt", "dnp3.al.iin.cc", FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_CC, "", HFILL }},
{ &hf_dnp3_al_obj,
{ "Object", "dnp3.al.obj", FT_UINT16, BASE_HEX, VALS(dnp3_al_obj_vals), 0x0, "Application Layer Object", HFILL }},
@@ -2254,189 +2560,244 @@ proto_register_dnp3(void)
{ "Qualifier Code", "dnp3.al.objq.code", FT_UINT8, BASE_DEC, VALS(dnp3_al_objq_code_vals), AL_OBJQ_CODE, "Object Qualifier Code", HFILL }},
{ &hf_dnp3_al_range_start8,
- { "Start", "dnp3.al.range.start8", FT_UINT8, BASE_DEC, NULL, 0x0, "Object Start Index", HFILL }},
+ { "Start (8 bit)", "dnp3.al.range.start", FT_UINT8, BASE_DEC, NULL, 0x0, "Object Start Index", HFILL }},
{ &hf_dnp3_al_range_stop8,
- { "Stop", "dnp3.al.range.stop8", FT_UINT8, BASE_DEC, NULL, 0x0, "Object Stop Index", HFILL }},
+ { "Stop (8 bit)", "dnp3.al.range.stop", FT_UINT8, BASE_DEC, NULL, 0x0, "Object Stop Index", HFILL }},
{ &hf_dnp3_al_range_start16,
- { "Start", "dnp3.al.range.start16", FT_UINT16, BASE_DEC, NULL, 0x0, "Object Start Index", HFILL }},
+ { "Start (16 bit)", "dnp3.al.range.start", FT_UINT16, BASE_DEC, NULL, 0x0, "Object Start Index", HFILL }},
{ &hf_dnp3_al_range_stop16,
- { "Stop", "dnp3.al.range.stop16", FT_UINT16, BASE_DEC, NULL, 0x0, "Object Stop Index", HFILL }},
+ { "Stop (16 bit)", "dnp3.al.range.stop", FT_UINT16, BASE_DEC, NULL, 0x0, "Object Stop Index", HFILL }},
{ &hf_dnp3_al_range_start32,
- { "Start", "dnp3.al.range.start32", FT_UINT32, BASE_DEC, NULL, 0x0, "Object Start Index", HFILL }},
+ { "Start (32 bit)", "dnp3.al.range.start", FT_UINT32, BASE_DEC, NULL, 0x0, "Object Start Index", HFILL }},
{ &hf_dnp3_al_range_stop32,
- { "Stop", "dnp3.al.range.stop32", FT_UINT32, BASE_DEC, NULL, 0x0, "Object Stop Index", HFILL }},
+ { "Stop (32 bit)", "dnp3.al.range.stop", FT_UINT32, BASE_DEC, NULL, 0x0, "Object Stop Index", HFILL }},
{ &hf_dnp3_al_range_abs8,
- { "Address", "dnp3.al.range.abs8", FT_UINT8, BASE_DEC, NULL, 0x0, "Object Absolute Address", HFILL }},
+ { "Address (8 bit)", "dnp3.al.range.abs", FT_UINT8, BASE_DEC, NULL, 0x0, "Object Absolute Address", HFILL }},
{ &hf_dnp3_al_range_abs16,
- { "Address", "dnp3.al.range.abs16", FT_UINT16, BASE_DEC, NULL, 0x0, "Object Absolute Address", HFILL }},
+ { "Address (16 bit)", "dnp3.al.range.abs", FT_UINT16, BASE_DEC, NULL, 0x0, "Object Absolute Address", HFILL }},
{ &hf_dnp3_al_range_abs32,
- { "Address", "dnp3.al.range.abs32", FT_UINT32, BASE_DEC, NULL, 0x0, "Object Absolute Address", HFILL }},
+ { "Address (32 bit)", "dnp3.al.range.abs", FT_UINT32, BASE_DEC, NULL, 0x0, "Object Absolute Address", HFILL }},
{ &hf_dnp3_al_range_quant8,
- { "Quantity", "dnp3.al.range.quant8", FT_UINT8, BASE_DEC, NULL, 0x0, "Object Quantity", HFILL }},
+ { "Quantity (8 bit)", "dnp3.al.range.quantity", FT_UINT8, BASE_DEC, NULL, 0x0, "Object Quantity", HFILL }},
{ &hf_dnp3_al_range_quant16,
- { "Quantity", "dnp3.al.range.quant16", FT_UINT16, BASE_DEC, NULL, 0x0, "Object Quantity", HFILL }},
+ { "Quantity (16 bit)", "dnp3.al.range.quantity", FT_UINT16, BASE_DEC, NULL, 0x0, "Object Quantity", HFILL }},
{ &hf_dnp3_al_range_quant32,
- { "Quantity", "dnp3.al.range.quant32", FT_UINT32, BASE_DEC, NULL, 0x0, "Object Quantity", HFILL }},
+ { "Quantity (32 bit)", "dnp3.al.range.quantity", FT_UINT32, BASE_DEC, NULL, 0x0, "Object Quantity", HFILL }},
+
+ { &hf_dnp3_al_index8,
+ { "Index (8 bit)", "dnp3.al.index", FT_UINT8, BASE_DEC, NULL, 0x0, "Object Index", HFILL }},
+
+ { &hf_dnp3_al_index16,
+ { "Index (16 bit)", "dnp3.al.index", FT_UINT16, BASE_DEC, NULL, 0x0, "Object Index", HFILL }},
+
+ { &hf_dnp3_al_index32,
+ { "Index (32 bit)", "dnp3.al.index", FT_UINT32, BASE_DEC, NULL, 0x0, "Object Index", HFILL }},
{ &hf_dnp3_al_ptnum,
{ "Object Point Number", "dnp3.al.ptnum", FT_UINT16, BASE_DEC, NULL, 0x0, "Object Point Number", HFILL }},
+ { &hf_dnp3_al_bit,
+ { "Value (bit)", "dnp3.al.bit", FT_BOOLEAN, BASE_NONE, TFS(&tfs_on_off), 0x1, "Digital Value (1 bit)", HFILL }},
+
+ { &hf_dnp3_al_2bit,
+ { "Value (two bit)", "dnp3.al.2bit", FT_UINT8, BASE_DEC, NULL, 0x0, "Digital Value (2 bit)", HFILL }},
+
+ { &hf_dnp3_al_ana16,
+ { "Value (16 bit)", "dnp3.al.ana", FT_UINT16, BASE_DEC, NULL, 0x0, "Analog Value (16 bit)", HFILL }},
+
+ { &hf_dnp3_al_ana32,
+ { "Value (32 bit)", "dnp3.al.ana", FT_UINT32, BASE_DEC, NULL, 0x0, "Analog Value (32 bit)", HFILL }},
+
+ { &hf_dnp3_al_anaflt,
+ { "Value (float)", "dnp3.al.ana", FT_FLOAT, BASE_DEC, NULL, 0x0, "Analog Value (float)", HFILL }},
+
+ { &hf_dnp3_al_anadbl,
+ { "Value (double)", "dnp3.al.ana", FT_DOUBLE, BASE_DEC, NULL, 0x0, "Analog Value (double)", HFILL }},
+
+ { &hf_dnp3_al_anaout16,
+ { "Output Value (16 bit)", "dnp3.al.anaout", FT_UINT16, BASE_DEC, NULL, 0x0, "Output Value (16 bit)", HFILL }},
+
+ { &hf_dnp3_al_anaout32,
+ { "Output Value (32 bit)", "dnp3.al.anaout", FT_UINT32, BASE_DEC, NULL, 0x0, "Output Value (32 bit)", HFILL }},
+
+ { &hf_dnp3_al_anaoutflt,
+ { "Output Value (float)", "dnp3.al.anaout", FT_FLOAT, BASE_DEC, NULL, 0x0, "Output Value (float)", HFILL }},
+
+ { &hf_dnp3_al_anaoutdbl,
+ { "Output (double)", "dnp3.al.anaout", FT_DOUBLE, BASE_DEC, NULL, 0x0, "Output Value (double)", HFILL }},
+
+ { &hf_dnp3_al_cnt16,
+ { "Counter (16 bit)", "dnp3.al.cnt", FT_UINT16, BASE_DEC, NULL, 0x0, "Counter Value (16 bit)", HFILL }},
+
+ { &hf_dnp3_al_cnt32,
+ { "Counter (32 bit)", "dnp3.al.cnt", FT_UINT32, BASE_DEC, NULL, 0x0, "Counter Value (32 bit)", HFILL }},
+
+ { &hf_dnp3_al_ctrlstatus,
+ { "Control Status", "dnp3.al.ctrlstatus", FT_UINT8, BASE_DEC, dnp3_al_ctl_status_vals, 0xff, "Control Status", HFILL }},
+
{ &hf_dnp3_al_biq_b0,
- { "Online", "dnp3.al.biq.b0", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BI_FLAG0, "", HFILL }},
+ { "Online", "dnp3.al.biq.b0", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG0, "", HFILL }},
{ &hf_dnp3_al_biq_b1,
- { "Restart", "dnp3.al.biq.b1", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BI_FLAG1, "", HFILL }},
+ { "Restart", "dnp3.al.biq.b1", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG1, "", HFILL }},
{ &hf_dnp3_al_biq_b2,
- { "Comm Fail", "dnp3.al.biq.b2", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BI_FLAG2, "", HFILL }},
+ { "Comm Fail", "dnp3.al.biq.b2", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG2, "", HFILL }},
{ &hf_dnp3_al_biq_b3,
- { "Remote Force", "dnp3.al.biq.b3", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BI_FLAG3, "", HFILL }},
+ { "Remote Force", "dnp3.al.biq.b3", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG3, "", HFILL }},
{ &hf_dnp3_al_biq_b4,
- { "Local Force", "dnp3.al.biq.b4", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BI_FLAG4, "", HFILL }},
+ { "Local Force", "dnp3.al.biq.b4", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG4, "", HFILL }},
{ &hf_dnp3_al_biq_b5,
- { "Chatter Filter", "dnp3.al.biq.b5", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BI_FLAG5, "", HFILL }},
+ { "Chatter Filter", "dnp3.al.biq.b5", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG5, "", HFILL }},
{ &hf_dnp3_al_biq_b6,
- { "Reserved", "dnp3.al.biq.b6", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BI_FLAG6, "", HFILL }},
+ { "Reserved", "dnp3.al.biq.b6", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG6, "", HFILL }},
{ &hf_dnp3_al_biq_b7,
- { "Point Value", "dnp3.al.biq.b7", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BI_FLAG7, "", HFILL }},
+ { "Point Value", "dnp3.al.biq.b7", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG7, "", HFILL }},
{ &hf_dnp3_al_boq_b0,
- { "Online", "dnp3.al.boq.b0", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BO_FLAG0, "", HFILL }},
+ { "Online", "dnp3.al.boq.b0", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG0, "", HFILL }},
{ &hf_dnp3_al_boq_b1,
- { "Restart", "dnp3.al.boq.b1", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BO_FLAG1, "", HFILL }},
+ { "Restart", "dnp3.al.boq.b1", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG1, "", HFILL }},
{ &hf_dnp3_al_boq_b2,
- { "Comm Fail", "dnp3.al.boq.b2", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BO_FLAG2, "", HFILL }},
+ { "Comm Fail", "dnp3.al.boq.b2", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG2, "", HFILL }},
{ &hf_dnp3_al_boq_b3,
- { "Remote Force", "dnp3.al.boq.b3", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BO_FLAG3, "", HFILL }},
+ { "Remote Force", "dnp3.al.boq.b3", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG3, "", HFILL }},
{ &hf_dnp3_al_boq_b4,
- { "Local Force", "dnp3.al.boq.b4", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BO_FLAG4, "", HFILL }},
+ { "Local Force", "dnp3.al.boq.b4", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG4, "", HFILL }},
{ &hf_dnp3_al_boq_b5,
- { "Reserved", "dnp3.al.boq.b5", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BO_FLAG5, "", HFILL }},
+ { "Reserved", "dnp3.al.boq.b5", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG5, "", HFILL }},
{ &hf_dnp3_al_boq_b6,
- { "Reserved", "dnp3.al.boq.b6", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BO_FLAG6, "", HFILL }},
+ { "Reserved", "dnp3.al.boq.b6", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG6, "", HFILL }},
{ &hf_dnp3_al_boq_b7,
- { "Point Value", "dnp3.al.boq.b7", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BO_FLAG7, "", HFILL }},
+ { "Point Value", "dnp3.al.boq.b7", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG7, "", HFILL }},
{ &hf_dnp3_al_ctrq_b0,
- { "Online", "dnp3.al.ctrq.b0", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_CTR_FLAG0, "", HFILL }},
+ { "Online", "dnp3.al.ctrq.b0", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG0, "", HFILL }},
{ &hf_dnp3_al_ctrq_b1,
- { "Restart", "dnp3.al.ctrq.b1", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_CTR_FLAG1, "", HFILL }},
+ { "Restart", "dnp3.al.ctrq.b1", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG1, "", HFILL }},
{ &hf_dnp3_al_ctrq_b2,
- { "Comm Fail", "dnp3.al.ctrq.b2", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_CTR_FLAG2, "", HFILL }},
+ { "Comm Fail", "dnp3.al.ctrq.b2", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG2, "", HFILL }},
{ &hf_dnp3_al_ctrq_b3,
- { "Remote Force", "dnp3.al.ctrq.b3", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_CTR_FLAG3, "", HFILL }},
+ { "Remote Force", "dnp3.al.ctrq.b3", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG3, "", HFILL }},
{ &hf_dnp3_al_ctrq_b4,
- { "Local Force", "dnp3.al.ctrq.b4", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_CTR_FLAG4, "", HFILL }},
+ { "Local Force", "dnp3.al.ctrq.b4", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG4, "", HFILL }},
{ &hf_dnp3_al_ctrq_b5,
- { "Roll-Over", "dnp3.al.ctrq.b5", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_CTR_FLAG5, "", HFILL }},
+ { "Roll-Over", "dnp3.al.ctrq.b5", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG5, "", HFILL }},
{ &hf_dnp3_al_ctrq_b6,
- { "Reserved", "dnp3.al.ctrq.b6", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_CTR_FLAG6, "", HFILL }},
+ { "Discontinuity", "dnp3.al.ctrq.b6", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG6, "", HFILL }},
{ &hf_dnp3_al_ctrq_b7,
- { "Reserved", "dnp3.al.ctrq.b7", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_CTR_FLAG7, "", HFILL }},
+ { "Reserved", "dnp3.al.ctrq.b7", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG7, "", HFILL }},
{ &hf_dnp3_al_aiq_b0,
- { "Online", "dnp3.al.aiq.b0", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AI_FLAG0, "", HFILL }},
+ { "Online", "dnp3.al.aiq.b0", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG0, "", HFILL }},
{ &hf_dnp3_al_aiq_b1,
- { "Restart", "dnp3.al.aiq.b1", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AI_FLAG1, "", HFILL }},
+ { "Restart", "dnp3.al.aiq.b1", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG1, "", HFILL }},
{ &hf_dnp3_al_aiq_b2,
- { "Comm Fail", "dnp3.al.aiq.b2", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AI_FLAG2, "", HFILL }},
+ { "Comm Fail", "dnp3.al.aiq.b2", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG2, "", HFILL }},
{ &hf_dnp3_al_aiq_b3,
- { "Remote Force", "dnp3.al.aiq.b3", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AI_FLAG3, "", HFILL }},
+ { "Remote Force", "dnp3.al.aiq.b3", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG3, "", HFILL }},
{ &hf_dnp3_al_aiq_b4,
- { "Local Force", "dnp3.al.aiq.b4", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AI_FLAG4, "", HFILL }},
+ { "Local Force", "dnp3.al.aiq.b4", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG4, "", HFILL }},
{ &hf_dnp3_al_aiq_b5,
- { "Over-Range", "dnp3.al.aiq.b5", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AI_FLAG5, "", HFILL }},
+ { "Over-Range", "dnp3.al.aiq.b5", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG5, "", HFILL }},
{ &hf_dnp3_al_aiq_b6,
- { "Reference Check", "dnp3.al.aiq.b6", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AI_FLAG6, "", HFILL }},
+ { "Reference Check", "dnp3.al.aiq.b6", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG6, "", HFILL }},
{ &hf_dnp3_al_aiq_b7,
- { "Reserved", "dnp3.al.aiq.b7", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AI_FLAG7, "", HFILL }},
+ { "Reserved", "dnp3.al.aiq.b7", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG7, "", HFILL }},
{ &hf_dnp3_al_aoq_b0,
- { "Online", "dnp3.al.aoq.b0", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AO_FLAG0, "", HFILL }},
+ { "Online", "dnp3.al.aoq.b0", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG0, "", HFILL }},
{ &hf_dnp3_al_aoq_b1,
- { "Restart", "dnp3.al.aoq.b1", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AO_FLAG1, "", HFILL }},
+ { "Restart", "dnp3.al.aoq.b1", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG1, "", HFILL }},
{ &hf_dnp3_al_aoq_b2,
- { "Comm Fail", "dnp3.al.aoq.b2", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AO_FLAG2, "", HFILL }},
+ { "Comm Fail", "dnp3.al.aoq.b2", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG2, "", HFILL }},
{ &hf_dnp3_al_aoq_b3,
- { "Remote Force", "dnp3.al.aoq.b3", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AO_FLAG3, "", HFILL }},
+ { "Remote Force", "dnp3.al.aoq.b3", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG3, "", HFILL }},
{ &hf_dnp3_al_aoq_b4,
- { "Reserved", "dnp3.al.aoq.b4", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AO_FLAG4, "", HFILL }},
+ { "Local Force", "dnp3.al.aoq.b4", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG4, "", HFILL }},
{ &hf_dnp3_al_aoq_b5,
- { "Reserved", "dnp3.al.aoq.b5", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AO_FLAG5, "", HFILL }},
+ { "Reserved", "dnp3.al.aoq.b5", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG5, "", HFILL }},
{ &hf_dnp3_al_aoq_b6,
- { "Reserved", "dnp3.al.aoq.b6", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AO_FLAG6, "", HFILL }},
+ { "Reserved", "dnp3.al.aoq.b6", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG6, "", HFILL }},
{ &hf_dnp3_al_aoq_b7,
- { "Reserved", "dnp3.al.aoq.b7", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AO_FLAG7, "", HFILL }},
+ { "Reserved", "dnp3.al.aoq.b7", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG7, "", HFILL }},
+
+ { &hf_dnp3_al_timestamp,
+ { "Timestamp", "dnp3.al.timestamp", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0, "Object Timestamp", HFILL }},
+
+ { &hf_dnp3_al_rel_timestamp,
+ { "Relative Timestamp", "dnp3.al.reltimestamp", FT_RELATIVE_TIME, BASE_NONE, NULL, 0, "Object Relative Timestamp", HFILL }},
- { &hf_fragment,
+ { &hf_dnp3_fragment,
{ "DNP 3.0 AL Fragment", "al.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "DNP 3.0 Application Layer Fragment", HFILL }},
- { &hf_fragments,
+ { &hf_dnp3_fragments,
{ "DNP 3.0 AL Fragments", "al.fragments", FT_NONE, BASE_NONE, NULL, 0x0, "DNP 3.0 Application Layer Fragments", HFILL }},
- { &hf_fragment_overlap,
+ { &hf_dnp3_fragment_overlap,
{ "Fragment overlap", "al.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
- { &hf_fragment_overlap_conflict,
+ { &hf_dnp3_fragment_overlap_conflict,
{ "Conflicting data in fragment overlap", "al.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
"Overlapping fragments contained conflicting data", HFILL }},
- { &hf_fragment_multiple_tails,
+ { &hf_dnp3_fragment_multiple_tails,
{ "Multiple tail fragments found", "al.fragment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
"Several tails were found when defragmenting the packet", HFILL }},
- { &hf_fragment_too_long_fragment,
+ { &hf_dnp3_fragment_too_long_fragment,
{ "Fragment too long", "al.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
"Fragment contained data past end of packet", HFILL }},
- { &hf_fragment_error,
+ { &hf_dnp3_fragment_error,
{ "Defragmentation error", "al.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
"Defragmentation error due to illegal fragments", HFILL }},
- { &hf_fragment_reassembled_in,
+
+ { &hf_dnp3_fragment_reassembled_in,
{ "Reassembled PDU In Frame", "al.fragment.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
"This PDU is reassembled in this frame", HFILL }}
};
@@ -2456,9 +2817,14 @@ proto_register_dnp3(void)
&ett_dnp3_al_obj_range,
&ett_dnp3_al_objdet,
&ett_dnp3_al_obj_quality,
- &ett_fragment,
- &ett_fragments
+ &ett_dnp3_al_obj_point,
+ &ett_dnp3_fragment,
+ &ett_dnp3_fragments
};
+ module_t *dnp3_module;
+
+/* Register protocol init routine */
+ register_init_routine(&dnp3_init);
/* Register the protocol name and description */
proto_dnp3 = proto_register_protocol("Distributed Network Protocol 3.0",
@@ -2468,6 +2834,13 @@ proto_register_dnp3(void)
proto_register_field_array(proto_dnp3, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
+ dnp3_module = prefs_register_protocol(proto_dnp3, NULL);
+ prefs_register_bool_preference(dnp3_module, "desegment",
+ "Reassemble DNP3 messages spanning multiple TCP segments",
+ "Whether the DNP3 dissector should reassemble messages spanning multiple TCP segments."
+ " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
+ &dnp3_desegment);
+
al_defragment_init();
}