From 8591b0b374c5ec9bbb676bc38fd6a862e8c654d9 Mon Sep 17 00:00:00 2001 From: Michael Mann Date: Sun, 21 Apr 2013 23:20:10 +0000 Subject: 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 --- epan/dissectors/packet-iec104.c | 1320 ++++++++++++++++++--------------------- 1 file changed, 597 insertions(+), 723 deletions(-) (limited to 'epan/dissectors/packet-iec104.c') 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 /* floor */ #include +#include #include #include @@ -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, "")); - ep_strbuf_append_c(res, ' '); - cause_str = val_to_str(asduh->TNCause & F_CAUSE, causetx_types, " "); - 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, "", 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, " "); + 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, ""), 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, "") : ""); - - /* '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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, itSignal, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, "" ); + expert_add_info_format(pinfo, ioa_item, PI_MALFORMED, PI_ERROR, ""); 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, " ", 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, " ", 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, " ", 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, "")); - 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, "")); + } + else { + col_append_fstr( pinfo->cinfo, COL_INFO, " ", 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, "")); + col_append_fstr( pinfo->cinfo, COL_INFO, "%s) ", val_to_str_const((temp8 >> 2) & 0x3F, u_types, "")); + 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, " ", apcih->ApduLen- APDU_MIN_LEN); - } - else { - ep_strbuf_append_printf(res, " ", 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); } -- cgit v1.2.3