aboutsummaryrefslogtreecommitdiffstats
path: root/epan
diff options
context:
space:
mode:
authorMichael Mann <mmann78@netscape.net>2013-07-16 14:01:45 +0000
committerMichael Mann <mmann78@netscape.net>2013-07-16 14:01:45 +0000
commit18ea28c45e32659a1eee3d94d9e9d942138c03bc (patch)
tree7daca90e369238aed4402aac1ff7b5855ad68229 /epan
parent3baf637267ea5ac6173acfc0a4c1dc9dd6016761 (diff)
Improve iec104 dissector. Bug 8849 (https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8849)
1) Decoding type 70 - End of initialization 2) Decoding qualifier of interrogation for type 100 3) Table of data length for all object types => checking length on one place 4) Setting correct number of selected bytes for IOA From Jiří Engelthaler svn path=/trunk/; revision=50664
Diffstat (limited to 'epan')
-rw-r--r--epan/dissectors/packet-iec104.c933
1 files changed, 544 insertions, 389 deletions
diff --git a/epan/dissectors/packet-iec104.c b/epan/dissectors/packet-iec104.c
index b9f9d8496a..a5c7ad61d9 100644
--- a/epan/dissectors/packet-iec104.c
+++ b/epan/dissectors/packet-iec104.c
@@ -56,9 +56,10 @@ struct asduheader {
guint32 IOA;
guint8 NumIx;
guint8 SQ;
+ guint8 DataLength;
};
-/* asdu command value/status structure */
+/* ASDU command value/status structure */
typedef struct {
gboolean OFF;
gboolean ON;
@@ -73,8 +74,6 @@ typedef struct {
gboolean LongP; /* Long Pulse */
gboolean Persist; /* Persistent output */
gboolean SE; /* Select (1) / Execute (0) */
-
-
} td_CmdInfo;
#define IEC104_PORT 2404
@@ -102,19 +101,17 @@ static int proto_iec104asdu = -1;
/* Type I is only lowest bit set to 0 */
#define I_TYPE 0
-#define I_TYPE2 2
#define S_TYPE 1
#define U_TYPE 3
#define APCI_TYPE_UNKNOWN 4
+
static const value_string apci_types [] = {
{ I_TYPE, "I" },
{ S_TYPE, "S" },
- { I_TYPE2, "I" },
{ U_TYPE, "U" },
{ 0, NULL }
};
-
/* Constants relative to the filed, independent of the field position in the byte */
/* U (Unnombered) constants */
#define U_STARTDT_ACT 0x01
@@ -133,7 +130,6 @@ static const value_string u_types[] = {
{ 0, NULL }
};
-
/* ASDU types (TypeId) */
#define M_SP_NA_1 1 /* single-point information */
#define M_DP_NA_1 3 /* double-point information */
@@ -246,6 +242,7 @@ static const value_string asdu_types [] = {
{ F_SC_NB_1, "F_SC_NB_1" },
{ 0, NULL }
};
+
static const value_string asdu_lngtypes [] = {
{ M_SP_NA_1, "single-point information" },
{ M_DP_NA_1, "double-point information" },
@@ -304,6 +301,68 @@ static const value_string asdu_lngtypes [] = {
{ 0, NULL }
};
+typedef struct {
+ guint8 value;
+ guint8 length;
+} td_asdu_length;
+
+static const td_asdu_length asdu_length [] = {
+ { M_SP_NA_1, 1 },
+ { M_DP_NA_1, 1 },
+ { M_ST_NA_1, 2 },
+ { M_BO_NA_1, 5 },
+ { M_ME_NA_1, 3 },
+ { M_ME_NB_1, 3 },
+ { M_ME_NC_1, 5 },
+ { M_IT_NA_1, 5 },
+ { M_PS_NA_1, 5 },
+ { M_ME_ND_1, 2 },
+ { M_SP_TB_1, 8 },
+ { M_DP_TB_1, 8 },
+ { M_ST_TB_1, 9 },
+ { M_BO_TB_1, 12 },
+ { M_ME_TD_1, 10 },
+ { M_ME_TE_1, 10 },
+ { M_ME_TF_1, 12 },
+ { M_IT_TB_1, 12 },
+ { M_EP_TD_1, 10 },
+ { M_EP_TE_1, 11 },
+ { M_EP_TF_1, 11 },
+ { C_SC_NA_1, 1 },
+ { C_DC_NA_1, 1 },
+ { C_RC_NA_1, 1 },
+ { C_SE_NA_1, 3 },
+ { C_SE_NB_1, 3 },
+ { C_SE_NC_1, 5 },
+ { C_BO_NA_1, 4 },
+ { C_SC_TA_1, 8 },
+ { C_DC_TA_1, 8 },
+ { C_RC_TA_1, 8 },
+ { C_SE_TA_1, 10 },
+ { C_SE_TB_1, 10 },
+ { C_SE_TC_1, 12 },
+ { C_BO_TA_1, 11 },
+ { M_EI_NA_1, 1 },
+ { C_IC_NA_1, 1 },
+ { C_CI_NA_1, 1 },
+ { C_RD_NA_1, 0 },
+ { C_CS_NA_1, 7 },
+ { C_RP_NA_1, 1 },
+ { C_TS_TA_1, 9 },
+ { P_ME_NA_1, 3 },
+ { P_ME_NB_1, 3 },
+ { P_ME_NC_1, 5 },
+ { P_AC_NA_1, 1 },
+ { F_FR_NA_1, 6 },
+ { F_SR_NA_1, 7 },
+ { F_SC_NA_1, 4 },
+ { F_LS_NA_1, 5 },
+ { F_AF_NA_1, 4 },
+ { F_SG_NA_1, 0 },
+ { F_DR_TA_1, 13 },
+ { F_SC_NB_1, 16 },
+ { 0, 0 }
+};
/* Cause of Transmision (CauseTx) */
#define Per_Cyc 1
@@ -345,6 +404,7 @@ static const value_string asdu_lngtypes [] = {
#define UkCauseTx 45
#define UkComAdrASDU 46
#define UkIOA 47
+
static const value_string causetx_types [] = {
{ Per_Cyc ,"Per/Cyc" },
{ Back ,"Back" },
@@ -389,10 +449,10 @@ static const value_string causetx_types [] = {
};
static const value_string diq_types[] = {
- { 0, "IPOS0" },
+ { 0, "Indeterminate or Intermediate" },
{ 1, "OFF" },
{ 2, "ON" },
- { 3, "IPOS3" },
+ { 3, "Indeterminate" },
{ 0, NULL }
};
@@ -420,18 +480,49 @@ static const value_string rco_up_types[] = {
{ 0, NULL }
};
+static const value_string coi_r_types[] = {
+ { 0, "Local power switch on" },
+ { 1, "Local manual reset" },
+ { 2, "Remote reset" },
+ { 0, NULL }
+};
+static const value_string qoi_r_types[] = {
+ { 0, "Not specified" },
+ { 20, "Station interrogation (global)" },
+ { 21, "Group 1 interrotagion" },
+ { 22, "Group 2 interrotagion" },
+ { 23, "Group 3 interrotagion" },
+ { 24, "Group 4 interrotagion" },
+ { 25, "Group 5 interrotagion" },
+ { 26, "Group 6 interrotagion" },
+ { 27, "Group 7 interrotagion" },
+ { 28, "Group 8 interrotagion" },
+ { 29, "Group 9 interrotagion" },
+ { 30, "Group 10 interrotagion" },
+ { 31, "Group 11 interrotagion" },
+ { 32, "Group 12 interrotagion" },
+ { 33, "Group 13 interrotagion" },
+ { 34, "Group 14 interrotagion" },
+ { 35, "Group 15 interrotagion" },
+ { 36, "Group 16 interrotagion" },
+ { 0, NULL }
+};
static const true_false_string tfs_blocked_not_blocked = { "Blocked", "Not blocked" };
static const true_false_string tfs_substituted_not_substituted = { "Substituted", "Not Substituted" };
static const true_false_string tfs_not_topical_topical = { "Not Topical", "Topical" };
static const true_false_string tfs_invalid_valid = { "Invalid", "Valid" };
+static const true_false_string tfs_transient_not_transient = { "Transient", "Not Transient" };
static const true_false_string tfs_overflow_no_overflow = { "Overflow", "No overflow" };
static const true_false_string tfs_select_execute = { "Select", "Execute" };
+static const true_false_string tfs_local_dst = { "DST", "Local" };
+static const true_false_string tfs_coi_i = { "Initialisation after change of local parameters", "Initialisation with unchanged local parameters" };
/* Protocol fields to be filtered */
static int hf_apdulen = -1;
-static int hf_apcitype = -1;
+static int hf_apcitype1 = -1;
+static int hf_apcitype2 = -1;
static int hf_apciutype = -1;
static int hf_apcitx = -1;
static int hf_apcirx = -1;
@@ -447,14 +538,23 @@ static int hf_ioa = -1;
static int hf_numix = -1;
static int hf_sq = -1;
static int hf_cp56time = -1;
+static int hf_cp56time_ms = -1;
+static int hf_cp56time_min = -1;
+static int hf_cp56time_iv = -1;
+static int hf_cp56time_hour = -1;
+static int hf_cp56time_su = -1;
+static int hf_cp56time_day = -1;
+static int hf_cp56time_dow = -1;
+static int hf_cp56time_month = -1;
+static int hf_cp56time_year = -1;
static int hf_siq = -1;
-static int hf_siq_on = -1;
+static int hf_siq_spi = -1;
static int hf_siq_bl = -1;
static int hf_siq_sb = -1;
static int hf_siq_nt = -1;
static int hf_siq_iv = -1;
static int hf_diq = -1;
-static int hf_diq_value = -1;
+static int hf_diq_dpi = -1;
static int hf_diq_bl = -1;
static int hf_diq_sb = -1;
static int hf_diq_nt = -1;
@@ -466,7 +566,9 @@ static int hf_qds_sb = -1;
static int hf_qds_nt = -1;
static int hf_qds_iv = -1;
static int hf_vti = -1;
-static int hf_vti_tr = -1;
+static int hf_vti_v = -1;
+static int hf_vti_t = -1;
+static int hf_qos = -1;
static int hf_qos_ql = -1;
static int hf_qos_se = -1;
static int hf_sco = -1;
@@ -481,20 +583,28 @@ static int hf_rco = -1;
static int hf_rco_up = -1;
static int hf_rco_qu = -1;
static int hf_rco_se = -1;
+static int hf_coi = -1;
+static int hf_coi_r = -1;
+static int hf_coi_i = -1;
+static int hf_qoi = -1;
static gint hf_asdu_bitstring = -1;
static gint hf_asdu_float = -1;
static gint hf_asdu_normval = -1;
+static gint hf_asdu_scalval = -1;
static gint ett_apci = -1;
static gint ett_asdu = -1;
static gint ett_asdu_objects = -1;
static gint ett_siq = -1;
static gint ett_diq = -1;
+static gint ett_vti = -1;
static gint ett_qds = -1;
+static gint ett_qos = -1;
static gint ett_sco = -1;
static gint ett_dco = -1;
static gint ett_rco = -1;
+static gint ett_cp56time = -1;
static expert_field ei_iec104_short_asdu = EI_INIT;
static expert_field ei_iec104_apdu_min_len = EI_INIT;
@@ -502,55 +612,90 @@ static expert_field ei_iec104_apdu_min_len = EI_INIT;
/* Misc. functions for dissection of signal values */
/* ====================================================================
- void get_CP56Time( td_CP56Time *cp56t, tvbuff_t *tvb, guint8 offset)
+ void get_CP56Time(td_CP56Time *cp56t, tvbuff_t *tvb, guint8 offset)
Dissects the CP56Time2a time (Seven octet binary time)
that starts 'offset' bytes in 'tvb'.
- The time and date is put in struct 'cp56t'
==================================================================== */
-static void get_CP56Time(tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_CP56Time(tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree)
{
guint16 ms;
- guint8 valid;
+ guint8 value;
+ guint8 su;
struct tm tm;
nstime_t datetime;
proto_item* ti;
+ proto_tree* cp56time_tree;
- ms = tvb_get_letohs( tvb , *offset );
- (*offset) += 2;
+ ms = tvb_get_letohs(tvb, *offset);
tm.tm_sec = ms / 1000;
- datetime.nsecs = ms * 1000000;
-
- tm.tm_min = tvb_get_guint8(tvb, *offset);
- /* "Invalid" -- Todo: test */
- valid = tm.tm_min & 0x80;
+ datetime.nsecs = (ms % 1000) * 1000000;
+ (*offset) += 2;
- tm.tm_min &= 0x3F;
+ value = tvb_get_guint8(tvb, *offset);
+ tm.tm_min = value & 0x3F;
(*offset)++;
- tm.tm_hour = 0x1F & tvb_get_guint8(tvb, *offset);
+
+ value = tvb_get_guint8(tvb, *offset);
+ tm.tm_hour = value & 0x1F;
+ su = value & 0x80;
(*offset)++;
- tm.tm_mday = tvb_get_guint8(tvb, *offset) & 0x1F;
+
+ value = tvb_get_guint8(tvb, *offset);
+ tm.tm_mday = value & 0x1F;
(*offset)++;
- tm.tm_mon = 0x0F & tvb_get_guint8(tvb, *offset);
+
+ value = tvb_get_guint8(tvb, *offset);
+ tm.tm_mon = (value & 0x0F) - 1;
(*offset)++;
- tm.tm_year = 0x7F & tvb_get_guint8(tvb, *offset);
+
+ value = tvb_get_guint8(tvb, *offset);
+ tm.tm_year = value & 0x7F;
+ if (tm.tm_year < 70)
+ tm.tm_year += 100;
+
(*offset)++;
- tm.tm_isdst = -1; /* there's no info on whether DST was in force; assume it's
- * the same as currently */
+ if (su)
+ tm.tm_isdst = 1;
+ else
+ tm.tm_isdst = -1; /* there's no info on whether DST was in force; assume it's
+ * the same as currently */
datetime.secs = mktime(&tm);
- ti = proto_tree_add_time(iec104_header_tree, hf_cp56time, tvb, (*offset)-7, 7, &datetime);
- proto_item_append_text(ti, "%s", valid ? "Invalid":"Valid");
-}
+ (*offset) -= 7;
+
+ ti = proto_tree_add_time(iec104_header_tree, hf_cp56time, tvb, *offset, 7, &datetime);
+ cp56time_tree = proto_item_add_subtree(ti, ett_cp56time);
+
+ proto_tree_add_item(cp56time_tree, hf_cp56time_ms, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
+ (*offset) += 2;
+
+ proto_tree_add_item(cp56time_tree, hf_cp56time_min, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(cp56time_tree, hf_cp56time_iv, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
+ (*offset) ++;
+
+ proto_tree_add_item(cp56time_tree, hf_cp56time_hour, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(cp56time_tree, hf_cp56time_su, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
+ (*offset) ++;
+
+ proto_tree_add_item(cp56time_tree, hf_cp56time_day, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(cp56time_tree, hf_cp56time_dow, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
+ (*offset) ++;
+
+ proto_tree_add_item(cp56time_tree, hf_cp56time_month, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
+ (*offset) ++;
+ proto_tree_add_item(cp56time_tree, hf_cp56time_year, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
+ (*offset) ++;
+}
/* ====================================================================
Information object address (Identifier)
ASDU -> Inform Object #1 -> Information object address
==================================================================== */
-static proto_item* get_InfoObjectAddress( guint32 *asdu_info_obj_addr, tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static proto_item* get_InfoObjectAddress(guint32 *asdu_info_obj_addr, tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree)
{
proto_item* ti;
@@ -562,21 +707,40 @@ static proto_item* get_InfoObjectAddress( guint32 *asdu_info_obj_addr, tvbuff_t
return ti;
}
-
-
+/* ====================================================================
+ TypeId length
+ ==================================================================== */
+static guint8 get_TypeIdLength(guint8 TypeId)
+{
+ guint8 ret = 0;
+ td_asdu_length *item;
+
+ item = (td_asdu_length *)asdu_length;
+ while (item->value)
+ {
+ if (item->value == TypeId)
+ {
+ ret = item->length;
+ break;
+ }
+ item++;
+ }
+
+ return ret;
+}
/* ====================================================================
SIQ: Single-point information (IEV 371-02-07) w quality descriptor
==================================================================== */
-static void get_SIQ( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_SIQ(tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree)
{
proto_item* ti;
proto_tree* siq_tree;
ti = proto_tree_add_item(iec104_header_tree, hf_siq, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
- siq_tree = proto_item_add_subtree( ti, ett_siq );
+ siq_tree = proto_item_add_subtree(ti, ett_siq);
- proto_tree_add_item(siq_tree, hf_siq_on, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(siq_tree, hf_siq_spi, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(siq_tree, hf_siq_bl, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(siq_tree, hf_siq_sb, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(siq_tree, hf_siq_nt, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
@@ -588,34 +752,33 @@ static void get_SIQ( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tr
/* ====================================================================
DIQ: Double-point information (IEV 371-02-08) w quality descriptor
==================================================================== */
-static void get_DIQ( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_DIQ(tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree)
{
proto_item* ti;
proto_tree* diq_tree;
ti = proto_tree_add_item(iec104_header_tree, hf_diq, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
- diq_tree = proto_item_add_subtree( ti, ett_diq );
+ diq_tree = proto_item_add_subtree(ti, ett_diq);
- proto_tree_add_item(diq_tree, hf_diq_value, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(diq_tree, hf_diq_dpi, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(diq_tree, hf_diq_bl, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(diq_tree, hf_diq_sb, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(diq_tree, hf_diq_nt, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(diq_tree, hf_diq_iv, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
(*offset)++;
-
}
/* ====================================================================
QDS: Quality descriptor (separate octet)
==================================================================== */
-static void get_QDS( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_QDS(tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree)
{
proto_item* ti;
proto_tree* qds_tree;
ti = proto_tree_add_item(iec104_header_tree, hf_qds, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
- qds_tree = proto_item_add_subtree( ti, ett_qds );
+ qds_tree = proto_item_add_subtree(ti, ett_qds);
proto_tree_add_item(qds_tree, hf_qds_ov, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(qds_tree, hf_qds_bl, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
@@ -631,7 +794,7 @@ static void get_QDS( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tr
(separate octet)
==================================================================== */
#if 0
-static void get_QDP( tvbuff_t *tvb _U_, guint8 *offset _U_, proto_tree *iec104_header_tree _U_ )
+static void get_QDP(tvbuff_t *tvb _U_, guint8 *offset _U_, proto_tree *iec104_header_tree _U_)
{
/* todo */
@@ -641,10 +804,16 @@ static void get_QDP( tvbuff_t *tvb _U_, guint8 *offset _U_, proto_tree *iec104_h
/* ====================================================================
VTI: Value with transient state indication
==================================================================== */
-static void get_VTI( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree)
+static void get_VTI(tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree)
{
- proto_tree_add_item(iec104_header_tree, hf_vti, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
- proto_tree_add_item(iec104_header_tree, hf_vti_tr, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
+ proto_item* ti;
+ proto_tree* vti_tree;
+
+ ti = proto_tree_add_item(iec104_header_tree, hf_vti, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
+ vti_tree = proto_item_add_subtree(ti, ett_vti);
+
+ proto_tree_add_item(vti_tree, hf_vti_v, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(vti_tree, hf_vti_t, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
(*offset)++;
}
@@ -652,7 +821,7 @@ static void get_VTI( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tr
/* ====================================================================
NVA: Normalized value
==================================================================== */
-static void get_NVA( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_NVA(tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree)
{
/* Normalized value F16[1..16]<-1..+1-2^-15> */
proto_tree_add_item(iec104_header_tree, hf_asdu_normval, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
@@ -662,7 +831,7 @@ static void get_NVA( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tr
(*offset) += 2;
}
-static void get_NVAspt( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_NVAspt(tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree)
{
/* Normalized value F16[1..16]<-1..+1-2^-15> */
proto_tree_add_item(iec104_header_tree, hf_asdu_normval, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
@@ -675,18 +844,18 @@ static void get_NVAspt( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header
/* ====================================================================
SVA: Scaled value
==================================================================== */
-static void get_SVA( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_SVA(tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree)
{
/* Scaled value I16[1..16]<-2^15..+2^15-1> */
- proto_tree_add_item(iec104_header_tree, hf_asdu_normval, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(iec104_header_tree, hf_asdu_scalval, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
(*offset) += 2;
}
-static void get_SVAspt( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_SVAspt(tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree)
{
/* Scaled value I16[1..16]<-2^15..+2^15-1> */
- proto_tree_add_item(iec104_header_tree, hf_asdu_normval, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(iec104_header_tree, hf_asdu_scalval, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
(*offset) += 2;
}
@@ -694,7 +863,7 @@ static void get_SVAspt( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header
/* ====================================================================
"FLT": Short floating point number
==================================================================== */
-static void get_FLT( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_FLT(tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree)
{
/* -------- IEEE 754 float value */
proto_tree_add_item(iec104_header_tree, hf_asdu_float, tvb, *offset, 4, ENC_LITTLE_ENDIAN);
@@ -702,7 +871,7 @@ static void get_FLT( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tr
(*offset) += 4;
}
-static void get_FLTspt( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_FLTspt(tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree)
{
/* -------- IEEE 754 float value */
proto_tree_add_item(iec104_header_tree, hf_asdu_float, tvb, *offset, 4, ENC_LITTLE_ENDIAN);
@@ -713,14 +882,14 @@ static void get_FLTspt( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header
/* ====================================================================
"BSI": Binary state information, 32 bit
==================================================================== */
-static void get_BSI( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_BSI(tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree)
{
proto_tree_add_bits_item(iec104_header_tree, hf_asdu_bitstring, tvb, *offset*8, 32, ENC_BIG_ENDIAN);
(*offset) += 4;
}
-static void get_BSIspt( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_BSIspt(tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree)
{
proto_tree_add_bits_item(iec104_header_tree, hf_asdu_bitstring, tvb, *offset*8, 32, ENC_BIG_ENDIAN);
@@ -730,14 +899,13 @@ static void get_BSIspt( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header
/* ====================================================================
todo -- BCR: Binary counter reading
==================================================================== */
-/* void get_BCR( guint8 *offset,
- proto_tree *iec104_header_tree ); */
+/* void get_BCR(guint8 *offset, proto_tree *iec104_header_tree); */
/* ====================================================================
todo -- SEP: Single event of protection equipment
==================================================================== */
#if 0
-static void get_SEP( tvbuff_t *tvb _U_, guint8 *offset _U_, proto_tree *iec104_header_tree _U_ )
+static void get_SEP(tvbuff_t *tvb _U_, guint8 *offset _U_, proto_tree *iec104_header_tree _U_)
{
/* todo */
@@ -747,10 +915,16 @@ static void get_SEP( tvbuff_t *tvb _U_, guint8 *offset _U_, proto_tree *iec104_h
/* ====================================================================
QOS: Qualifier Of Set-point command
==================================================================== */
-static void get_QOS( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_QOS(tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree)
{
- proto_tree_add_item(iec104_header_tree, hf_qos_ql, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
- proto_tree_add_item(iec104_header_tree, hf_qos_se, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
+ proto_item* ti;
+ proto_tree* qos_tree;
+
+ ti = proto_tree_add_item(iec104_header_tree, hf_qos, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
+ qos_tree = proto_item_add_subtree(ti, ett_qos);
+
+ proto_tree_add_item(qos_tree, hf_qos_ql, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(qos_tree, hf_qos_se, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
(*offset)++;
}
@@ -758,13 +932,13 @@ static void get_QOS( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tr
/* ====================================================================
SCO: Single Command (IEV 371-03-02)
==================================================================== */
-static void get_SCO( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_SCO(tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree)
{
proto_item* ti;
proto_tree* sco_tree;
ti = proto_tree_add_item(iec104_header_tree, hf_sco, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
- sco_tree = proto_item_add_subtree( ti, ett_sco );
+ sco_tree = proto_item_add_subtree(ti, ett_sco);
proto_tree_add_item(sco_tree, hf_sco_on, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(sco_tree, hf_sco_qu, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
@@ -776,13 +950,13 @@ static void get_SCO( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tr
/* ====================================================================
DCO: Double Command (IEV 371-03-03)
==================================================================== */
-static void get_DCO( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_DCO(tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree)
{
proto_item* ti;
proto_tree* dco_tree;
ti = proto_tree_add_item(iec104_header_tree, hf_dco, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
- dco_tree = proto_item_add_subtree( ti, ett_dco );
+ dco_tree = proto_item_add_subtree(ti, ett_dco);
proto_tree_add_item(dco_tree, hf_dco_on, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(dco_tree, hf_dco_qu, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
@@ -794,13 +968,13 @@ static void get_DCO( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tr
/* ====================================================================
RCO: Regulating step command (IEV 371-03-13)
==================================================================== */
-static void get_RCO( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_RCO(tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree)
{
proto_item* ti;
proto_tree* rco_tree;
ti = proto_tree_add_item(iec104_header_tree, hf_rco, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
- rco_tree = proto_item_add_subtree( ti, ett_rco );
+ rco_tree = proto_item_add_subtree(ti, ett_rco);
proto_tree_add_item(rco_tree, hf_rco_up, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(rco_tree, hf_rco_qu, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
@@ -808,6 +982,33 @@ static void get_RCO( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tr
(*offset)++;
}
+
+/* ====================================================================
+ COI: Qualifier of interrogation
+ ==================================================================== */
+static void get_COI(tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree)
+{
+ proto_item* ti;
+ proto_tree* coi_tree;
+
+ ti = proto_tree_add_item(iec104_header_tree, hf_coi, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
+ coi_tree = proto_item_add_subtree(ti, ett_rco);
+
+ proto_tree_add_item(coi_tree, hf_coi_r, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(coi_tree, hf_coi_i, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
+
+ (*offset)++;
+}
+
+/* ====================================================================
+ QOI: Qualifier of interrogation
+ ==================================================================== */
+static void get_QOI(tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree)
+{
+ proto_tree_add_item(iec104_header_tree, hf_qoi, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
+
+ (*offset)++;
+}
/* .... end Misc. functions for dissection of signal values */
@@ -818,9 +1019,9 @@ static guint get_iec104apdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offse
guint8 Val;
guint32 Off;
- for (Off = 0; Off <= tvb_reported_length(tvb) - 2; Off++) {
+ for (Off = 0; Off <= tvb_reported_length(tvb) - 2; Off++) {
Val = tvb_get_guint8(tvb, offset + Off);
- if (Val == APCI_START) {
+ if (Val == APCI_START) {
return (guint)(Off + tvb_get_guint8(tvb, offset + Off + 1) + 2);
}
}
@@ -837,9 +1038,9 @@ static void dissect_iec104asdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tr
const char *cause_str;
size_t Ind;
struct asduheader asduh;
- proto_item *it104, *ioa_item;
+ proto_item *it104;
proto_tree *it104tree;
-
+ emem_strbuf_t * res;
guint8 offset = 0; /* byte offset, signal dissection */
guint8 offset_start_ioa = 0; /* position first ioa */
@@ -849,56 +1050,71 @@ static void dissect_iec104asdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tr
proto_tree * trSignal;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "104asdu");
- col_clear(pinfo->cinfo, COL_INFO);
it104 = proto_tree_add_item(tree, proto_iec104asdu, tvb, 0, -1, ENC_NA);
it104tree = proto_item_add_subtree(it104, ett_asdu);
+ res = ep_strbuf_new_label(NULL);
+
+ /* Type identification */
asduh.TypeId = tvb_get_guint8(tvb, 0);
proto_tree_add_item(it104tree, hf_typeid, tvb, 0, 1, ENC_LITTLE_ENDIAN);
+ asduh.DataLength = get_TypeIdLength(asduh.TypeId);
+
+ /* Variable structure qualifier */
Bytex = tvb_get_guint8(tvb, 1);
- asduh.NumIx = Bytex & 0x7F;
asduh.SQ = Bytex & F_SQ;
+ asduh.NumIx = Bytex & 0x7F;
+ proto_tree_add_item(it104tree, hf_sq, tvb, 1, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(it104tree, hf_numix, tvb, 1, 1, ENC_LITTLE_ENDIAN);
- if (asduh.NumIx > 1)
- proto_tree_add_item(it104tree, hf_sq, tvb, 1, 1, ENC_LITTLE_ENDIAN);
+
+ /* Cause of transmission */
asduh.TNCause = tvb_get_guint8(tvb, 2);
proto_tree_add_item(it104tree, hf_causetx, tvb, 2, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(it104tree, hf_nega, tvb, 2, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(it104tree, hf_test, tvb, 2, 1, ENC_LITTLE_ENDIAN);
+
+ /* Originator address */
asduh.OA = tvb_get_guint8(tvb, 3);
proto_tree_add_item(it104tree, hf_oa, tvb, 3, 1, ENC_LITTLE_ENDIAN);
+
+ /* Common address of ASDU */
asduh.Addr = tvb_get_letohs(tvb, 4);
proto_tree_add_item(it104tree, hf_addr, tvb, 4, 2, ENC_LITTLE_ENDIAN);
+
+ /* Information object address */
asduh.IOA = tvb_get_letoh24(tvb, 6);
- proto_tree_add_item(it104tree, hf_ioa, tvb, 6, 3, ENC_LITTLE_ENDIAN);
cause_str = val_to_str(asduh.TNCause & F_CAUSE, causetx_types, " <CauseTx=%u>");
- col_append_fstr( pinfo->cinfo, COL_INFO, "%u %s %u %s %s", asduh.Addr, pinfo->srcport == IEC104_PORT ? "->" : "<-",
- asduh.OA, val_to_str(asduh.TypeId, asdu_types, "<TypeId=%u>"), cause_str);
+
+ ep_strbuf_append_printf(res, "ASDU=%u %s %s", asduh.Addr, val_to_str(asduh.TypeId, asdu_types, "<TypeId=%u>"), cause_str);
+
if (asduh.TNCause & F_NEGA)
- col_append_str( pinfo->cinfo, COL_INFO, "_NEGA");
+ ep_strbuf_append(res, "_NEGA");
if (asduh.TNCause & F_TEST)
- col_append_str( pinfo->cinfo, COL_INFO, "_TEST");
+ ep_strbuf_append(res, "_TEST");
- if (asduh.TNCause & (F_TEST | F_NEGA)) {
+ if ((asduh.TNCause & (F_TEST | F_NEGA)) == 0) {
for (Ind=strlen(cause_str); Ind< 7; Ind++)
- col_append_str( pinfo->cinfo, COL_INFO, " ");
+ ep_strbuf_append(res, " ");
}
- col_append_fstr( pinfo->cinfo, COL_INFO, " IOA=%d", asduh.IOA);
- if (asduh.NumIx > 1) {
+ if (asduh.NumIx > 1) {
+ ep_strbuf_append_printf(res, " IOA[%d]=%d", asduh.NumIx, asduh.IOA);
if (asduh.SQ == F_SQ)
- col_append_fstr( pinfo->cinfo, COL_INFO, "-%d", asduh.IOA + asduh.NumIx - 1);
+ ep_strbuf_append_printf(res, "-%d", asduh.IOA + asduh.NumIx - 1);
else
- col_append_str( pinfo->cinfo, COL_INFO, ",...");
- col_append_fstr( pinfo->cinfo, COL_INFO, " (%u) ", asduh.NumIx);
+ ep_strbuf_append(res, ",...");
} else {
- col_append_str( pinfo->cinfo, COL_INFO, " ");
+ ep_strbuf_append_printf(res, " IOA=%d", asduh.IOA);
}
+ col_append_str(pinfo->cinfo, COL_INFO, res->str);
col_set_fence(pinfo->cinfo, COL_INFO);
+ /* 'ASDU Details': ROOT ITEM */
+ proto_item_append_text(it104, ": %s '%s'", res->str, Len >= ASDU_HEAD_LEN ? val_to_str_const(asduh.TypeId, asdu_lngtypes, "<Unknown TypeId>") : "");
+
/* 'Signal Details': TREE */
offset = 6; /* offset position after DUI, already stored in asduh struct */
/* -------- get signal value and status based on ASDU type id */
@@ -933,316 +1149,179 @@ static void dissect_iec104asdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tr
case C_SE_TB_1:
case C_SE_TC_1:
case C_BO_TA_1:
+ case M_EI_NA_1:
+ case C_IC_NA_1:
case C_CS_NA_1:
- /* create subtree for the signal values ... */
- itSignal = proto_tree_add_text(it104tree, tvb, offset, -1, "Object values");
- trSignal = proto_item_add_subtree( itSignal, ett_asdu_objects );
-
/* -- object values */
for(i = 0; i < asduh.NumIx; i++)
{
+ /* create subtree for the signal values ... */
+ itSignal = proto_tree_add_text(it104tree, tvb, offset, asduh.DataLength + 3, "IOA:s");
+ trSignal = proto_item_add_subtree(itSignal, ett_asdu_objects);
+
/* -------- First Information object address */
if (!i)
{
offset_start_ioa = offset;
/* -------- Information object address */
- asdu_info_obj_addr = asduh.IOA;
- ioa_item = proto_tree_add_uint(trSignal, hf_ioa, tvb, offset_start_ioa, 3, asdu_info_obj_addr);
/* check length */
- if( Len < (guint)(offset+3) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
+ if(Len < (guint)(offset + 3)) {
+ expert_add_info(pinfo, itSignal, &ei_iec104_short_asdu);
return;
}
- offset += 3; /* step over IOA bytes */
+ get_InfoObjectAddress(&asdu_info_obj_addr, tvb, &offset, trSignal);
} else {
/* -------- following Information object address depending on SQ */
if (asduh.SQ) /* <=> SQ=1, info obj addr = startaddr++ */
{
asdu_info_obj_addr++;
- ioa_item = proto_tree_add_uint(trSignal, hf_ioa, tvb, offset_start_ioa, 3, asdu_info_obj_addr);
+ proto_tree_add_uint(trSignal, hf_ioa, tvb, offset_start_ioa, 3, asdu_info_obj_addr);
} else { /* SQ=0, info obj addr given */
/* -------- Information object address */
/* check length */
- if( Len < (guint)(offset+3) ) {
+ if(Len < (guint)(offset + 3)) {
expert_add_info(pinfo, itSignal, &ei_iec104_short_asdu);
return;
}
- ioa_item = get_InfoObjectAddress( &asdu_info_obj_addr, tvb, &offset, trSignal);
-
+ get_InfoObjectAddress(&asdu_info_obj_addr, tvb, &offset, trSignal);
}
}
+ proto_item_set_text(itSignal, "IOA: %d", asdu_info_obj_addr);
+
+ /* check length */
+ if(Len < (guint)(offset + asduh.DataLength)) {
+ expert_add_info(pinfo, itSignal, &ei_iec104_short_asdu);
+ return;
+ }
+
switch (asduh.TypeId) {
case M_SP_NA_1: /* 1 Single-point information */
- /* check length */
- if( Len < (guint)(offset+1) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_SIQ( tvb, &offset, trSignal );
+ get_SIQ(tvb, &offset, trSignal);
break;
case M_DP_NA_1: /* 3 Double-point information */
- /* check length */
- if( Len < (guint)(offset+1) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_DIQ( tvb, &offset, trSignal );
+ get_DIQ(tvb, &offset, trSignal);
break;
case M_ST_NA_1: /* 5 Step position information */
- /* check length */
- if( Len < (guint)(offset+2) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_VTI( tvb, &offset, trSignal );
- get_QDS( tvb, &offset, trSignal );
+ get_VTI(tvb, &offset, trSignal);
+ get_QDS(tvb, &offset, trSignal);
break;
case M_BO_NA_1: /* 7 Bitstring of 32 bits */
- /* check length */
- if( Len < (guint)(offset+5) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_BSI( tvb, &offset, trSignal );
- get_QDS( tvb, &offset, trSignal );
+ get_BSI(tvb, &offset, trSignal);
+ get_QDS(tvb, &offset, trSignal);
break;
case M_ME_NA_1: /* 9 Measured value, normalized value */
- /* check length */
- if( Len < (guint)(offset+3) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_NVA( tvb, &offset, trSignal );
- get_QDS( tvb, &offset, trSignal );
+ get_NVA(tvb, &offset, trSignal);
+ get_QDS(tvb, &offset, trSignal);
break;
case M_ME_NB_1: /* 11 Measured value, scaled value */
- /* check length */
- if( Len < (guint)(offset+3) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_SVA( tvb, &offset, trSignal );
- get_QDS( tvb, &offset, trSignal );
+ get_SVA(tvb, &offset, trSignal);
+ get_QDS(tvb, &offset, trSignal);
break;
case M_ME_NC_1: /* 13 Measured value, short floating point value */
- /* check length */
- if( Len < (guint)(offset+5) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_FLT( tvb, &offset, trSignal );
- get_QDS( tvb, &offset, trSignal );
+ get_FLT(tvb, &offset, trSignal);
+ get_QDS(tvb, &offset, trSignal);
break;
case M_ME_ND_1: /* 21 Measured value, normalized value without quality descriptor */
- /* check length */
- if( Len < (guint)(offset+2) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_NVA( tvb, &offset, trSignal );
+ get_NVA(tvb, &offset, trSignal);
break;
case M_SP_TB_1: /* 30 Single-point information with time tag CP56Time2a */
- /* check length */
- if( Len < (guint)(offset+8) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_SIQ( tvb, &offset, trSignal );
- get_CP56Time( tvb, &offset, trSignal );
+ get_SIQ(tvb, &offset, trSignal);
+ get_CP56Time(tvb, &offset, trSignal);
break;
case M_DP_TB_1: /* 31 Double-point information with time tag CP56Time2a */
- /* check length */
- if( Len < (guint)(offset+8) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_DIQ( tvb, &offset, trSignal );
- get_CP56Time( tvb, &offset, trSignal );
+ get_DIQ(tvb, &offset, trSignal);
+ get_CP56Time(tvb, &offset, trSignal);
break;
case M_ST_TB_1: /* 32 Step position information with time tag CP56Time2a */
- /* check length */
- if( Len < (guint)(offset+9) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_VTI( tvb, &offset, trSignal );
- get_QDS( tvb, &offset, trSignal );
- get_CP56Time( tvb, &offset, trSignal );
+ get_VTI(tvb, &offset, trSignal);
+ get_QDS(tvb, &offset, trSignal);
+ get_CP56Time(tvb, &offset, trSignal);
break;
case M_BO_TB_1: /* 33 bitstring of 32 bit with time tag CP56Time2a */
- /* check length */
- if( Len < (guint)(offset+12) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_BSI( tvb, &offset, trSignal );
- get_QDS( tvb, &offset, trSignal );
- get_CP56Time( tvb, &offset, trSignal );
+ get_BSI(tvb, &offset, trSignal);
+ get_QDS(tvb, &offset, trSignal);
+ get_CP56Time(tvb, &offset, trSignal);
break;
case M_ME_TD_1: /* 34 Measured value, normalized value with time tag CP56Time2a */
- /* check length */
- if( Len < (guint)(offset+10) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_NVA( tvb, &offset, trSignal );
- get_QDS( tvb, &offset, trSignal );
- get_CP56Time( tvb, &offset, trSignal );
+ get_NVA(tvb, &offset, trSignal);
+ get_QDS(tvb, &offset, trSignal);
+ get_CP56Time(tvb, &offset, trSignal);
break;
case M_ME_TE_1: /* 35 Measured value, scaled value with time tag CP56Time2a */
- /* check length */
- if( Len < (guint)(offset+10) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_SVA( tvb, &offset, trSignal );
- get_QDS( tvb, &offset, trSignal );
- get_CP56Time( tvb, &offset, trSignal );
+ get_SVA(tvb, &offset, trSignal);
+ get_QDS(tvb, &offset, trSignal);
+ get_CP56Time(tvb, &offset, trSignal);
break;
case M_ME_TF_1: /* 36 Measured value, short floating point value with time tag CP56Time2a */
- /* check length */
- if( Len < (guint)(offset+12) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_FLT( tvb, &offset, trSignal );
- get_QDS( tvb, &offset, trSignal );
- get_CP56Time( tvb, &offset, trSignal );
+ get_FLT(tvb, &offset, trSignal);
+ get_QDS(tvb, &offset, trSignal);
+ get_CP56Time(tvb, &offset, trSignal);
break;
case C_SC_NA_1: /* 45 Single command */
- /* check length */
- if( Len < (guint)(offset+1) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_SCO( tvb, &offset, trSignal );
+ get_SCO(tvb, &offset, trSignal);
break;
case C_DC_NA_1: /* 46 Double command */
- /* check length */
- if( Len < (guint)(offset+1) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_DCO( tvb, &offset, trSignal );
+ get_DCO(tvb, &offset, trSignal);
break;
case C_RC_NA_1: /* 47 Regulating step command */
- /* check length */
- if( Len < (guint)(offset+1) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_RCO( tvb, &offset, trSignal );
+ get_RCO(tvb, &offset, trSignal);
break;
- case C_SE_NA_1: /* 48 Set point command, normalized value */
- /* check length */
- if( Len < (guint)(offset+3) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_NVAspt( tvb, &offset, trSignal );
- get_QOS( tvb, &offset, trSignal );
+ case C_SE_NA_1: /* 48 Set point command, normalized value */
+ get_NVAspt(tvb, &offset, trSignal);
+ get_QOS(tvb, &offset, trSignal);
break;
case C_SE_NB_1: /* 49 Set point command, scaled value */
- /* check length */
- if( Len < (guint)(offset+3) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_SVAspt( tvb, &offset, trSignal );
- get_QOS( tvb, &offset, trSignal );
+ get_SVAspt(tvb, &offset, trSignal);
+ get_QOS(tvb, &offset, trSignal);
break;
case C_SE_NC_1: /* 50 Set point command, short floating point value */
- /* check length */
- if( Len < (guint)(offset+5) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_FLTspt( tvb, &offset, trSignal );
- get_QOS( tvb, &offset, trSignal );
+ get_FLTspt(tvb, &offset, trSignal);
+ get_QOS(tvb, &offset, trSignal);
break;
case C_BO_NA_1: /* 51 Bitstring of 32 bits */
- /* check length */
- if( Len < (guint)(offset+4) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_BSIspt( tvb, &offset, trSignal );
- break;
+ get_BSIspt(tvb, &offset, trSignal);
+ break;
case C_SC_TA_1: /* 58 Single command with time tag CP56Time2a */
- /* check length */
- if( Len < (guint)(offset+8) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_SCO( tvb, &offset, trSignal );
- get_CP56Time( tvb, &offset, trSignal );
+ get_SCO(tvb, &offset, trSignal);
+ get_CP56Time(tvb, &offset, trSignal);
break;
case C_DC_TA_1: /* 59 Double command with time tag CP56Time2a */
- /* check length */
- if( Len < (guint)(offset+8) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_DCO( tvb, &offset, trSignal );
- get_CP56Time( tvb, &offset, trSignal );
+ get_DCO(tvb, &offset, trSignal);
+ get_CP56Time(tvb, &offset, trSignal);
break;
case C_RC_TA_1: /* 60 Regulating step command with time tag CP56Time2a */
- /* check length */
- if( Len < (guint)(offset+8) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_RCO( tvb, &offset, trSignal );
- get_CP56Time( tvb, &offset, trSignal );
+ get_RCO(tvb, &offset, trSignal);
+ get_CP56Time(tvb, &offset, trSignal);
break;
case C_SE_TA_1: /* 61 Set point command, normalized value with time tag CP56Time2a */
- /* check length */
- if( Len < (guint)(offset+10) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_NVAspt( tvb, &offset, trSignal );
- get_QOS( tvb, &offset, trSignal );
- get_CP56Time( tvb, &offset, trSignal );
+ get_NVAspt(tvb, &offset, trSignal);
+ get_QOS(tvb, &offset, trSignal);
+ get_CP56Time(tvb, &offset, trSignal);
break;
case C_SE_TB_1: /* 62 Set point command, scaled value with time tag CP56Time2a */
- /* check length */
- if( Len < (guint)(offset+10) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_SVAspt( tvb, &offset, trSignal );
- get_QOS( tvb, &offset, trSignal );
- get_CP56Time( tvb, &offset, trSignal );
+ get_SVAspt(tvb, &offset, trSignal);
+ get_QOS(tvb, &offset, trSignal);
+ get_CP56Time(tvb, &offset, trSignal);
break;
case C_SE_TC_1: /* 63 Set point command, short floating point value with time tag CP56Time2a */
- /* check length */
- if( Len < (guint)(offset+12) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_FLTspt( tvb, &offset, trSignal );
- get_QOS( tvb, &offset, trSignal );
- get_CP56Time( tvb, &offset, trSignal );
+ get_FLTspt(tvb, &offset, trSignal);
+ get_QOS(tvb, &offset, trSignal);
+ get_CP56Time(tvb, &offset, trSignal);
break;
case C_BO_TA_1: /* 64 Bitstring of 32 bits with time tag CP56Time2a */
- /* check length */
- if( Len < (guint)(offset+11) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_BSIspt( tvb, &offset, trSignal );
- get_CP56Time( tvb, &offset, trSignal );
+ get_BSIspt(tvb, &offset, trSignal);
+ get_CP56Time(tvb, &offset, trSignal);
+ break;
+ case M_EI_NA_1: /* 70 end of initialization */
+ get_COI(tvb, &offset, trSignal);
+ break;
+ case C_IC_NA_1: /* 100 interrogation command */
+ get_QOI(tvb, &offset, trSignal);
break;
case C_CS_NA_1: /* 103 clock synchronization command */
- /* check length */
- if( Len < (guint)(offset+7) ) {
- expert_add_info(pinfo, ioa_item, &ei_iec104_short_asdu);
- return;
- }
- get_CP56Time( tvb, &offset, trSignal );
+ get_CP56Time(tvb, &offset, trSignal);
break;
default:
@@ -1251,6 +1330,7 @@ static void dissect_iec104asdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tr
} /* end 'for(i = 0; i < dui.asdu_vsq_no_of_obj; i++)' */
break;
default:
+ proto_tree_add_item(it104tree, hf_ioa, tvb, offset, 3, ENC_LITTLE_ENDIAN);
break;
} /* end 'switch (asdu_typeid)' */
@@ -1262,89 +1342,99 @@ static void dissect_iec104asdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tr
static void dissect_iec104apci(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
guint TcpLen = tvb_reported_length(tvb);
- guint8 Start = 0, len, type = 0, temp8;
- guint8 temp16;
+ guint8 Start, len, type, temp8;
+ guint16 temp16;
guint Off;
proto_item *it104, *ti;
proto_tree *it104tree;
+ emem_strbuf_t * res;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "104apci");
- col_clear(pinfo->cinfo, COL_INFO);
it104 = proto_tree_add_item(tree, proto_iec104apci, tvb, 0, -1, ENC_NA);
it104tree = proto_item_add_subtree(it104, ett_apci);
- for (Off = 0; Off <= TcpLen - 2; Off++) {
+ res = ep_strbuf_new_label(NULL);
+
+ for (Off = 0; Off <= TcpLen - 2; Off++) {
Start = tvb_get_guint8(tvb, Off);
- if (Start == APCI_START) {
+ if (Start == APCI_START) {
if (Off > 0)
{
proto_tree_add_item(it104tree, hf_apcidata, tvb, 0, Off, ENC_NA);
- col_append_fstr( pinfo->cinfo, COL_INFO, "<ERR prefix %u bytes> ", Off);
+ ep_strbuf_append_printf(res, "<ERR prefix %u bytes> ", Off);
}
proto_item_set_len(it104, Off + APCI_LEN);
proto_tree_add_text(it104tree, tvb, Off, 1, "START");
ti = proto_tree_add_item(it104tree, hf_apdulen, tvb, Off + 1, 1, ENC_LITTLE_ENDIAN);
- proto_tree_add_item(it104tree, hf_apcitype, tvb, Off + 2, 1, ENC_LITTLE_ENDIAN);
-
+
len = tvb_get_guint8(tvb, Off + 1);
- if (len < APDU_MIN_LEN) {
+ if (len < APDU_MIN_LEN) {
expert_add_info_format_text(pinfo, ti, &ei_iec104_apdu_min_len, "APDU less than %d bytes", APDU_MIN_LEN);
- col_append_fstr( pinfo->cinfo, COL_INFO, "<ERR ApduLen=%u bytes> ", len);
+ ep_strbuf_append_printf(res, "<ERR ApduLen=%u bytes> ", len);
return;
}
temp8 = tvb_get_guint8(tvb, Off + 2);
- type = temp8 & 0x03;
+ if ((temp8 & 0x01) == 0)
+ type = 0;
+ else
+ type = temp8 & 0x03;
+
+ if (type == I_TYPE)
+ proto_tree_add_item(it104tree, hf_apcitype1, tvb, Off + 2, 1, ENC_LITTLE_ENDIAN);
+ else
+ proto_tree_add_item(it104tree, hf_apcitype2, tvb, Off + 2, 1, ENC_LITTLE_ENDIAN);
if (len <= APDU_MAX_LEN) {
- col_append_fstr( pinfo->cinfo, COL_INFO, "%s %s (",
+ ep_strbuf_append_printf(res, "%s %s (",
(pinfo->srcport == IEC104_PORT ? "->" : "<-"),
val_to_str_const(type, apci_types, "<ERR>"));
}
else {
- col_append_fstr( pinfo->cinfo, COL_INFO, "<ERR ApduLen=%u bytes> ", len);
+ ep_strbuf_append_printf(res, "<ERR ApduLen=%u bytes> ", len);
}
- switch(type) {
+ switch(type) {
case I_TYPE:
- case I_TYPE2:
temp16 = tvb_get_letohs(tvb, Off + 2) >> 1;
- col_append_fstr( pinfo->cinfo, COL_INFO, "%2.2d,", temp16);
+ ep_strbuf_append_printf(res, "%d,", temp16);
proto_tree_add_uint(it104tree, hf_apcitx, tvb, Off+2, 2, temp16);
case S_TYPE:
temp16 = tvb_get_letohs(tvb, Off + 4) >> 1;
- col_append_fstr( pinfo->cinfo, COL_INFO, "%2.2d) ", temp16);
+ ep_strbuf_append_printf(res, "%d) ", temp16);
proto_tree_add_uint(it104tree, hf_apcirx, tvb, Off+4, 2, temp16);
break;
case U_TYPE:
- col_append_fstr( pinfo->cinfo, COL_INFO, "%s) ", val_to_str_const((temp8 >> 2) & 0x3F, u_types, "<ERR>"));
+ ep_strbuf_append_printf(res, "%s) ", val_to_str_const((temp8 >> 2) & 0x3F, u_types, "<ERR>"));
proto_tree_add_item(it104tree, hf_apciutype, tvb, Off + 2, 1, ENC_LITTLE_ENDIAN);
break;
}
+
+ col_clear(pinfo->cinfo, COL_INFO);
+ col_append_sep_str(pinfo->cinfo, COL_INFO, " | ", res->str);
+ col_set_fence(pinfo->cinfo, COL_INFO);
+
+ proto_item_append_text(it104, ": %s", res->str);
+
+ if (type == I_TYPE)
+ call_dissector(iec104asdu_handle, tvb_new_subset(tvb, Off + APCI_LEN, -1, len - APCI_DATA_LEN), pinfo, tree);
+
/* Don't search more the APCI_START */
break;
}
}
- if (Start != APCI_START) {
+ if (Start != APCI_START) {
/* Everything is bad (no APCI found) */
proto_tree_add_item(it104tree, hf_apcidata, tvb, 0, Off, ENC_NA);
return;
}
- if ((type == I_TYPE) || (type == I_TYPE2)) {
- call_dissector(iec104asdu_handle, tvb_new_subset(tvb, Off + APCI_LEN, -1, len - APCI_DATA_LEN), pinfo, tree);
- } else {
- col_set_fence(pinfo->cinfo, COL_INFO);
- }
}
-
-
-
static void dissect_iec104reas(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
/* 5th parameter = 6 = minimum bytes received to calculate the length.
@@ -1354,19 +1444,21 @@ static void dissect_iec104reas(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tr
get_iec104apdu_len, dissect_iec104apci);
}
-
/* The protocol has two subprotocols: Register APCI */
void
proto_register_iec104apci(void)
{
-
static hf_register_info hf_ap[] = {
{ &hf_apdulen,
{ "ApduLen", "104apci.apdulen", FT_UINT8, BASE_DEC, NULL, 0x0,
"APDU Len", HFILL }},
- { &hf_apcitype,
+ { &hf_apcitype1,
+ { "Type", "104apci.type", FT_UINT8, BASE_HEX, VALS(apci_types), 0x01,
+ "APCI type", HFILL }},
+
+ { &hf_apcitype2,
{ "Type", "104apci.type", FT_UINT8, BASE_HEX, VALS(apci_types), 0x03,
"APCI type", HFILL }},
@@ -1398,7 +1490,6 @@ proto_register_iec104apci(void)
);
proto_register_field_array(proto_iec104apci, hf_ap, array_length(hf_ap));
proto_register_subtree_array(ett_ap, array_length(ett_ap));
-
}
@@ -1406,7 +1497,6 @@ proto_register_iec104apci(void)
void
proto_register_iec104asdu(void)
{
-
static hf_register_info hf_as[] = {
{ &hf_addr,
@@ -1433,7 +1523,6 @@ proto_register_iec104asdu(void)
{ "Test", "104asdu.test", FT_BOOLEAN, 8, NULL, F_TEST,
NULL, HFILL }},
-
{ &hf_ioa,
{ "IOA", "104asdu.ioa", FT_UINT24, BASE_DEC, NULL, 0x0,
"Information Object Address", HFILL }},
@@ -1450,13 +1539,49 @@ proto_register_iec104asdu(void)
{ "CP56Time", "104asdu.cp56time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0,
NULL, HFILL }},
+ { &hf_cp56time_ms,
+ { "MS", "104asdu.cp56time.ms", FT_UINT16, BASE_DEC, NULL, 0xFFFF,
+ "CP56Time milliseconds", HFILL }},
+
+ { &hf_cp56time_min,
+ { "Min", "104asdu.cp56time.min", FT_UINT8, BASE_DEC, NULL, 0x3F,
+ "CP56Time minutes", HFILL }},
+
+ { &hf_cp56time_iv,
+ { "IV", "104asdu.cp56time.iv", FT_BOOLEAN, 8, TFS(&tfs_invalid_valid), 0x80,
+ "CP56Time invalid", HFILL }},
+
+ { &hf_cp56time_hour,
+ { "Hour", "104asdu.cp56time.hour", FT_UINT8, BASE_DEC, NULL, 0x1F,
+ "CP56Time hours", HFILL }},
+
+ { &hf_cp56time_su,
+ { "SU", "104asdu.cp56time.su", FT_BOOLEAN, 8, TFS(&tfs_local_dst), 0x80,
+ "CP56Time summer time", HFILL }},
+
+ { &hf_cp56time_day,
+ { "Day", "104asdu.cp56time.day", FT_UINT8, BASE_DEC, NULL, 0x1F,
+ "CP56Time day", HFILL }},
+
+ { &hf_cp56time_dow,
+ { "DOW", "104asdu.cp56time.dow", FT_UINT8, BASE_DEC, NULL, 0xE0,
+ "CP56Time day of week", HFILL }},
+
+ { &hf_cp56time_month,
+ { "Month", "104asdu.cp56time.month", FT_UINT8, BASE_DEC, NULL, 0x0F,
+ "CP56Time month", HFILL }},
+
+ { &hf_cp56time_year,
+ { "Year", "104asdu.cp56time.year", FT_UINT8, BASE_DEC, NULL, 0x7F,
+ "CP56Time year", HFILL }},
+
{ &hf_siq,
{ "SIQ", "104asdu.siq", FT_UINT8, BASE_HEX, NULL, 0,
NULL, HFILL }},
- { &hf_siq_on,
- { "SQ", "104asdu.siq.on", FT_BOOLEAN, 8, TFS(&tfs_on_off), 0x01,
- "SIQ SQ", HFILL }},
+ { &hf_siq_spi,
+ { "SPI", "104asdu.siq.spi", FT_BOOLEAN, 8, TFS(&tfs_on_off), 0x01,
+ "SIQ SPI", HFILL }},
{ &hf_siq_bl,
{ "BL", "104asdu.siq.bl", FT_BOOLEAN, 8, TFS(&tfs_blocked_not_blocked), 0x10,
@@ -1478,9 +1603,9 @@ proto_register_iec104asdu(void)
{ "DIQ", "104asdu.diq", FT_UINT8, BASE_HEX, NULL, 0,
NULL, HFILL }},
- { &hf_diq_value,
- { "Value", "104asdu.diq.value", FT_UINT8, BASE_DEC, VALS(diq_types), 0x03,
- "DIQ Value", HFILL }},
+ { &hf_diq_dpi,
+ { "DPI", "104asdu.diq.dpi", FT_UINT8, BASE_DEC, VALS(diq_types), 0x03,
+ "DIQ DPI", HFILL }},
{ &hf_diq_bl,
{ "BL", "104asdu.diq.bl", FT_BOOLEAN, 8, TFS(&tfs_blocked_not_blocked), 0x10,
@@ -1523,81 +1648,108 @@ proto_register_iec104asdu(void)
"QDS IV", HFILL }},
{ &hf_vti,
- { "VTI", "104asdu.vti", FT_UINT8, BASE_DEC, NULL, 0x7F,
+ { "VTI", "104asdu.vti", FT_UINT8, BASE_HEX, NULL, 0,
NULL, HFILL }},
- { &hf_vti_tr,
- { "VTI Transient", "104asdu.vti.ov", FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x80,
+ { &hf_vti_v,
+ { "Value", "104asdu.vti.v", FT_UINT8, BASE_DEC, NULL, 0x7F,
+ "VTI Value", HFILL }},
+
+ { &hf_vti_t,
+ { "T", "104asdu.vti.t", FT_BOOLEAN, 8, TFS(&tfs_transient_not_transient), 0x80,
+ "VTI T", HFILL }},
+
+ { &hf_qos,
+ { "QOS", "104asdu.qos", FT_UINT8, BASE_HEX, NULL, 0,
NULL, HFILL }},
{ &hf_qos_ql,
- { "QOS Qualifier", "104asdu.qos_ql", FT_UINT8, BASE_DEC, NULL, 0x7F,
- NULL, HFILL }},
+ { "QL", "104asdu.qos.ql", FT_UINT8, BASE_DEC, NULL, 0x7F,
+ "QOS QL", HFILL }},
{ &hf_qos_se,
- { "QOS S/E", "104asdu.qos_se", FT_BOOLEAN, 8, TFS(&tfs_select_execute), 0x80,
- NULL, HFILL }},
+ { "S/E", "104asdu.qos.se", FT_BOOLEAN, 8, TFS(&tfs_select_execute), 0x80,
+ "QOS S/E", HFILL }},
{ &hf_sco,
{ "SCO", "104asdu.sco", FT_UINT8, BASE_HEX, NULL, 0,
NULL, HFILL }},
{ &hf_sco_on,
- { "SCO ON/OFF", "104asdu.sco.on", FT_BOOLEAN, 8, TFS(&tfs_on_off), 0x01,
- NULL, HFILL }},
+ { "ON/OFF", "104asdu.sco.on", FT_BOOLEAN, 8, TFS(&tfs_on_off), 0x01,
+ "SCO SCS", HFILL }},
{ &hf_sco_qu,
- { "SCO QU", "104asdu.sco.qu", FT_UINT8, BASE_DEC, VALS(qos_qu_types), 0x7C,
- NULL, HFILL }},
+ { "QU", "104asdu.sco.qu", FT_UINT8, BASE_DEC, VALS(qos_qu_types), 0x7C,
+ "SCO QU", HFILL }},
{ &hf_sco_se,
- { "SCO S/E", "104asdu.sco.se", FT_BOOLEAN, 8, TFS(&tfs_select_execute), 0x80,
- NULL, HFILL }},
+ { "S/E", "104asdu.sco.se", FT_BOOLEAN, 8, TFS(&tfs_select_execute), 0x80,
+ "SCO S/E", HFILL }},
{ &hf_dco,
{ "DCO", "104asdu.dco", FT_UINT8, BASE_HEX, NULL, 0,
NULL, HFILL }},
{ &hf_dco_on,
- { "DCO ON/OFF", "104asdu.dco.on", FT_UINT8, BASE_DEC, VALS(dco_on_types), 0x03,
- NULL, HFILL }},
+ { "ON/OFF", "104asdu.dco.on", FT_UINT8, BASE_DEC, VALS(dco_on_types), 0x03,
+ "DCO DCS", HFILL }},
{ &hf_dco_qu,
- { "DCO QU", "104asdu.dco.qu", FT_UINT8, BASE_DEC, VALS(qos_qu_types), 0x7C,
- NULL, HFILL }},
+ { "QU", "104asdu.dco.qu", FT_UINT8, BASE_DEC, VALS(qos_qu_types), 0x7C,
+ "DCO QU", HFILL }},
{ &hf_dco_se,
- { "DCO S/E", "104asdu.dco.se", FT_BOOLEAN, 8, TFS(&tfs_select_execute), 0x80,
- NULL, HFILL }},
+ { "S/E", "104asdu.dco.se", FT_BOOLEAN, 8, TFS(&tfs_select_execute), 0x80,
+ "DCO S/E", HFILL }},
{ &hf_rco,
{ "RCO", "104asdu.rco", FT_UINT8, BASE_HEX, NULL, 0,
NULL, HFILL }},
{ &hf_rco_up,
- { "RCO UP/DOWN", "104asdu.rco.up", FT_UINT8, BASE_DEC, VALS(rco_up_types), 0x03,
- NULL, HFILL }},
+ { "UP/DOWN", "104asdu.rco.up", FT_UINT8, BASE_DEC, VALS(rco_up_types), 0x03,
+ "RCO RCS", HFILL }},
{ &hf_rco_qu,
- { "RCO QU", "104asdu.rco.qu", FT_UINT8, BASE_DEC, VALS(qos_qu_types), 0x7C,
- NULL, HFILL }},
+ { "QU", "104asdu.rco.qu", FT_UINT8, BASE_DEC, VALS(qos_qu_types), 0x7C,
+ "RCO QU", HFILL }},
{ &hf_rco_se,
- { "RCO S/E", "104asdu.rco.se", FT_BOOLEAN, 8, TFS(&tfs_select_execute), 0x80,
+ { "S/E", "104asdu.rco.se", FT_BOOLEAN, 8, TFS(&tfs_select_execute), 0x80,
+ "RCO S/E", HFILL }},
+
+ { &hf_coi,
+ { "COI", "104asdu.coi", FT_UINT8, BASE_HEX, NULL, 0,
+ NULL, HFILL }},
+
+ { &hf_coi_r,
+ { "R", "104asdu.coi_r", FT_UINT8, BASE_DEC, VALS(coi_r_types), 0x7F,
+ "COI R", HFILL }},
+
+ { &hf_coi_i,
+ { "I", "104asdu.coi_i", FT_BOOLEAN, 8, TFS(&tfs_coi_i), 0x80,
+ "COI I", HFILL }},
+
+ { &hf_qoi,
+ { "QOI", "104asdu.qoi", FT_UINT8, BASE_DEC, VALS(qoi_r_types), 0,
NULL, HFILL }},
{ &hf_asdu_bitstring,
- { "Object value", "104asdu.bitstring", FT_UINT32, BASE_HEX, NULL, 0x0,
- NULL, HFILL }},
+ { "Value", "104asdu.bitstring", FT_UINT32, BASE_HEX, NULL, 0x0,
+ "BSI value", HFILL }},
{ &hf_asdu_float,
- { "Object value", "104asdu.float", FT_FLOAT, BASE_NONE, NULL, 0x0,
- NULL, HFILL }},
+ { "Value", "104asdu.float", FT_FLOAT, BASE_NONE, NULL, 0x0,
+ "Float value", HFILL }},
{ &hf_asdu_normval,
- { "Object value", "104asdu.normval", FT_INT16, BASE_DEC, NULL, 0x0,
- NULL, HFILL }},
+ { "Value", "104asdu.normval", FT_INT16, BASE_DEC, NULL, 0x0,
+ "Normalised value", HFILL }},
+ { &hf_asdu_scalval,
+ { "Value", "104asdu.scalval", FT_INT16, BASE_DEC, NULL, 0x0,
+ "Scaled value", HFILL }},
};
static gint *ett_as[] = {
@@ -1606,9 +1758,12 @@ proto_register_iec104asdu(void)
&ett_siq,
&ett_diq,
&ett_qds,
+ &ett_qos,
+ &ett_vti,
&ett_sco,
&ett_dco,
- &ett_rco
+ &ett_rco,
+ &ett_cp56time
};
static ei_register_info ei[] = {
@@ -1623,11 +1778,11 @@ proto_register_iec104asdu(void)
"104asdu",
"104asdu"
);
+
proto_register_field_array(proto_iec104asdu, hf_as, array_length(hf_as));
proto_register_subtree_array(ett_as, array_length(ett_as));
expert_iec104 = expert_register_protocol(proto_iec104asdu);
expert_register_field_array(expert_iec104, ei, array_length(ei));
-
}