aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-iec104.c
diff options
context:
space:
mode:
authorMichael Mann <mmann78@netscape.net>2013-04-21 23:20:10 +0000
committerMichael Mann <mmann78@netscape.net>2013-04-21 23:20:10 +0000
commit8591b0b374c5ec9bbb676bc38fd6a862e8c654d9 (patch)
treeb6cfab4fa8f68879f4e1547782e48a56f2a6b690 /epan/dissectors/packet-iec104.c
parent2b9db8a7d45c875f74c37106b787b1f11d3a988c (diff)
General cleanup.
Converted to proto_tree_add_text to proto_tree_add_item/expert_info Allow columns/tree/(sub)dissectors/expert_info to be called at all of the proper times. COL_INFO data still seems a bit verbose when errors occur, but I left it alone, just cleaning up the sequence of events. Removed some structure definitions where the variables that used them were effectively "useless" once proto_tree_add_item was added (although they weren't that useful before that) svn path=/trunk/; revision=48958
Diffstat (limited to 'epan/dissectors/packet-iec104.c')
-rw-r--r--epan/dissectors/packet-iec104.c1320
1 files changed, 597 insertions, 723 deletions
diff --git a/epan/dissectors/packet-iec104.c b/epan/dissectors/packet-iec104.c
index bdd0e8dc1d..2c6c4dbfb2 100644
--- a/epan/dissectors/packet-iec104.c
+++ b/epan/dissectors/packet-iec104.c
@@ -37,6 +37,7 @@
#include <math.h> /* floor */
#include <epan/packet.h>
+#include <epan/expert.h>
#include <epan/dissectors/packet-tcp.h>
#include <epan/emem.h>
@@ -48,8 +49,7 @@ static dissector_handle_t iec104asdu_handle;
/* the asdu header structure */
struct asduheader {
- guint8 AddrLow;
- guint8 AddrHigh;
+ guint16 Addr;
guint8 OA;
guint8 TypeId;
guint8 TNCause;
@@ -58,65 +58,6 @@ struct asduheader {
guint8 SQ;
};
-/* the apci header structure */
-struct apciheader {
- guint8 ApduLen;
- guint8 Type;
- guint8 UType;
- guint16 Tx;
- guint16 Rx;
-};
-
-/* asdu value time stamp structure */
-typedef struct
-{
- guint16 cp56t_ms;
- guint8 cp56t_s;
- guint8 cp56t_min;
- guint8 cp56t_h;
- guint8 cp56t_dom; /* day of month */
- guint8 cp56t_dow; /* day of week */
- guint8 cp56t_month;
- guint8 cp56t_year;
-
- gboolean IV; /* Invalid (1) */
-
-
-} td_CP56Time;
-
-/* asdu value/status structure */
-typedef struct {
- union {
- guint8 VTI; /* Value w transient state indication, */
- /* CP8: value I7[1..7]<-64..+63>, */
- /* Transient BS1[8]<0..1>0: eq. not in transient state, 1: in trans ... */
- gint16 NVA; /* Normalized value F16[1..16]<-1..+1-2^-15> */
- gint16 SVA; /* Scaled value I16[1..16]<-2^15..+2^15-1> */
- gfloat FLT; /* IEEE 754 float value R32.23{Fraction,Exponent,Sign} */
- /* ToDo -- BCR Binary counter reading */
- } MV; /* Measured Value */
-
- /* together with VTI */
- gboolean TRANSIENT; /* equipment is in transient state */
-
- /* boolean values */
- gboolean IPOS0; /* double-point: indeterminate or intermediate state */
- gboolean OFF;
- gboolean ON;
- gboolean IPOS3; /* double-point: indeterminate state (fault?) */
-
- /* quality descriptor-bits */
- gboolean BL; /* Blocked (1) */
- gboolean SB; /* Substituted (1) */
- gboolean NT; /* Topical (0) / Not topical (1) [Topical <=> if most recent update was successful] */
- gboolean IV; /* Invalid (1) */
- /* from separat quality descriptor */
- gboolean OV; /* Overflow (1) */
- /* from separate quality descriptor */
- gboolean EI; /* Elapsed time valid (0) / Elapsed time invalid (1) */
-
-} td_ValueInfo;
-
/* asdu command value/status structure */
typedef struct {
gboolean OFF;
@@ -136,24 +77,7 @@ typedef struct {
} td_CmdInfo;
-/* asdu setpoint value/status structure */
-typedef struct {
- union {
- gint16 NVA; /* Normalized value F16[1..16]<-1..+1-2^-15> */
- gint16 SVA; /* Scaled value I16[1..16]<-2^15..+2^15-1> */
- gfloat FLT; /* IEEE 754 float value R32.23{Fraction,Exponent,Sign} */
- } SP; /* Measured Value */
-
- /* QOS qualifier-bits */
- guint8 QL; /* UI7[1..7]<0..127>; 0-default, 1..63-reserved for strd def., */
- /* 64..127-reserved for special use (private range) */
- gboolean SE; /* Select (1) / Execute (0) */
-
-} td_SpInfo;
-
-
-
-static guint iec104port = 2404;
+#define IEC104_PORT 2404
/* Define the iec104 proto */
static int proto_iec104apci = -1;
@@ -175,13 +99,17 @@ static int proto_iec104asdu = -1;
#define F_SQ 0x80
/* APCI types */
+
+/* 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 }
};
@@ -460,11 +388,54 @@ static const value_string causetx_types [] = {
{ 0, NULL }
};
+static const value_string diq_types[] = {
+ { 0, "IPOS0" },
+ { 1, "OFF" },
+ { 2, "ON" },
+ { 3, "IPOS3" },
+ { 0, NULL }
+};
+
+static const value_string qos_qu_types[] = {
+ { 0, "No pulse defined" },
+ { 1, "Short Pulse" },
+ { 2, "Long Pulse" },
+ { 3, "Persistent Output" },
+ { 0, NULL }
+};
+
+static const value_string dco_on_types[] = {
+ { 0, "(None)" },
+ { 1, "OFF" },
+ { 2, "ON" },
+ { 3, "Error: On/Off not defined" },
+ { 0, NULL }
+};
+
+static const value_string rco_up_types[] = {
+ { 0, "(None)" },
+ { 1, "DOWN" },
+ { 2, "UP" },
+ { 3, "Error: Up/Down not defined" },
+ { 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_overflow_no_overflow = { "Overflow", "No overflow" };
+static const true_false_string tfs_select_execute = { "Select", "Execute" };
/* Protocol fields to be filtered */
static int hf_apdulen = -1;
static int hf_apcitype = -1;
-static int hf_apciutype = -1;
+static int hf_apciutype = -1;
+static int hf_apcitx = -1;
+static int hf_apcirx = -1;
+static int hf_apcidata = -1;
static int hf_addr = -1;
static int hf_oa = -1;
@@ -475,6 +446,41 @@ static int hf_test = -1;
static int hf_ioa = -1;
static int hf_numix = -1;
static int hf_sq = -1;
+static int hf_cp56time = -1;
+static int hf_siq = -1;
+static int hf_siq_on = -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_bl = -1;
+static int hf_diq_sb = -1;
+static int hf_diq_nt = -1;
+static int hf_diq_iv = -1;
+static int hf_qds = -1;
+static int hf_qds_ov = -1;
+static int hf_qds_bl = -1;
+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_qos_ql = -1;
+static int hf_qos_se = -1;
+static int hf_sco = -1;
+static int hf_sco_on = -1;
+static int hf_sco_qu = -1;
+static int hf_sco_se = -1;
+static int hf_dco = -1;
+static int hf_dco_on = -1;
+static int hf_dco_qu = -1;
+static int hf_dco_se = -1;
+static int hf_rco = -1;
+static int hf_rco_up = -1;
+static int hf_rco_qu = -1;
+static int hf_rco_se = -1;
static gint hf_asdu_bitstring = -1;
static gint hf_asdu_float = -1;
@@ -482,6 +488,13 @@ static gint hf_asdu_normval = -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_qds = -1;
+static gint ett_sco = -1;
+static gint ett_dco = -1;
+static gint ett_rco = -1;
/* Misc. functions for dissection of signal values */
@@ -492,44 +505,41 @@ static gint ett_asdu = -1;
that starts 'offset' bytes in 'tvb'.
The time and date is put in struct 'cp56t'
==================================================================== */
-static void get_CP56Time( td_CP56Time *cp56t, 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;
+ struct tm tm;
+ nstime_t datetime;
+ proto_item* ti;
+
ms = tvb_get_letohs( tvb , *offset );
(*offset) += 2;
- cp56t->cp56t_s = ms / 1000;
- cp56t->cp56t_ms = ms % 1000;
+ tm.tm_sec = ms / 1000;
+ datetime.nsecs = ms * 1000000;
- cp56t->cp56t_min = tvb_get_guint8(tvb, *offset);
+ tm.tm_min = tvb_get_guint8(tvb, *offset);
/* "Invalid" -- Todo: test */
- cp56t->IV = cp56t->cp56t_min & 0x80;
+ valid = tm.tm_min & 0x80;
- cp56t->cp56t_min = cp56t->cp56t_min & 0x3F;
+ tm.tm_min &= 0x3F;
(*offset)++;
- cp56t->cp56t_h = 0x1F & tvb_get_guint8(tvb, *offset);
+ tm.tm_hour = 0x1F & tvb_get_guint8(tvb, *offset);
(*offset)++;
- cp56t->cp56t_dom = tvb_get_guint8(tvb, *offset);
- cp56t->cp56t_dow = 0xE0 & cp56t->cp56t_dom;
- cp56t->cp56t_dow >>= 5;
- cp56t->cp56t_dom = cp56t->cp56t_dom & 0x1F;
+ tm.tm_mday = tvb_get_guint8(tvb, *offset) & 0x1F;
(*offset)++;
- cp56t->cp56t_month = 0x0F & tvb_get_guint8(tvb, *offset);
+ tm.tm_mon = 0x0F & tvb_get_guint8(tvb, *offset);
(*offset)++;
- cp56t->cp56t_year = 0x7F & tvb_get_guint8(tvb, *offset);
+ tm.tm_year = 0x7F & tvb_get_guint8(tvb, *offset);
(*offset)++;
+ tm.tm_isdst = -1; /* there's no info on whether DST was in force; assume it's
+ * the same as currently */
- if( iec104_header_tree != NULL )
- {
- /* ---- format yy-mm-dd (dow) hh:mm:ss.ms */
- proto_tree_add_text(iec104_header_tree, tvb, (*offset)-7, 7,
- "%.2d-%.2d-%.2d (%d) %.2d:%.2d:%.2d.%.3d (%s)",
- cp56t->cp56t_year,cp56t->cp56t_month,cp56t->cp56t_dom,
- cp56t->cp56t_dow,cp56t->cp56t_h,cp56t->cp56t_min,
- cp56t->cp56t_s,cp56t->cp56t_ms,cp56t->IV?"Invalid":"Valid");
- }
-
+ 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");
}
@@ -537,17 +547,16 @@ static void get_CP56Time( td_CP56Time *cp56t, tvbuff_t *tvb, guint8 *offset, pro
Information object address (Identifier)
ASDU -> Inform Object #1 -> Information object address
==================================================================== */
-static void 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;
+
/* -------- Information object address */
*asdu_info_obj_addr = tvb_get_letoh24(tvb, *offset);
- if( iec104_header_tree != NULL )
- {
- proto_tree_add_uint(iec104_header_tree, hf_ioa,
- tvb, *offset, 3, *asdu_info_obj_addr);
-
- }
+ ti = proto_tree_add_item(iec104_header_tree, hf_ioa, tvb, *offset, 3, ENC_LITTLE_ENDIAN);
(*offset) += 3;
+
+ return ti;
}
@@ -556,25 +565,19 @@ static void get_InfoObjectAddress( guint32 *asdu_info_obj_addr, tvbuff_t *tvb, g
/* ====================================================================
SIQ: Single-point information (IEV 371-02-07) w quality descriptor
==================================================================== */
-static void get_SIQ( td_ValueInfo *value, tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_SIQ( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
{
- guint8 siq;
- siq = tvb_get_guint8(tvb, *offset);
-
- value->ON = siq & 0x01;
- value->OFF = !(value->ON);
- value->BL = siq & 0x10; /* Blocked (1) */
- value->SB = siq & 0x20; /* Substituted (1) */
- value->NT = siq & 0x40; /* Topical (0) / Not topical (1) */
- /* [Topical <=> if most recent update was successful] */
- value->IV = siq & 0x80; /* Invalid (1) */
- if( iec104_header_tree != NULL )
- {
- proto_tree_add_text( iec104_header_tree, tvb, *offset, 1, "Value: %s - Status: %s, %s, %s, %s",
- value->ON?"ON":"OFF", value->BL?"Blocked":"Not blocked",
- value->SB?"Substituted":"Not Substituted", value->NT?"Not Topical":"Topical",
- value->IV?"Invalid":"Valid" );
- }
+ 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 );
+
+ proto_tree_add_item(siq_tree, hf_siq_on, 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);
+ proto_tree_add_item(siq_tree, hf_siq_iv, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
(*offset)++;
@@ -584,45 +587,19 @@ static void get_SIQ( td_ValueInfo *value, tvbuff_t *tvb, guint8 *offset, proto_t
/* ====================================================================
DIQ: Double-point information (IEV 371-02-08) w quality descriptor
==================================================================== */
-static void get_DIQ( td_ValueInfo *value, 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 );
- guint8 diq;
- diq = tvb_get_guint8(tvb, *offset);
- value->IPOS0 = FALSE;
- value->OFF = FALSE;
- value->ON = FALSE;
- value->IPOS3 = FALSE;
- switch ( diq & 0x03 )
- {
- case 0:
- value->IPOS0 = TRUE;
- break;
- case 1:
- value->OFF = TRUE;
- break;
- case 2:
- value->ON = TRUE;
- break;
- case 3:
- value->IPOS3 = TRUE;
- break;
- default:
- break;
- }
- value->BL = diq & 0x10; /* Blocked (1) */
- value->SB = diq & 0x20; /* Substituted (1) */
- value->NT = diq & 0x40; /* Topical (0) / Not topical (1) */
- /* [Topical <=> if most recent update was successful] */
- value->IV = diq & 0x80; /* Invalid (1) */
-
- if( iec104_header_tree != NULL )
- {
- proto_tree_add_text( iec104_header_tree, tvb, *offset, 1, "Value: %s%s%s%s - Status: %s, %s, %s, %s",
- value->ON?"ON":"", value->OFF?"OFF":"", value->IPOS0?"IPOS0":"", value->IPOS3?"IPOS3":"",
- value->BL?"Blocked":"Not blocked", value->SB?"Substituted":"Not Substituted",
- value->NT?"Not Topical":"Topical", value->IV?"Invalid":"Valid" );
- }
+ proto_tree_add_item(diq_tree, hf_diq_value, 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)++;
@@ -631,25 +608,19 @@ static void get_DIQ( td_ValueInfo *value, tvbuff_t *tvb, guint8 *offset, proto_t
/* ====================================================================
QDS: Quality descriptor (separate octet)
==================================================================== */
-static void get_QDS( td_ValueInfo *value, tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_QDS( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
{
- guint8 qds;
- /* -------- QDS quality description */
- qds = tvb_get_guint8(tvb, *offset);
-
- value->OV = qds & 0x01; /* Overflow (1) */
- value->BL = qds & 0x10; /* Blocked (1) */
- value->SB = qds & 0x20; /* Substituted (1) */
- value->NT = qds & 0x40; /* Topical (0) / Not topical (1) */
- /* [Topical <=> if most recent update was successful] */
- value->IV = qds & 0x80; /* Invalid (1) */
- if( iec104_header_tree != NULL )
- {
- proto_tree_add_text( iec104_header_tree, tvb, *offset, 1, "Status: %s, %s, %s, %s, %s",
- value->OV?"Overflow!":"No Overflow", value->BL?"Blocked!":"Not Blocked",
- value->SB?"Substituted!":"Not Substituted", value->NT?"Not Topical!":"Topical",
- value->IV?"Invalid!":"Valid" );
- }
+ 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 );
+
+ 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);
+ proto_tree_add_item(qds_tree, hf_qds_sb, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(qds_tree, hf_qds_nt, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(qds_tree, hf_qds_iv, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
(*offset)++;
@@ -660,7 +631,7 @@ static void get_QDS( td_ValueInfo *value, tvbuff_t *tvb, guint8 *offset, proto_t
(separate octet)
==================================================================== */
#if 0
-static void get_QDP( td_ValueInfo *value _U_, 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 */
@@ -670,19 +641,10 @@ static void get_QDP( td_ValueInfo *value _U_, tvbuff_t *tvb _U_, guint8 *offset
/* ====================================================================
VTI: Value with transient state indication
==================================================================== */
-static void get_VTI( td_ValueInfo *value _U_, tvbuff_t *tvb _U_, guint8 *offset _U_, proto_tree *iec104_header_tree _U_ )
+static void get_VTI( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree)
{
- guint8 vti;
- vti = tvb_get_guint8(tvb, *offset);
-
- value->MV.VTI= vti & 0x7F;
- value->TRANSIENT = (vti & 0x80) != 0;
-
- if( iec104_header_tree != NULL )
- {
- proto_tree_add_text( iec104_header_tree, tvb, *offset, 1, "Value: %d - Status: %s",
- value->MV.VTI, value->TRANSIENT?"Transient":"Not transient" );
- }
+ 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);
(*offset)++;
}
@@ -690,233 +652,124 @@ static void get_VTI( td_ValueInfo *value _U_, tvbuff_t *tvb _U_, guint8 *offset
/* ====================================================================
NVA: Normalized value
==================================================================== */
-static void get_NVA( td_ValueInfo *value, 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> */
- value->MV.NVA = tvb_get_letohs(tvb, *offset);
+ proto_tree_add_item(iec104_header_tree, hf_asdu_normval, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
- if ( iec104_header_tree != NULL )
- {
- proto_tree_add_int(iec104_header_tree, hf_asdu_normval,
- tvb, *offset, 2, value->MV.NVA);
- /* todo ... presentation as float +/- 1 (val/32767) ... */
- }
- (*offset) += 2;
+ /* todo ... presentation as float +/- 1 (val/32767) ... */
+ (*offset) += 2;
}
-static void get_NVAspt( td_SpInfo *spt, 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> */
- spt->SP.NVA = tvb_get_letohs(tvb, *offset);
+ proto_tree_add_item(iec104_header_tree, hf_asdu_normval, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
- if ( iec104_header_tree != NULL )
- {
- proto_tree_add_int(iec104_header_tree, hf_asdu_normval,
- tvb, *offset, 2, spt->SP.NVA);
- /* todo ... presentation as float +/- 1 */
- }
- (*offset) += 2;
+ /* todo ... presentation as float +/- 1 */
+ (*offset) += 2;
}
/* ====================================================================
SVA: Scaled value
==================================================================== */
-static void get_SVA( td_ValueInfo *value, 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> */
- value->MV.SVA = tvb_get_letohs(tvb, *offset);
- if ( iec104_header_tree != NULL )
- {
- proto_tree_add_int(iec104_header_tree, hf_asdu_normval,
- tvb, *offset, 2, value->MV.SVA);
- }
- (*offset) += 2;
+ proto_tree_add_item(iec104_header_tree, hf_asdu_normval, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
+ (*offset) += 2;
}
-static void get_SVAspt( td_SpInfo *spt, 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> */
- spt->SP.SVA = tvb_get_letohs(tvb, *offset);
- if ( iec104_header_tree != NULL )
- {
- proto_tree_add_int(iec104_header_tree, hf_asdu_normval,
- tvb, *offset, 2, spt->SP.SVA);
- }
- (*offset) += 2;
+ proto_tree_add_item(iec104_header_tree, hf_asdu_normval, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
+ (*offset) += 2;
}
/* ====================================================================
"FLT": Short floating point number
==================================================================== */
-static void get_FLT( td_ValueInfo *value, 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 */
- value->MV.FLT = tvb_get_letohieee_float(tvb, *offset);
-
- if ( iec104_header_tree != NULL )
- {
- proto_tree_add_float(iec104_header_tree, hf_asdu_float,
- tvb, *offset, 4, value->MV.FLT);
- }
- (*offset) += 4;
-
+ /* -------- IEEE 754 float value */
+ proto_tree_add_item(iec104_header_tree, hf_asdu_float, tvb, *offset, 4, ENC_LITTLE_ENDIAN);
+ (*offset) += 4;
}
-static void get_FLTspt( td_SpInfo *spt, 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 */
- spt->SP.FLT = tvb_get_letohieee_float(tvb, *offset);
-
- if ( iec104_header_tree != NULL )
- {
- proto_tree_add_float(iec104_header_tree, hf_asdu_float,
- tvb, *offset, 4, spt->SP.FLT);
- }
- (*offset) += 4;
-
+ /* -------- IEEE 754 float value */
+ proto_tree_add_item(iec104_header_tree, hf_asdu_float, tvb, *offset, 4, ENC_LITTLE_ENDIAN);
+ (*offset) += 4;
}
/* ====================================================================
"BSI": Binary state information, 32 bit
==================================================================== */
-static void get_BSI( td_ValueInfo *value _U_, tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_BSI( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
{
- if ( iec104_header_tree != NULL )
- {
- proto_tree_add_bits_item(iec104_header_tree, hf_asdu_bitstring,
- tvb, *offset*8, 32, ENC_BIG_ENDIAN);
- }
- (*offset) += 4;
+ proto_tree_add_bits_item(iec104_header_tree, hf_asdu_bitstring, tvb, *offset*8, 32, ENC_BIG_ENDIAN);
+ (*offset) += 4;
}
-static void get_BSIspt( td_ValueInfo *value _U_, tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_BSIspt( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
{
- if ( iec104_header_tree != NULL )
- {
- proto_tree_add_bits_item(iec104_header_tree, hf_asdu_bitstring,
- tvb, *offset*8, 32, ENC_BIG_ENDIAN);
- }
- (*offset) += 4;
+ proto_tree_add_bits_item(iec104_header_tree, hf_asdu_bitstring, tvb, *offset*8, 32, ENC_BIG_ENDIAN);
+ (*offset) += 4;
}
/* ====================================================================
todo -- BCR: Binary counter reading
==================================================================== */
-/* void get_BCR( td_ValueInfo *value, tvbuff_t *tvb, guint8 *offset,
+/* void get_BCR( guint8 *offset,
proto_tree *iec104_header_tree ); */
/* ====================================================================
todo -- SEP: Single event of protection equipment
==================================================================== */
#if 0
-static void get_SEP( td_ValueInfo *value _U_, 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 */
+ /* todo */
}
#endif
/* ====================================================================
- QOC: Qualifier Of Command
- ==================================================================== */
-static void get_QOC( td_CmdInfo *value, guint8 data )
-{
- value->ZeroP = FALSE; /* No pulse */
- value->ShortP = FALSE; /* Short Pulse */
- value->LongP = FALSE; /* Long Pulse */
- value->Persist = FALSE; /* Persistent output */
-
- value->QU = data & 0x7c;
- value->QU >>= 2;
-
- switch( value->QU )
- {
- case 0x00:
- value->ZeroP = TRUE;
- break; /* No additional definition */
- case 0x01:
- value->ShortP = TRUE;
- break;
- case 0x02:
- value->LongP = TRUE;
- break;
- case 0x03:
- value->Persist = TRUE;
- break;
- default:
- /* case 4..31 --> reserved .. */
- ;
- break;
- }
- value->SE = data & 0x80; /* Select (1) / Execute (0) */
-
-}
-
-
-/* ====================================================================
QOS: Qualifier Of Set-point command
==================================================================== */
-static void get_QOS( td_SpInfo *spt, tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_QOS( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
{
- guint8 qos;
- /* -------- QOS quality description */
- qos = tvb_get_guint8(tvb, *offset);
-
- spt->QL = qos & 0x7F; /* UI7[1..7]<0..127> */
- spt->SE = qos & 0x80; /* Select (1) / Execute (0) */
-
- if( iec104_header_tree != NULL )
- {
- proto_tree_add_text( iec104_header_tree, tvb, *offset, 1, "Qualifier - QL: %d, S/E: %s",
- spt->QL, spt->SE?"Select":"Execute" );
- }
+ 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);
(*offset)++;
}
-
/* ====================================================================
SCO: Single Command (IEV 371-03-02)
==================================================================== */
-static void get_SCO( td_CmdInfo *value, tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_SCO( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
{
- guint8 data;
- /* On/Off */
- data = tvb_get_guint8(tvb, *offset);
- value->ON = data & 0x01;
- value->OFF = !(value->ON);
-
- /* QOC */
- get_QOC( value, data );
-
-
- if( iec104_header_tree != NULL )
- {
- if ( value->QU < 4 )
- {
- proto_tree_add_text( iec104_header_tree, tvb, *offset, 1, "Command: %s%s, Qualifier: %s%s%s%s, %s",
- value->ON?"ON":"", value->OFF?"OFF":"",
- value->ZeroP?"No pulse defined":"", value->ShortP?"Short Pulse":"",
- value->LongP?"Long Pulse":"", value->Persist?"Persistent Output":"",
- value->SE?"Select":"Execute");
- } else {
- proto_tree_add_text( iec104_header_tree, tvb, *offset, 1, "Command: %s%s, Qualifier: QU=%d, %s",
- value->ON?"ON":"", value->OFF?"OFF":"",
- value->QU,
- value->SE?"Select":"Execute");
- }
- }
+ 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 );
+
+ 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);
+ proto_tree_add_item(sco_tree, hf_sco_se, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
(*offset)++;
@@ -925,46 +778,17 @@ static void get_SCO( td_CmdInfo *value, tvbuff_t *tvb, guint8 *offset, proto_tre
/* ====================================================================
DCO: Double Command (IEV 371-03-03)
==================================================================== */
-static void get_DCO( td_CmdInfo *value, tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_DCO( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
{
- guint8 data;
- /* On/Off */
- data = tvb_get_guint8(tvb, *offset);
- value->OFF = FALSE;
- value->ON = FALSE;
- switch ( data & 0x03 )
- {
- case 1:
- value->OFF = TRUE;
- break;
- case 2:
- value->ON = TRUE;
- break;
- default:
- ;
- break;
- }
-
- /* QOC */
- get_QOC( value, data );
-
-
- if( iec104_header_tree != NULL )
- {
- if ( value->QU < 4 )
- {
- proto_tree_add_text( iec104_header_tree, tvb, *offset, 1, "Command: %s%s%s, Qualifier: %s%s%s%s, %s",
- value->ON?"ON":"", value->OFF?"OFF":"", (value->ON | value->OFF)?"":"Error: On/Off not defined",
- value->ZeroP?"No pulse defined":"", value->ShortP?"Short Pulse":"",
- value->LongP?"Long Pulse":"", value->Persist?"Persistent Output":"",
- value->SE?"Select":"Execute");
- } else {
- proto_tree_add_text( iec104_header_tree, tvb, *offset, 1, "Command: %s%s%s, Qualifier: QU=%d, %s",
- value->ON?"ON":"", value->OFF?"OFF":"", (value->ON | value->OFF)?"":"Error: On/Off not defined",
- value->QU,
- value->SE?"Select":"Execute");
- }
- }
+ 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 );
+
+ 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);
+ proto_tree_add_item(dco_tree, hf_dco_se, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
(*offset)++;
@@ -973,46 +797,17 @@ static void get_DCO( td_CmdInfo *value, tvbuff_t *tvb, guint8 *offset, proto_tre
/* ====================================================================
RCO: Regulating step command (IEV 371-03-13)
==================================================================== */
-static void get_RCO( td_CmdInfo *value, tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
+static void get_RCO( tvbuff_t *tvb, guint8 *offset, proto_tree *iec104_header_tree )
{
- guint8 data;
- /* Up/Down */
- data = tvb_get_guint8(tvb, *offset);
- value->UP = FALSE;
- value->DOWN = FALSE;
- switch ( data & 0x03 )
- {
- case 1:
- value->DOWN = TRUE;
- break;
- case 2:
- value->UP = TRUE;
- break;
- default:
- ;
- break;
- }
-
- /* QOC */
- get_QOC( value, data );
-
-
- if( iec104_header_tree != NULL )
- {
- if ( value->QU < 4 )
- {
- proto_tree_add_text( iec104_header_tree, tvb, *offset, 1, "Command: %s%s%s, Qualifier: %s%s%s%s, %s",
- value->UP?"UP":"", value->DOWN?"DOWN":"", (value->UP | value->DOWN)?"":"Error: On/Off not defined",
- value->ZeroP?"No pulse defined":"", value->ShortP?"Short Pulse":"",
- value->LongP?"Long Pulse":"", value->Persist?"Persistent Output":"",
- value->SE?"Select":"Execute");
- } else {
- proto_tree_add_text( iec104_header_tree, tvb, *offset, 1, "Command: %s%s%s, Qualifier: QU=%d, %s",
- value->UP?"UP":"", value->DOWN?"DOWN":"", (value->UP | value->DOWN)?"":"Error: On/Off not defined",
- value->QU,
- value->SE?"Select":"Execute");
- }
- }
+ 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 );
+
+ 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);
+ proto_tree_add_item(rco_tree, hf_rco_se, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
(*offset)++;
@@ -1027,14 +822,14 @@ static guint get_iec104apdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offse
guint8 Val;
guint32 Off;
- for (Off= 0; Off <= tvb_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) {
return (guint)(Off+ tvb_get_guint8(tvb, offset+ Off+ 1)+ 2);
}
}
- return (guint)(tvb_length(tvb));
+ return (guint)(tvb_reported_length(tvb));
}
@@ -1042,13 +837,12 @@ static guint get_iec104apdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offse
static void dissect_iec104asdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
guint Len = tvb_reported_length(tvb);
- guint8 Bytex = 0;
+ guint8 Bytex;
const char *cause_str;
- size_t Ind = 0;
- struct asduheader * asduh;
- emem_strbuf_t * res;
- proto_item * it104 = NULL;
- proto_tree * trHead;
+ size_t Ind;
+ struct asduheader asduh;
+ proto_item *it104, *ioa_item;
+ proto_tree *it104tree;
guint8 offset = 0; /* byte offset, signal dissection */
@@ -1057,91 +851,63 @@ static void dissect_iec104asdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tr
guint32 asdu_info_obj_addr = 0;
proto_item * itSignal = NULL;
proto_tree * trSignal;
- td_ValueInfo value; /* signal value struct */
- td_CmdInfo cmd; /* command value struct */
- td_SpInfo spt; /* setpoint value struct */
- td_CP56Time cp56t; /* time value struct */
-
- if (!(check_col(pinfo->cinfo, COL_INFO) || tree)) return; /* Be sure that the function is only called twice */
col_set_str(pinfo->cinfo, COL_PROTOCOL, "104asdu");
col_clear(pinfo->cinfo, COL_INFO);
- asduh = ep_new(struct asduheader);
- res = ep_strbuf_new_label(NULL);
-
- /*** *** START: Common to 'Packet List' and 'Packet Details' *** ***/
- if (Len >= ASDU_HEAD_LEN) {
- /* Get fields */
- asduh->AddrLow = tvb_get_guint8(tvb, 4);
- asduh->AddrHigh = tvb_get_guint8(tvb, 5);
- asduh->OA = tvb_get_guint8(tvb, 3);
- asduh->TypeId = tvb_get_guint8(tvb, 0);
- asduh->TNCause = tvb_get_guint8(tvb, 2);
- asduh->IOA = tvb_get_letoh24(tvb, 6);
- Bytex = tvb_get_guint8(tvb, 1);
- asduh->NumIx = Bytex & 0x7F;
- asduh->SQ = Bytex & F_SQ;
- /* Build common string for 'Packet List' and 'Packet Details' */
- ep_strbuf_printf(res, "%u,%u%s%u ", asduh->AddrLow, asduh->AddrHigh, pinfo->srcport == iec104port ? "->" : "<-", asduh->OA);
- ep_strbuf_append(res, val_to_str(asduh->TypeId, asdu_types, "<TypeId=%u>"));
- ep_strbuf_append_c(res, ' ');
- cause_str = val_to_str(asduh->TNCause & F_CAUSE, causetx_types, " <CauseTx=%u>");
- ep_strbuf_append(res, cause_str);
- if (asduh->TNCause & F_NEGA) ep_strbuf_append(res, "_NEGA");
- if (asduh->TNCause & F_TEST) ep_strbuf_append(res, "_TEST");
- if (asduh->TNCause & (F_TEST | F_NEGA)) {
- for (Ind=strlen(cause_str); Ind< 7; Ind++) ep_strbuf_append_c(res, ' ');
- }
- ep_strbuf_append_printf(res, " IOA=%d", asduh->IOA);
- if (asduh->NumIx > 1) {
- if (asduh->SQ == F_SQ) ep_strbuf_append_printf(res, "-%d", asduh->IOA + asduh->NumIx - 1);
- else ep_strbuf_append(res, ",...");
- ep_strbuf_append_printf(res, " (%u)", asduh->NumIx);
- }
- }
- else {
- ep_strbuf_printf(res, "<ERR Short Asdu, Len=%u>", Len);
+ it104 = proto_tree_add_item(tree, proto_iec104asdu, tvb, 0, -1, ENC_NA);
+ it104tree = proto_item_add_subtree(it104, ett_asdu);
+
+ asduh.TypeId = tvb_get_guint8(tvb, 0);
+ proto_tree_add_item(it104tree, hf_typeid, tvb, 0, 1, ENC_LITTLE_ENDIAN);
+ Bytex = tvb_get_guint8(tvb, 1);
+ asduh.NumIx = Bytex & 0x7F;
+ asduh.SQ = Bytex & F_SQ;
+ 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);
+ 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);
+ asduh.OA = tvb_get_guint8(tvb, 3);
+ proto_tree_add_item(it104tree, hf_oa, tvb, 3, 1, ENC_LITTLE_ENDIAN);
+ asduh.Addr = tvb_get_letohs(tvb, 4);
+ proto_tree_add_item(it104tree, hf_addr, tvb, 4, 2, ENC_LITTLE_ENDIAN);
+ 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);
+ if (asduh.TNCause & F_NEGA)
+ col_append_str( pinfo->cinfo, COL_INFO, "_NEGA");
+ if (asduh.TNCause & F_TEST)
+ col_append_str( pinfo->cinfo, COL_INFO, "_TEST");
+
+ if (asduh.TNCause & (F_TEST | F_NEGA)) {
+ for (Ind=strlen(cause_str); Ind< 7; Ind++)
+ col_append_str( pinfo->cinfo, COL_INFO, " ");
}
- ep_strbuf_append_c(res, ' '); /* We add a space to separate possible APCIs/ASDUs in the same packet */
- /*** *** END: Common to 'Packet List' and 'Packet Details' *** ***/
- /*** *** DISSECT 'Packet List' *** ***/
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_add_str(pinfo->cinfo, COL_INFO, res->str);
- col_set_fence(pinfo->cinfo, COL_INFO);
+ col_append_fstr( pinfo->cinfo, COL_INFO, " IOA=%d", asduh.IOA);
+ if (asduh.NumIx > 1) {
+ if (asduh.SQ == F_SQ)
+ col_append_fstr( pinfo->cinfo, COL_INFO, "-%d", asduh.IOA + asduh.NumIx - 1);
+ else
+ col_append_str( pinfo->cinfo, COL_INFO, ",...");
+ col_append_fstr( pinfo->cinfo, COL_INFO, " (%u) ", asduh.NumIx);
+ } else {
+ col_append_str( pinfo->cinfo, COL_INFO, " ");
}
- if(!tree) return;
-
- /*** *** DISSECT 'Packet Details' *** ***/
-
- it104 = proto_tree_add_item(tree, proto_iec104asdu, tvb, 0, -1, ENC_NA);
-
- /* 'Packet 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>") : "");
-
- /* 'Packet Details': TREE */
- if (Len < ASDU_HEAD_LEN) return;
- trHead = proto_item_add_subtree(it104, ett_asdu);
-
- /* Remember: add_uint, add_boolean, _add_text: value from last parameter.
- add_item: value from tvb. */
- proto_tree_add_uint(trHead, hf_typeid, tvb, 0, 1, asduh->TypeId);
- proto_tree_add_uint(trHead, hf_numix, tvb, 1, 1, asduh->NumIx);
- proto_tree_add_uint(trHead, hf_causetx, tvb, 2, 1, asduh->TNCause & F_CAUSE);
- proto_tree_add_boolean(trHead, hf_nega, tvb, 2, 1, asduh->TNCause);
- proto_tree_add_boolean(trHead, hf_test, tvb, 2, 1, asduh->TNCause);
- proto_tree_add_uint(trHead, hf_oa, tvb, 3, 1, asduh->OA);
- proto_tree_add_uint(trHead, hf_addr, tvb, 4, 2, asduh->AddrLow+ 256* asduh->AddrHigh);
- proto_tree_add_uint(trHead, hf_ioa, tvb, 6, 3, asduh->IOA);
- if (asduh->NumIx > 1) proto_tree_add_boolean(trHead, hf_sq, tvb, 1, 1, asduh->SQ);
+ col_set_fence(pinfo->cinfo, COL_INFO);
/* 'Signal Details': TREE */
offset = 6; /* offset position after DUI, already stored in asduh struct */
/* -------- get signal value and status based on ASDU type id */
- switch (asduh->TypeId) {
+ switch (asduh.TypeId) {
case M_SP_NA_1:
case M_DP_NA_1:
case M_ST_NA_1:
@@ -1174,325 +940,318 @@ static void dissect_iec104asdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tr
case C_CS_NA_1:
/* create subtree for the signal values ... */
- itSignal = proto_tree_add_item( trHead, proto_iec104asdu, tvb, offset, -1, ENC_NA );
- proto_item_append_text(itSignal, ": Value");
-
- trSignal = proto_item_add_subtree( itSignal, ett_asdu );
+ 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++)
+ for(i = 0; i < asduh.NumIx; i++)
{
/* -------- First Information object address */
if (!i)
{
offset_start_ioa = offset;
/* -------- Information object address */
- asdu_info_obj_addr = asduh->IOA;
- proto_tree_add_uint(trSignal, hf_ioa,
- tvb, offset_start_ioa, 3, asdu_info_obj_addr);
+ 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
offset += 3; /* step over IOA bytes */
} else {
/* -------- following Information object address depending on SQ */
- if (asduh->SQ) /* <=> SQ=1, info obj addr = startaddr++ */
+ if (asduh.SQ) /* <=> SQ=1, info obj addr = startaddr++ */
{
asdu_info_obj_addr++;
- proto_tree_add_uint(trSignal, hf_ioa,
- tvb, offset_start_ioa, 3, asdu_info_obj_addr);
-
-
+ ioa_item = 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, itSignal, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_InfoObjectAddress( &asdu_info_obj_addr, tvb, &offset,
- trSignal);
+ ioa_item = get_InfoObjectAddress( &asdu_info_obj_addr, tvb, &offset, trSignal);
}
}
- switch (asduh->TypeId) {
+ switch (asduh.TypeId) {
case M_SP_NA_1: /* 1 Single-point information */
/* check length */
if( Len < (guint)(offset+1) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_SIQ( &value, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_DIQ( &value, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_VTI( &value, tvb, &offset, trSignal );
- get_QDS( &value, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_BSI( &value, tvb, &offset, trSignal );
- get_QDS( &value, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_NVA( &value, tvb, &offset, trSignal );
- get_QDS( &value, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_SVA( &value, tvb, &offset, trSignal );
- get_QDS( &value, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_FLT( &value, tvb, &offset, trSignal );
- get_QDS( &value, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_NVA( &value, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_SIQ( &value, tvb, &offset, trSignal );
- get_CP56Time( &cp56t, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_DIQ( &value, tvb, &offset, trSignal );
- get_CP56Time( &cp56t, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_VTI( &value, tvb, &offset, trSignal );
- get_QDS( &value, tvb, &offset, trSignal );
- get_CP56Time( &cp56t, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_BSI( &value, tvb, &offset, trSignal );
- get_QDS( &value, tvb, &offset, trSignal );
- get_CP56Time( &cp56t, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_NVA( &value, tvb, &offset, trSignal );
- get_QDS( &value, tvb, &offset, trSignal );
- get_CP56Time( &cp56t, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_SVA( &value, tvb, &offset, trSignal );
- get_QDS( &value, tvb, &offset, trSignal );
- get_CP56Time( &cp56t, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_FLT( &value, tvb, &offset, trSignal );
- get_QDS( &value, tvb, &offset, trSignal );
- get_CP56Time( &cp56t, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_SCO( &cmd, tvb, &offset, trSignal );
+ get_SCO( tvb, &offset, trSignal );
break;
case C_DC_NA_1: /* 46 Double command */
/* check length */
if( Len < (guint)(offset+1) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_DCO( &cmd, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_RCO( &cmd, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_NVAspt( &spt, tvb, &offset, trSignal );
- get_QOS( &spt, tvb, &offset, trSignal );
+ 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_SVAspt( &spt, tvb, &offset, trSignal );
- get_QOS( &spt, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_FLTspt( &spt, tvb, &offset, trSignal );
- get_QOS( &spt, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_BSIspt( &value, tvb, &offset, trSignal );
+ 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_SCO( &cmd, tvb, &offset, trSignal );
- get_CP56Time( &cp56t, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_DCO( &cmd, tvb, &offset, trSignal );
- get_CP56Time( &cp56t, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_RCO( &cmd, tvb, &offset, trSignal );
- get_CP56Time( &cp56t, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_NVAspt( &spt, tvb, &offset, trSignal );
- get_QOS( &spt, tvb, &offset, trSignal );
- get_CP56Time( &cp56t, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_SVAspt( &spt, tvb, &offset, trSignal );
- get_QOS( &spt, tvb, &offset, trSignal );
- get_CP56Time( &cp56t, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_FLTspt( &spt, tvb, &offset, trSignal );
- get_QOS( &spt, tvb, &offset, trSignal );
- get_CP56Time( &cp56t, 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) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_BSIspt( &value, tvb, &offset, trSignal );
- get_CP56Time( &cp56t, tvb, &offset, trSignal );
+ get_BSIspt( tvb, &offset, trSignal );
+ get_CP56Time( tvb, &offset, trSignal );
break;
case C_CS_NA_1: /* 103 clock synchronization command */
/* check length */
if( Len < (guint)(offset+7) ) {
- proto_tree_add_text( trSignal, tvb, offset, 1, "<ERR Short Asdu>" );
+ expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>");
return;
}
- get_CP56Time( &cp56t, tvb, &offset, trSignal );
+ get_CP56Time( tvb, &offset, trSignal );
break;
default:
break;
- } /* end 'switch (asduh->TypeId)' */
+ } /* end 'switch (asduh.TypeId)' */
} /* end 'for(i = 0; i < dui.asdu_vsq_no_of_obj; i++)' */
break;
default:
@@ -1506,128 +1265,85 @@ static void dissect_iec104asdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tr
/* Is is called twice: For 'Packet List' and for 'Packet Details' */
static void dissect_iec104apci(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
- guint TcpLen = tvb_length(tvb);
- guint Brossa = 0;
- guint8 Start;
+ guint TcpLen = tvb_reported_length(tvb);
+ guint8 Start = 0, len, type = 0, temp8;
+ guint8 temp16;
guint Off;
- guint8 Byte1 = 0;
- struct apciheader * apcih;
- emem_strbuf_t * res;
- proto_item * it104 = NULL;
- proto_tree * trHead;
-
- if (!(check_col(pinfo->cinfo, COL_INFO) || tree)) return; /* Be sure that the function is only called twice */
+ proto_item *it104, *ti;
+ proto_tree *it104tree;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "104apci");
col_clear(pinfo->cinfo, COL_INFO);
- apcih = ep_new(struct apciheader);
+ it104 = proto_tree_add_item(tree, proto_iec104apci, tvb, 0, -1, ENC_NA);
+ it104tree = proto_item_add_subtree(it104, ett_apci);
- /*** *** START: Common to 'Packet List' and 'Packet Details' *** ***/
- Start = 0;
for (Off= 0; Off <= TcpLen- 2; Off++) {
Start = tvb_get_guint8(tvb, Off);
if (Start == APCI_START) {
- Brossa = Off;
- apcih->ApduLen = tvb_get_guint8(tvb, Off+ 1);
- if (apcih->ApduLen >= APDU_MIN_LEN) {
- Byte1 = tvb_get_guint8(tvb, Off+ 2);
- apcih->Type = Byte1 & 0x03;
- /* Type I is only lowest bit set to 0 */
- if (apcih->Type == 2) apcih->Type = 0;
- switch(apcih->Type) {
- case I_TYPE:
- apcih->Tx = tvb_get_letohs(tvb, Off+ 2) >> 1;
- case S_TYPE:
- apcih->Rx = tvb_get_letohs(tvb, Off+ 4) >> 1;
- break;
- case U_TYPE:
- apcih->UType = (Byte1 & 0xFC); /* Don't shift */
- break;
- }
+ 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);
}
- else {
- /* WireShark can crash if we process packets with length less than expected (6). We consider that everything is bad */
- Brossa = TcpLen;
+
+ 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) {
+ expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR, "APDU less than %d bytes", APDU_MIN_LEN);
+ col_append_fstr( pinfo->cinfo, COL_INFO, "<ERR ApduLen=%u bytes> ", len);
+ return;
}
- /* Don't search more the APCI_START */
- break;
- }
- }
- if (Start != APCI_START) {
- /* Everything is bad (no APCI found) */
- Brossa = TcpLen;
- }
- /* Construir string comu a List i Details */
- res = ep_strbuf_new_label(NULL);
- if (Brossa > 0)
- ep_strbuf_append_printf(res, "<ERR %u bytes> ", Brossa);
- if (Brossa != TcpLen) {
- if (apcih->ApduLen <= APDU_MAX_LEN) {
- /* APCI in 'Paquet List' */
- ep_strbuf_append_printf(res, "%s%s(", pinfo->srcport == iec104port ? "->" : "<-", val_to_str_const(apcih->Type, apci_types, "<ERR>"));
- switch(apcih->Type) { /* APCI in 'Packet List' */
+
+ temp8 = tvb_get_guint8(tvb, Off+ 2);
+ type = temp8 & 0x03;
+
+ if (len <= APDU_MAX_LEN) {
+ col_append_fstr( pinfo->cinfo, COL_INFO, "%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);
+ }
+
+ switch(type) {
case I_TYPE:
- ep_strbuf_append_printf(res, "%d,", apcih->Tx);
+ case I_TYPE2:
+ temp16 = tvb_get_letohs(tvb, Off+ 2) >> 1;
+ col_append_fstr( pinfo->cinfo, COL_INFO, "%2.2d,", temp16);
+ proto_tree_add_uint(it104tree, hf_apcitx, tvb, Off+2, 2, temp16);
case S_TYPE:
- ep_strbuf_append_printf(res, "%d)", apcih->Rx);
- /* Align first packets */
- if (apcih->Tx < 10)
- ep_strbuf_append_c(res, ' ');
- if (apcih->Rx < 10)
- ep_strbuf_append_c(res, ' ');
+ temp16 = tvb_get_letohs(tvb, Off+ 4) >> 1;
+ col_append_fstr( pinfo->cinfo, COL_INFO, "%2.2d) ", temp16);
+ proto_tree_add_uint(it104tree, hf_apcirx, tvb, Off+4, 2, temp16);
break;
case U_TYPE:
- ep_strbuf_append_printf(res, "%s)", val_to_str_const(apcih->UType >> 2, u_types, "<ERR>"));
+ col_append_fstr( pinfo->cinfo, COL_INFO, "%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;
}
- if (apcih->Type != I_TYPE && apcih->ApduLen > APDU_MIN_LEN) ep_strbuf_append_printf(res, "<ERR %u bytes> ", apcih->ApduLen- APDU_MIN_LEN);
- }
- else {
- ep_strbuf_append_printf(res, "<ERR ApduLen=%u bytes> ", apcih->ApduLen);
- }
- }
- ep_strbuf_append_c(res, ' '); /* We add a space to separate possible APCIs/ASDUs in the same packet */
- /*** *** END: Common to 'Packet List' and 'Packet Details' *** ***/
-
- /*** *** Dissect 'Packet List' *** ***/
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_add_str(pinfo->cinfo, COL_INFO, res->str);
- if(apcih->Type == I_TYPE && Brossa != TcpLen) {
- call_dissector(iec104asdu_handle, tvb_new_subset(tvb, Off+ APCI_LEN, -1, apcih->ApduLen- APCI_DATA_LEN), pinfo, tree);
- } else {
- col_set_fence(pinfo->cinfo, COL_INFO);
+ /* Don't search more the APCI_START */
+ break;
}
}
- if(!tree) return;
-
- /*** *** DISSECT 'Packet Details' *** ***/
-
- it104 = proto_tree_add_item(tree, proto_iec104apci, tvb, 0, Off+ APCI_LEN, ENC_NA);
-
- /* 'Packet Details': ROOT ITEM */
- proto_item_append_text(it104, ": %s", res->str);
-
- if(Brossa == TcpLen) return;
-
- /* Don't call ASDU dissector if it was called before */
- if(apcih->Type == I_TYPE && (!check_col(pinfo->cinfo, COL_INFO))){
- call_dissector(iec104asdu_handle, tvb_new_subset(tvb, Off+ APCI_LEN, -1, apcih->ApduLen- APCI_DATA_LEN), pinfo, tree);
+ if (Start != APCI_START) {
+ /* Everything is bad (no APCI found) */
+ proto_tree_add_item(it104tree, hf_apcidata, tvb, 0, Off, ENC_NA);
+ return;
}
- /* 'Packet Details': TREE */
- trHead = proto_item_add_subtree(it104, ett_apci);
- /* Remember: add_uint, add_boolean, _add_text: value from last parameter.
- add_item: value from tvb. */
- proto_tree_add_uint(trHead, hf_apdulen, tvb, Off+ 1, 1, apcih->ApduLen);
- proto_tree_add_uint(trHead, hf_apcitype, tvb, Off+ 2, 1, apcih->Type);
- switch(apcih->Type){
- case U_TYPE:
- proto_tree_add_uint(trHead, hf_apciutype, tvb, Off+ 2, 1, apcih->UType); /* Don't shift the value */
- break;
+ 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);
}
-
}
@@ -1655,13 +1371,24 @@ proto_register_iec104apci(void)
"APDU Len", HFILL }},
{ &hf_apcitype,
- { "ApciType", "104apci.type", FT_UINT8, BASE_HEX, VALS(apci_types), 0x03,
+ { "Type", "104apci.type", FT_UINT8, BASE_HEX, VALS(apci_types), 0x03,
"APCI type", HFILL }},
{ &hf_apciutype,
- { "ApciUType", "104apci.utype", FT_UINT8, BASE_HEX, VALS(u_types), 0xFC,
+ { "UType", "104apci.utype", FT_UINT8, BASE_HEX, VALS(u_types), 0xFC,
"Apci U type", HFILL }},
+ { &hf_apcitx,
+ { "Tx", "104apci.tx", FT_UINT16, BASE_DEC, NULL, 0,
+ NULL, HFILL }},
+
+ { &hf_apcirx,
+ { "Rx", "104apci.rx", FT_UINT16, BASE_DEC, NULL, 0,
+ NULL, HFILL }},
+
+ { &hf_apcidata,
+ { "Data", "104apci.data", FT_BYTES, BASE_NONE, NULL, 0,
+ NULL, HFILL }},
};
static gint *ett_ap[] = {
@@ -1699,7 +1426,7 @@ proto_register_iec104asdu(void)
"Asdu Type Id", HFILL }},
{ &hf_causetx,
- { "CauseTx", "104asdu.causetx", FT_UINT8, BASE_DEC, VALS(causetx_types), 0x3F,
+ { "CauseTx", "104asdu.causetx", FT_UINT8, BASE_DEC, VALS(causetx_types), F_CAUSE,
"Cause of Transmision", HFILL }},
{ &hf_nega,
@@ -1723,22 +1450,169 @@ proto_register_iec104asdu(void)
{ "SQ", "104asdu.sq", FT_BOOLEAN, 8, NULL, F_SQ,
"Sequence", HFILL }},
- { &hf_asdu_bitstring,
- { "Object value", "104asdu.bitstring", FT_UINT32, BASE_HEX, NULL, 0x0,
+ { &hf_cp56time,
+ { "CP56Time", "104asdu.cp56time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0,
+ NULL, 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_bl,
+ { "BL", "104asdu.siq.bl", FT_BOOLEAN, 8, TFS(&tfs_blocked_not_blocked), 0x02,
+ "SIQ BL", HFILL }},
+
+ { &hf_siq_sb,
+ { "SB", "104asdu.siq.sb", FT_BOOLEAN, 8, TFS(&tfs_substituted_not_substituted), 0x04,
+ "SIQ SB", HFILL }},
+
+ { &hf_siq_nt,
+ { "NT", "104asdu.siq.nt", FT_BOOLEAN, 8, TFS(&tfs_not_topical_topical), 0x08,
+ "SIQ NT", HFILL }},
+
+ { &hf_siq_iv,
+ { "IV", "104asdu.siq.iv", FT_BOOLEAN, 8, TFS(&tfs_invalid_valid), 0x10,
+ "SIQ IV", HFILL }},
+
+ { &hf_diq,
+ { "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_bl,
+ { "BL", "104asdu.diq.bl", FT_BOOLEAN, 8, TFS(&tfs_blocked_not_blocked), 0x10,
+ "DIQ BL", HFILL }},
+
+ { &hf_diq_sb,
+ { "SB", "104asdu.diq.sb", FT_BOOLEAN, 8, TFS(&tfs_substituted_not_substituted), 0x20,
+ "DIQ SB", HFILL }},
+
+ { &hf_diq_nt,
+ { "NT", "104asdu.diq.nt", FT_BOOLEAN, 8, TFS(&tfs_not_topical_topical), 0x40,
+ "DIQ NT", HFILL }},
+
+ { &hf_diq_iv,
+ { "IV", "104asdu.diq.iv", FT_BOOLEAN, 8, TFS(&tfs_invalid_valid), 0x80,
+ "DIQ IV", HFILL }},
+
+ { &hf_qds,
+ { "QDS", "104asdu.qds", FT_UINT8, BASE_HEX, NULL, 0,
+ NULL, HFILL }},
+
+ { &hf_qds_ov,
+ { "OV", "104asdu.qds.ov", FT_BOOLEAN, 8, TFS(&tfs_overflow_no_overflow), 0x01,
+ "QDS OV", HFILL }},
+
+ { &hf_qds_bl,
+ { "BL", "104asdu.qds.bl", FT_BOOLEAN, 8, TFS(&tfs_blocked_not_blocked), 0x02,
+ "QDS BL", HFILL }},
+
+ { &hf_qds_sb,
+ { "SB", "104asdu.qds.sb", FT_BOOLEAN, 8, TFS(&tfs_substituted_not_substituted), 0x04,
+ "QDS SB", HFILL }},
+
+ { &hf_qds_nt,
+ { "NT", "104asdu.qds.nt", FT_BOOLEAN, 8, TFS(&tfs_not_topical_topical), 0x08,
+ "QDS NT", HFILL }},
+
+ { &hf_qds_iv,
+ { "IV", "104asdu.qds.iv", FT_BOOLEAN, 8, TFS(&tfs_invalid_valid), 0x10,
+ "QDS IV", HFILL }},
+
+ { &hf_vti,
+ { "VTI", "104asdu.vti", FT_UINT8, BASE_DEC, NULL, 0x7F,
+ NULL, HFILL }},
+
+ { &hf_vti_tr,
+ { "VTI Transient", "104asdu.qds.ov", FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x80,
+ NULL, HFILL }},
+
+ { &hf_qos_ql,
+ { "QOS Qualifier", "104asdu.qos_ql", FT_UINT8, BASE_DEC, NULL, 0x7F,
+ NULL, HFILL }},
+
+ { &hf_qos_se,
+ { "QOS S/E", "104asdu.qos_se", FT_BOOLEAN, 8, TFS(&tfs_select_execute), 0x80,
+ NULL, HFILL }},
+
+ { &hf_sco,
+ { "SCO", "104asdu.sco", FT_UINT8, BASE_DEC, NULL, 0,
+ NULL, HFILL }},
+
+ { &hf_sco_on,
+ { "SCO ON/OFF", "104asdu.sco.on", FT_BOOLEAN, 8, TFS(&tfs_on_off), 0x01,
+ NULL, HFILL }},
+
+ { &hf_sco_qu,
+ { "SCO QU", "104asdu.sco.qu", FT_UINT8, BASE_DEC, VALS(qos_qu_types), 0x70,
+ NULL, HFILL }},
+
+ { &hf_sco_se,
+ { "SCO S/E", "104asdu.sco.se", FT_BOOLEAN, 8, TFS(&tfs_select_execute), 0x80,
+ NULL, HFILL }},
+
+ { &hf_dco,
+ { "DCO", "104asdu.dco", FT_UINT8, BASE_DEC, NULL, 0,
+ NULL, HFILL }},
+
+ { &hf_dco_on,
+ { "DCO ON/OFF", "104asdu.dco.on", FT_UINT8, BASE_DEC, VALS(dco_on_types), 0x03,
+ NULL, HFILL }},
+
+ { &hf_dco_qu,
+ { "DCO QU", "104asdu.dco.qu", FT_UINT8, BASE_DEC, VALS(qos_qu_types), 0x70,
+ NULL, HFILL }},
+
+ { &hf_dco_se,
+ { "DCO S/E", "104asdu.dco.se", FT_BOOLEAN, 8, TFS(&tfs_select_execute), 0x80,
+ NULL, HFILL }},
+
+ { &hf_rco,
+ { "RCO", "104asdu.rco", FT_UINT8, BASE_DEC, NULL, 0,
+ NULL, HFILL }},
+
+ { &hf_rco_up,
+ { "RCO UP/DOWN", "104asdu.rco.up", FT_UINT8, BASE_DEC, VALS(rco_up_types), 0x03,
+ NULL, HFILL }},
+
+ { &hf_rco_qu,
+ { "RCO QU", "104asdu.rco.qu", FT_UINT8, BASE_DEC, VALS(qos_qu_types), 0x70,
+ NULL, HFILL }},
+
+ { &hf_rco_se,
+ { "RCO S/E", "104asdu.rco.se", FT_BOOLEAN, 8, TFS(&tfs_select_execute), 0x80,
+ NULL, HFILL }},
+
+ { &hf_asdu_bitstring,
+ { "Object value", "104asdu.bitstring", FT_UINT32, BASE_HEX, NULL, 0x0,
NULL, HFILL }},
{ &hf_asdu_float,
- { "Object value", "104asdu.float", FT_FLOAT, BASE_NONE, NULL, 0x0,
+ { "Object value", "104asdu.float", FT_FLOAT, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_asdu_normval,
- { "Object value", "104asdu.normval", FT_INT16, BASE_DEC, NULL, 0x0,
+ { "Object value", "104asdu.normval", FT_INT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
};
static gint *ett_as[] = {
&ett_asdu,
+ &ett_asdu_objects,
+ &ett_siq,
+ &ett_diq,
+ &ett_qds,
+ &ett_sco,
+ &ett_dco,
+ &ett_rco
};
proto_iec104asdu = proto_register_protocol(
@@ -1762,6 +1636,6 @@ proto_reg_handoff_iec104(void)
iec104apci_handle = create_dissector_handle(dissect_iec104reas, proto_iec104apci);
iec104asdu_handle = create_dissector_handle(dissect_iec104asdu, proto_iec104asdu);
- dissector_add_uint("tcp.port", iec104port, iec104apci_handle);
+ dissector_add_uint("tcp.port", IEC104_PORT, iec104apci_handle);
}