1 /* Do not modify this file. Changes will be overwritten. */
2 /* Generated automatically by the ASN.1 to Wireshark dissector compiler */
4 /* asn2wrs.py -b -q -L -p sv -c ./sv.cnf -s ./packet-sv-template -D . -O ../.. sv.asn */
7 * Routines for IEC 61850 Sampled Values packet dissection
8 * Michael Bernhard 2008
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
14 * SPDX-License-Identifier: GPL-2.0-or-later
19 #include <epan/packet.h>
20 #include <epan/asn1.h>
21 #include <epan/etypes.h>
22 #include <epan/expert.h>
23 #include <epan/prefs.h>
24 #include <epan/addr_resolv.h>
25 #include <wsutil/array.h>
27 #include "packet-ber.h"
28 #include "packet-acse.h"
32 #include "packet-sv.h"
34 #define PNAME "IEC61850 Sampled Values"
38 /* see IEC61850-8-1 8.2 */
39 #define Q_VALIDITY_GOOD (0x0U << 0)
40 #define Q_VALIDITY_INVALID_BW (0x1U << 0)
41 #define Q_VALIDITY_INVALID (0x2U << 0)
42 #define Q_VALIDITY_QUESTIONABLE (0x3U << 0)
43 #define Q_VALIDITY_MASK (0x3U << 0)
45 #define Q_OVERFLOW (1U << 2)
46 #define Q_OUTOFRANGE (1U << 3)
47 #define Q_BADREFERENCE (1U << 4)
48 #define Q_OSCILLATORY (1U << 5)
49 #define Q_FAILURE (1U << 6)
50 #define Q_OLDDATA (1U << 7)
51 #define Q_INCONSISTENT (1U << 8)
52 #define Q_INACCURATE (1U << 9)
54 #define Q_SOURCE_PROCESS (0U << 10)
55 #define Q_SOURCE_SUBSTITUTED (1U << 10)
56 #define Q_SOURCE_MASK (1U << 10)
58 #define Q_TEST (1U << 11)
59 #define Q_OPERATORBLOCKED (1U << 12)
61 /* see UCA Implementation Guideline for IEC 61850-9-2 */
62 #define Q_DERIVED (1U << 13)
64 /* Bit fields in the Reserved attributes */
65 #define F_RESERVE1_S_BIT 0x8000
68 void proto_register_sv(void);
69 void proto_reg_handoff_sv(void);
73 static sv_frame_data sv_data
;
75 /* Initialize the protocol and registered fields */
77 static int hf_sv_appid
;
78 static int hf_sv_length
;
79 static int hf_sv_reserve1
;
80 static int hf_sv_reserve1_s_bit
;
81 static int hf_sv_reserve2
;
82 static int hf_sv_phmeas_instmag_i
;
83 static int hf_sv_phsmeas_q
;
84 static int hf_sv_phsmeas_q_validity
;
85 static int hf_sv_phsmeas_q_overflow
;
86 static int hf_sv_phsmeas_q_outofrange
;
87 static int hf_sv_phsmeas_q_badreference
;
88 static int hf_sv_phsmeas_q_oscillatory
;
89 static int hf_sv_phsmeas_q_failure
;
90 static int hf_sv_phsmeas_q_olddata
;
91 static int hf_sv_phsmeas_q_inconsistent
;
92 static int hf_sv_phsmeas_q_inaccurate
;
93 static int hf_sv_phsmeas_q_source
;
94 static int hf_sv_phsmeas_q_test
;
95 static int hf_sv_phsmeas_q_operatorblocked
;
96 static int hf_sv_phsmeas_q_derived
;
97 static int hf_sv_gmidentity
;
98 static int hf_sv_gmidentity_manuf
;
100 static int hf_sv_savPdu
; /* SavPdu */
101 static int hf_sv_noASDU
; /* INTEGER_0_65535 */
102 static int hf_sv_seqASDU
; /* SEQUENCE_OF_ASDU */
103 static int hf_sv_seqASDU_item
; /* ASDU */
104 static int hf_sv_svID
; /* VisibleString */
105 static int hf_sv_datSet
; /* VisibleString */
106 static int hf_sv_smpCnt
; /* T_smpCnt */
107 static int hf_sv_confRev
; /* INTEGER_0_4294967295 */
108 static int hf_sv_refrTm
; /* UtcTime */
109 static int hf_sv_smpSynch
; /* T_smpSynch */
110 static int hf_sv_smpRate
; /* INTEGER_0_65535 */
111 static int hf_sv_seqData
; /* Data */
112 static int hf_sv_smpMod
; /* T_smpMod */
113 static int hf_sv_gmidData
; /* GmidData */
115 /* Initialize the subtree pointers */
117 static int ett_phsmeas
;
118 static int ett_phsmeas_q
;
119 static int ett_gmidentity
;
120 static int ett_reserve1
;
123 static int ett_sv_SampledValues
;
124 static int ett_sv_SavPdu
;
125 static int ett_sv_SEQUENCE_OF_ASDU
;
126 static int ett_sv_ASDU
;
128 static expert_field ei_sv_mal_utctime
;
129 static expert_field ei_sv_zero_pdu
;
130 static expert_field ei_sv_mal_gmidentity
;
132 static bool sv_decode_data_as_phsmeas
;
134 static dissector_handle_t sv_handle
;
138 * IEC 61850-9-2 Edition 2.1 2020-02,
139 * Section 8.6 Definitions for basic data types – Presentation layer functionality,
142 * Be aware that in the specification the bits are numbered in reverse (it
143 * specifies the least significant bit as bit 31 instead of as bit 0)!
146 static const value_string sv_q_validity_vals
[] = {
148 { 1, "invalid (backwards compatible)" },
150 { 3, "questionable" },
154 static const value_string sv_q_source_vals
[] = {
156 { 1, "substituted" },
161 dissect_PhsMeas1(bool implicit_tag
, packet_info
*pinfo
, proto_tree
*tree
, tvbuff_t
*tvb
, int offset
, int hf_id _U_
)
172 static int * const q_flags
[] = {
173 &hf_sv_phsmeas_q_validity
,
174 &hf_sv_phsmeas_q_overflow
,
175 &hf_sv_phsmeas_q_outofrange
,
176 &hf_sv_phsmeas_q_badreference
,
177 &hf_sv_phsmeas_q_oscillatory
,
178 &hf_sv_phsmeas_q_failure
,
179 &hf_sv_phsmeas_q_olddata
,
180 &hf_sv_phsmeas_q_inconsistent
,
181 &hf_sv_phsmeas_q_inaccurate
,
182 &hf_sv_phsmeas_q_source
,
183 &hf_sv_phsmeas_q_test
,
184 &hf_sv_phsmeas_q_operatorblocked
,
185 &hf_sv_phsmeas_q_derived
,
190 offset
=dissect_ber_identifier(pinfo
, tree
, tvb
, offset
, &ber_class
, &pc
, &tag
);
191 offset
=dissect_ber_length(pinfo
, tree
, tvb
, offset
, &len
, NULL
);
193 len
=tvb_reported_length_remaining(tvb
, offset
);
196 subtree
= proto_tree_add_subtree(tree
, tvb
, offset
, len
, ett_phsmeas
, NULL
, "PhsMeas1");
198 sv_data
.num_phsMeas
= 0;
199 for (i
= 0; i
< len
/8; i
++) {
200 if (tree
&& subtree
) {
201 value
= tvb_get_ntohl(tvb
, offset
);
202 qual
= tvb_get_ntohl(tvb
, offset
+ 4);
204 proto_tree_add_item(subtree
, hf_sv_phmeas_instmag_i
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
205 proto_tree_add_bitmask(subtree
, tvb
, offset
+ 4, hf_sv_phsmeas_q
, ett_phsmeas_q
, q_flags
, ENC_BIG_ENDIAN
);
207 if (i
< IEC61850_SV_MAX_PHSMEAS_ENTRIES
) {
208 sv_data
.phsMeas
[i
].value
= value
;
209 sv_data
.phsMeas
[i
].qual
= qual
;
210 sv_data
.num_phsMeas
++;
223 dissect_sv_INTEGER_0_65535(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
224 offset
= dissect_ber_integer(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
,
233 dissect_sv_VisibleString(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
234 offset
= dissect_ber_restricted_string(implicit_tag
, BER_UNI_TAG_VisibleString
,
235 actx
, tree
, tvb
, offset
, hf_index
,
244 dissect_sv_T_smpCnt(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
246 offset
= dissect_ber_integer(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
,
249 sv_data
.smpCnt
= value
;
257 dissect_sv_INTEGER_0_4294967295(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
258 offset
= dissect_ber_integer(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
,
267 dissect_sv_UtcTime(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
271 uint32_t nanoseconds
;
275 len
= tvb_reported_length_remaining(tvb
, offset
);
279 proto_tree_add_expert_format(tree
, actx
->pinfo
, &ei_sv_mal_utctime
, tvb
, offset
, len
,
280 "BER Error: malformed UTCTime encoding, length must be 8 bytes");
283 proto_tree_add_string(tree
, hf_index
, tvb
, offset
, len
, "????");
288 seconds
= tvb_get_ntohl(tvb
, offset
);
289 fraction
= tvb_get_ntoh24(tvb
, offset
+4) * 0x100; /* Only 3 bytes are recommended */
290 nanoseconds
= (uint32_t)( ((uint64_t)fraction
* UINT64_C(1000000000)) / UINT64_C(0x100000000) ) ;
293 ts
.nsecs
= nanoseconds
;
295 ptime
= abs_time_to_str(actx
->pinfo
->pool
, &ts
, ABSOLUTE_TIME_UTC
, true);
299 proto_tree_add_string(tree
, hf_index
, tvb
, offset
, len
, ptime
);
307 static const value_string sv_T_smpSynch_vals
[] = {
316 dissect_sv_T_smpSynch(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
318 offset
= dissect_ber_integer(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
,
321 sv_data
.smpSynch
= value
;
329 dissect_sv_Data(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
330 if (sv_decode_data_as_phsmeas
) {
331 offset
= dissect_PhsMeas1(implicit_tag
, actx
->pinfo
, tree
, tvb
, offset
, hf_index
);
333 offset
= dissect_ber_octet_string(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
, NULL
);
340 static const value_string sv_T_smpMod_vals
[] = {
341 { 0, "samplesPerNormalPeriod" },
342 { 1, "samplesPerSecond" },
343 { 2, "secondsPerSample" },
349 dissect_sv_T_smpMod(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
351 offset
= dissect_ber_integer(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
,
354 sv_data
.smpMod
= value
;
362 dissect_sv_GmidData(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
364 proto_item
*gmidentity_ti
;
365 proto_tree
*gmidentity_tree
;
366 const char *manuf_name
;
368 len
= tvb_reported_length_remaining(tvb
, offset
);
372 proto_tree_add_expert_format(tree
, actx
->pinfo
, &ei_sv_mal_gmidentity
, tvb
, offset
, len
,
373 "BER Error: malformed gmIdentity encoding, length must be 8 bytes");
376 proto_tree_add_string(tree
, hf_index
, tvb
, offset
, len
, "????");
381 gmidentity_ti
= proto_tree_add_item(tree
, hf_sv_gmidentity
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
383 /* EUI-64: vendor ID | 0xFF - 0xFE | card ID */
384 if (tvb_get_ntohs(tvb
, offset
+ 3) == 0xFFFE) {
385 gmidentity_tree
= proto_item_add_subtree(gmidentity_ti
, ett_gmidentity
);
387 manuf_name
= tvb_get_manuf_name(tvb
, offset
);
388 proto_tree_add_bytes_format_value(gmidentity_tree
, hf_sv_gmidentity_manuf
, tvb
, offset
, 3, NULL
, "%s", manuf_name
);
397 static const ber_sequence_t ASDU_sequence
[] = {
398 { &hf_sv_svID
, BER_CLASS_CON
, 0, BER_FLAGS_IMPLTAG
, dissect_sv_VisibleString
},
399 { &hf_sv_datSet
, BER_CLASS_CON
, 1, BER_FLAGS_OPTIONAL
|BER_FLAGS_IMPLTAG
, dissect_sv_VisibleString
},
400 { &hf_sv_smpCnt
, BER_CLASS_CON
, 2, BER_FLAGS_IMPLTAG
, dissect_sv_T_smpCnt
},
401 { &hf_sv_confRev
, BER_CLASS_CON
, 3, BER_FLAGS_IMPLTAG
, dissect_sv_INTEGER_0_4294967295
},
402 { &hf_sv_refrTm
, BER_CLASS_CON
, 4, BER_FLAGS_OPTIONAL
|BER_FLAGS_IMPLTAG
, dissect_sv_UtcTime
},
403 { &hf_sv_smpSynch
, BER_CLASS_CON
, 5, BER_FLAGS_OPTIONAL
|BER_FLAGS_IMPLTAG
, dissect_sv_T_smpSynch
},
404 { &hf_sv_smpRate
, BER_CLASS_CON
, 6, BER_FLAGS_OPTIONAL
|BER_FLAGS_IMPLTAG
, dissect_sv_INTEGER_0_65535
},
405 { &hf_sv_seqData
, BER_CLASS_CON
, 7, BER_FLAGS_IMPLTAG
, dissect_sv_Data
},
406 { &hf_sv_smpMod
, BER_CLASS_CON
, 8, BER_FLAGS_OPTIONAL
|BER_FLAGS_IMPLTAG
, dissect_sv_T_smpMod
},
407 { &hf_sv_gmidData
, BER_CLASS_CON
, 9, BER_FLAGS_OPTIONAL
|BER_FLAGS_IMPLTAG
, dissect_sv_GmidData
},
408 { NULL
, 0, 0, 0, NULL
}
412 dissect_sv_ASDU(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
413 offset
= dissect_ber_sequence(implicit_tag
, actx
, tree
, tvb
, offset
,
414 ASDU_sequence
, hf_index
, ett_sv_ASDU
);
420 static const ber_sequence_t SEQUENCE_OF_ASDU_sequence_of
[1] = {
421 { &hf_sv_seqASDU_item
, BER_CLASS_UNI
, BER_UNI_TAG_SEQUENCE
, BER_FLAGS_NOOWNTAG
, dissect_sv_ASDU
},
425 dissect_sv_SEQUENCE_OF_ASDU(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
426 offset
= dissect_ber_sequence_of(implicit_tag
, actx
, tree
, tvb
, offset
,
427 SEQUENCE_OF_ASDU_sequence_of
, hf_index
, ett_sv_SEQUENCE_OF_ASDU
);
433 static const ber_sequence_t SavPdu_sequence
[] = {
434 { &hf_sv_noASDU
, BER_CLASS_CON
, 0, BER_FLAGS_IMPLTAG
, dissect_sv_INTEGER_0_65535
},
435 { &hf_sv_seqASDU
, BER_CLASS_CON
, 2, BER_FLAGS_IMPLTAG
, dissect_sv_SEQUENCE_OF_ASDU
},
436 { NULL
, 0, 0, 0, NULL
}
440 dissect_sv_SavPdu(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
441 offset
= dissect_ber_sequence(implicit_tag
, actx
, tree
, tvb
, offset
,
442 SavPdu_sequence
, hf_index
, ett_sv_SavPdu
);
448 static const ber_choice_t SampledValues_choice
[] = {
449 { 0, &hf_sv_savPdu
, BER_CLASS_APP
, 0, BER_FLAGS_IMPLTAG
, dissect_sv_SavPdu
},
450 { 0, NULL
, 0, 0, 0, NULL
}
454 dissect_sv_SampledValues(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
455 offset
= dissect_ber_choice(actx
, tree
, tvb
, offset
,
456 SampledValues_choice
, hf_index
, ett_sv_SampledValues
,
464 * Dissect SV PDUs inside a PPDU.
467 dissect_sv(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data _U_
)
471 unsigned sv_length
= 0;
475 static int * const reserve1_flags
[] = {
476 &hf_sv_reserve1_s_bit
,
482 asn1_ctx_init(&asn1_ctx
, ASN1_ENC_BER
, true, pinfo
);
484 item
= proto_tree_add_item(parent_tree
, proto_sv
, tvb
, 0, -1, ENC_NA
);
485 tree
= proto_item_add_subtree(item
, ett_sv
);
487 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, PNAME
);
488 col_clear(pinfo
->cinfo
, COL_INFO
);
491 proto_tree_add_item(tree
, hf_sv_appid
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
494 proto_tree_add_item_ret_uint(tree
, hf_sv_length
, tvb
, offset
+ 2, 2, ENC_BIG_ENDIAN
, &sv_length
);
497 proto_tree_add_bitmask(tree
, tvb
, offset
+ 4, hf_sv_reserve1
, ett_reserve1
,
498 reserve1_flags
, ENC_BIG_ENDIAN
);
502 proto_tree_add_item(tree
, hf_sv_reserve2
, tvb
, offset
+ 6, 2, ENC_BIG_ENDIAN
);
505 set_actual_length(tvb
, sv_length
);
506 while (tvb_reported_length_remaining(tvb
, offset
) > 0) {
508 offset
= dissect_sv_SampledValues(false, tvb
, offset
, &asn1_ctx
, tree
, -1);
509 if (offset
== old_offset
) {
510 proto_tree_add_expert(tree
, pinfo
, &ei_sv_zero_pdu
, tvb
, offset
, -1);
515 tap_queue_packet(sv_tap
, pinfo
, &sv_data
);
516 return tvb_captured_length(tvb
);
520 /*--- proto_register_sv -------------------------------------------*/
521 void proto_register_sv(void) {
524 static hf_register_info hf
[] = {
526 { "APPID", "sv.appid", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
529 { "Length", "sv.length", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
532 { "Reserved 1", "sv.reserve1", FT_UINT16
, BASE_HEX_DEC
, NULL
, 0x0, NULL
, HFILL
}},
534 { &hf_sv_reserve1_s_bit
,
535 { "Simulated", "sv.reserve1.s_bit",
536 FT_BOOLEAN
, 16, NULL
, F_RESERVE1_S_BIT
, NULL
, HFILL
} },
539 { "Reserved 2", "sv.reserve2", FT_UINT16
, BASE_HEX_DEC
, NULL
, 0x0, NULL
, HFILL
}},
541 { &hf_sv_phmeas_instmag_i
,
542 { "value", "sv.meas_value", FT_INT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
545 { "quality", "sv.meas_quality", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
547 { &hf_sv_phsmeas_q_validity
,
548 { "validity", "sv.meas_quality.validity", FT_UINT32
, BASE_HEX
, VALS(sv_q_validity_vals
), Q_VALIDITY_MASK
, NULL
, HFILL
}},
550 { &hf_sv_phsmeas_q_overflow
,
551 { "overflow", "sv.meas_quality.overflow", FT_BOOLEAN
, 32, NULL
, Q_OVERFLOW
, NULL
, HFILL
}},
553 { &hf_sv_phsmeas_q_outofrange
,
554 { "out of range", "sv.meas_quality.outofrange", FT_BOOLEAN
, 32, NULL
, Q_OUTOFRANGE
, NULL
, HFILL
}},
556 { &hf_sv_phsmeas_q_badreference
,
557 { "bad reference", "sv.meas_quality.badreference", FT_BOOLEAN
, 32, NULL
, Q_BADREFERENCE
, NULL
, HFILL
}},
559 { &hf_sv_phsmeas_q_oscillatory
,
560 { "oscillatory", "sv.meas_quality.oscillatory", FT_BOOLEAN
, 32, NULL
, Q_OSCILLATORY
, NULL
, HFILL
}},
562 { &hf_sv_phsmeas_q_failure
,
563 { "failure", "sv.meas_quality.failure", FT_BOOLEAN
, 32, NULL
, Q_FAILURE
, NULL
, HFILL
}},
565 { &hf_sv_phsmeas_q_olddata
,
566 { "old data", "sv.meas_quality.olddata", FT_BOOLEAN
, 32, NULL
, Q_OLDDATA
, NULL
, HFILL
}},
568 { &hf_sv_phsmeas_q_inconsistent
,
569 { "inconsistent", "sv.meas_quality.inconsistent", FT_BOOLEAN
, 32, NULL
, Q_INCONSISTENT
, NULL
, HFILL
}},
571 { &hf_sv_phsmeas_q_inaccurate
,
572 { "inaccurate", "sv.meas_quality.inaccurate", FT_BOOLEAN
, 32, NULL
, Q_INACCURATE
, NULL
, HFILL
}},
574 { &hf_sv_phsmeas_q_source
,
575 { "source", "sv.meas_quality.source", FT_UINT32
, BASE_HEX
, VALS(sv_q_source_vals
), Q_SOURCE_MASK
, NULL
, HFILL
}},
577 { &hf_sv_phsmeas_q_test
,
578 { "test", "sv.meas_quality.test", FT_BOOLEAN
, 32, NULL
, Q_TEST
, NULL
, HFILL
}},
580 { &hf_sv_phsmeas_q_operatorblocked
,
581 { "operator blocked", "sv.meas_quality.operatorblocked", FT_BOOLEAN
, 32, NULL
, Q_OPERATORBLOCKED
, NULL
, HFILL
}},
583 { &hf_sv_phsmeas_q_derived
,
584 { "derived", "sv.meas_quality.derived", FT_BOOLEAN
, 32, NULL
, Q_DERIVED
, NULL
, HFILL
}},
587 { "gmIdentity", "sv.gmidentity", FT_UINT64
, BASE_HEX
, NULL
, 0x00, NULL
, HFILL
}},
589 { &hf_sv_gmidentity_manuf
,
590 { "MAC Vendor", "sv.gmidentity_manuf", FT_BYTES
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}},
594 { "savPdu", "sv.savPdu_element",
595 FT_NONE
, BASE_NONE
, NULL
, 0,
598 { "noASDU", "sv.noASDU",
599 FT_UINT32
, BASE_DEC
, NULL
, 0,
600 "INTEGER_0_65535", HFILL
}},
602 { "seqASDU", "sv.seqASDU",
603 FT_UINT32
, BASE_DEC
, NULL
, 0,
604 "SEQUENCE_OF_ASDU", HFILL
}},
605 { &hf_sv_seqASDU_item
,
606 { "ASDU", "sv.ASDU_element",
607 FT_NONE
, BASE_NONE
, NULL
, 0,
611 FT_STRING
, BASE_NONE
, NULL
, 0,
612 "VisibleString", HFILL
}},
614 { "datSet", "sv.datSet",
615 FT_STRING
, BASE_NONE
, NULL
, 0,
616 "VisibleString", HFILL
}},
618 { "smpCnt", "sv.smpCnt",
619 FT_UINT32
, BASE_DEC
, NULL
, 0,
622 { "confRev", "sv.confRev",
623 FT_UINT32
, BASE_DEC
, NULL
, 0,
624 "INTEGER_0_4294967295", HFILL
}},
626 { "refrTm", "sv.refrTm",
627 FT_STRING
, BASE_NONE
, NULL
, 0,
630 { "smpSynch", "sv.smpSynch",
631 FT_INT32
, BASE_DEC
, VALS(sv_T_smpSynch_vals
), 0,
634 { "smpRate", "sv.smpRate",
635 FT_UINT32
, BASE_DEC
, NULL
, 0,
636 "INTEGER_0_65535", HFILL
}},
638 { "seqData", "sv.seqData",
639 FT_BYTES
, BASE_NONE
, NULL
, 0,
642 { "smpMod", "sv.smpMod",
643 FT_INT32
, BASE_DEC
, VALS(sv_T_smpMod_vals
), 0,
646 { "gmidData", "sv.gmidData",
647 FT_BYTES
, BASE_NONE
, NULL
, 0,
651 /* List of subtrees */
652 static int *ett
[] = {
658 &ett_sv_SampledValues
,
660 &ett_sv_SEQUENCE_OF_ASDU
,
664 static ei_register_info ei
[] = {
665 { &ei_sv_mal_utctime
, { "sv.malformed.utctime", PI_MALFORMED
, PI_WARN
, "BER Error: malformed UTCTime encoding", EXPFILL
}},
666 { &ei_sv_zero_pdu
, { "sv.zero_pdu", PI_PROTOCOL
, PI_ERROR
, "Internal error, zero-byte SV PDU", EXPFILL
}},
667 { &ei_sv_mal_gmidentity
, { "sv.malformed.gmidentity", PI_MALFORMED
, PI_WARN
, "BER Error: malformed gmIdentity encoding", EXPFILL
}},
670 expert_module_t
* expert_sv
;
673 /* Register protocol */
674 proto_sv
= proto_register_protocol(PNAME
, PSNAME
, PFNAME
);
675 sv_handle
= register_dissector("sv", dissect_sv
, proto_sv
);
677 /* Register fields and subtrees */
678 proto_register_field_array(proto_sv
, hf
, array_length(hf
));
679 proto_register_subtree_array(ett
, array_length(ett
));
680 expert_sv
= expert_register_protocol(proto_sv
);
681 expert_register_field_array(expert_sv
, ei
, array_length(ei
));
682 sv_module
= prefs_register_protocol(proto_sv
, NULL
);
683 prefs_register_bool_preference(sv_module
, "decode_data_as_phsmeas",
684 "Force decoding of seqData as PhsMeas",
685 NULL
, &sv_decode_data_as_phsmeas
);
688 sv_tap
= register_tap("sv");
691 /*--- proto_reg_handoff_sv --- */
692 void proto_reg_handoff_sv(void) {
693 dissector_add_uint("ethertype", ETHERTYPE_IEC61850_SV
, sv_handle
);