Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-sv.c
blobb4b936206e0068e380682fbeefd20eb05d2524a6
1 /* Do not modify this file. Changes will be overwritten. */
2 /* Generated automatically by the ASN.1 to Wireshark dissector compiler */
3 /* packet-sv.c */
4 /* asn2wrs.py -b -q -L -p sv -c ./sv.cnf -s ./packet-sv-template -D . -O ../.. sv.asn */
6 /* packet-sv.c
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
17 #include "config.h"
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"
30 #include "tap.h"
32 #include "packet-sv.h"
34 #define PNAME "IEC61850 Sampled Values"
35 #define PSNAME "SV"
36 #define PFNAME "sv"
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);
71 /* Data for SV tap */
72 static int sv_tap;
73 static sv_frame_data sv_data;
75 /* Initialize the protocol and registered fields */
76 static int proto_sv;
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 */
116 static int ett_sv;
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;
137 * See
138 * IEC 61850-9-2 Edition 2.1 2020-02,
139 * Section 8.6 Definitions for basic data types – Presentation layer functionality,
140 * Table 21
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[] = {
147 { 0, "good" },
148 { 1, "invalid (backwards compatible)" },
149 { 2, "invalid" },
150 { 3, "questionable" },
151 { 0, NULL }
154 static const value_string sv_q_source_vals[] = {
155 { 0, "process" },
156 { 1, "substituted" },
157 { 0, NULL }
160 static int
161 dissect_PhsMeas1(bool implicit_tag, packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, int hf_id _U_)
163 int8_t ber_class;
164 bool pc;
165 int32_t tag;
166 uint32_t len;
167 proto_tree *subtree;
168 int32_t value;
169 uint32_t qual;
170 uint32_t i;
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,
186 NULL
189 if (!implicit_tag) {
190 offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &ber_class, &pc, &tag);
191 offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL);
192 } else {
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++;
214 offset += 8;
217 return offset;
222 static int
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,
225 NULL);
227 return offset;
232 static int
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,
236 NULL);
238 return offset;
243 static int
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_) {
245 uint32_t value;
246 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
247 &value);
249 sv_data.smpCnt = value;
251 return offset;
256 static int
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,
259 NULL);
261 return offset;
266 static int
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_) {
268 uint32_t len;
269 uint32_t seconds;
270 uint32_t fraction;
271 uint32_t nanoseconds;
272 nstime_t ts;
273 char * ptime;
275 len = tvb_reported_length_remaining(tvb, offset);
277 if(len != 8)
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");
281 if(hf_index > 0)
283 proto_tree_add_string(tree, hf_index, tvb, offset, len, "????");
285 return offset;
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) ) ;
292 ts.secs = seconds;
293 ts.nsecs = nanoseconds;
295 ptime = abs_time_to_str(actx->pinfo->pool, &ts, ABSOLUTE_TIME_UTC, true);
297 if(hf_index > 0)
299 proto_tree_add_string(tree, hf_index, tvb, offset, len, ptime);
301 offset += 8;
303 return offset;
307 static const value_string sv_T_smpSynch_vals[] = {
308 { 0, "none" },
309 { 1, "local" },
310 { 2, "global" },
311 { 0, NULL }
315 static int
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_) {
317 uint32_t value;
318 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
319 &value);
321 sv_data.smpSynch = value;
323 return offset;
328 static int
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);
332 } else {
333 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index, NULL);
336 return offset;
340 static const value_string sv_T_smpMod_vals[] = {
341 { 0, "samplesPerNormalPeriod" },
342 { 1, "samplesPerSecond" },
343 { 2, "secondsPerSample" },
344 { 0, NULL }
348 static int
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_) {
350 uint32_t value;
351 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
352 &value);
354 sv_data.smpMod = value;
356 return offset;
361 static int
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_) {
363 uint32_t len;
364 proto_item *gmidentity_ti;
365 proto_tree *gmidentity_tree;
366 const char *manuf_name;
368 len = tvb_reported_length_remaining(tvb, offset);
370 if(len != 8)
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");
374 if(hf_index > 0)
376 proto_tree_add_string(tree, hf_index, tvb, offset, len, "????");
378 return offset;
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);
391 offset += 8;
393 return offset;
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 }
411 static int
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);
416 return offset;
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 },
424 static int
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);
429 return offset;
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 }
439 static int
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);
444 return offset;
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 }
453 static int
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,
457 NULL);
459 return offset;
464 * Dissect SV PDUs inside a PPDU.
466 static int
467 dissect_sv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_)
469 int offset = 0;
470 int old_offset;
471 unsigned sv_length = 0;
472 proto_item *item;
473 proto_tree *tree;
475 static int * const reserve1_flags[] = {
476 &hf_sv_reserve1_s_bit,
477 NULL
480 asn1_ctx_t asn1_ctx;
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);
490 /* APPID */
491 proto_tree_add_item(tree, hf_sv_appid, tvb, offset, 2, ENC_BIG_ENDIAN);
493 /* Length */
494 proto_tree_add_item_ret_uint(tree, hf_sv_length, tvb, offset + 2, 2, ENC_BIG_ENDIAN, &sv_length);
496 /* Reserved 1 */
497 proto_tree_add_bitmask(tree, tvb, offset + 4, hf_sv_reserve1, ett_reserve1,
498 reserve1_flags, ENC_BIG_ENDIAN);
501 /* Reserved 2 */
502 proto_tree_add_item(tree, hf_sv_reserve2, tvb, offset + 6, 2, ENC_BIG_ENDIAN);
504 offset = 8;
505 set_actual_length(tvb, sv_length);
506 while (tvb_reported_length_remaining(tvb, offset) > 0) {
507 old_offset = offset;
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);
511 break;
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) {
523 /* List of fields */
524 static hf_register_info hf[] = {
525 { &hf_sv_appid,
526 { "APPID", "sv.appid", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
528 { &hf_sv_length,
529 { "Length", "sv.length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
531 { &hf_sv_reserve1,
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 } },
538 { &hf_sv_reserve2,
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}},
544 { &hf_sv_phsmeas_q,
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}},
586 { &hf_sv_gmidentity,
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}},
593 { &hf_sv_savPdu,
594 { "savPdu", "sv.savPdu_element",
595 FT_NONE, BASE_NONE, NULL, 0,
596 NULL, HFILL }},
597 { &hf_sv_noASDU,
598 { "noASDU", "sv.noASDU",
599 FT_UINT32, BASE_DEC, NULL, 0,
600 "INTEGER_0_65535", HFILL }},
601 { &hf_sv_seqASDU,
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,
608 NULL, HFILL }},
609 { &hf_sv_svID,
610 { "svID", "sv.svID",
611 FT_STRING, BASE_NONE, NULL, 0,
612 "VisibleString", HFILL }},
613 { &hf_sv_datSet,
614 { "datSet", "sv.datSet",
615 FT_STRING, BASE_NONE, NULL, 0,
616 "VisibleString", HFILL }},
617 { &hf_sv_smpCnt,
618 { "smpCnt", "sv.smpCnt",
619 FT_UINT32, BASE_DEC, NULL, 0,
620 NULL, HFILL }},
621 { &hf_sv_confRev,
622 { "confRev", "sv.confRev",
623 FT_UINT32, BASE_DEC, NULL, 0,
624 "INTEGER_0_4294967295", HFILL }},
625 { &hf_sv_refrTm,
626 { "refrTm", "sv.refrTm",
627 FT_STRING, BASE_NONE, NULL, 0,
628 "UtcTime", HFILL }},
629 { &hf_sv_smpSynch,
630 { "smpSynch", "sv.smpSynch",
631 FT_INT32, BASE_DEC, VALS(sv_T_smpSynch_vals), 0,
632 NULL, HFILL }},
633 { &hf_sv_smpRate,
634 { "smpRate", "sv.smpRate",
635 FT_UINT32, BASE_DEC, NULL, 0,
636 "INTEGER_0_65535", HFILL }},
637 { &hf_sv_seqData,
638 { "seqData", "sv.seqData",
639 FT_BYTES, BASE_NONE, NULL, 0,
640 "Data", HFILL }},
641 { &hf_sv_smpMod,
642 { "smpMod", "sv.smpMod",
643 FT_INT32, BASE_DEC, VALS(sv_T_smpMod_vals), 0,
644 NULL, HFILL }},
645 { &hf_sv_gmidData,
646 { "gmidData", "sv.gmidData",
647 FT_BYTES, BASE_NONE, NULL, 0,
648 NULL, HFILL }},
651 /* List of subtrees */
652 static int *ett[] = {
653 &ett_sv,
654 &ett_phsmeas,
655 &ett_phsmeas_q,
656 &ett_gmidentity,
657 &ett_reserve1,
658 &ett_sv_SampledValues,
659 &ett_sv_SavPdu,
660 &ett_sv_SEQUENCE_OF_ASDU,
661 &ett_sv_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;
671 module_t *sv_module;
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);
687 /* Register tap */
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);