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 goose -c ./goose.cnf -s ./packet-goose-template -D . -O ../.. goose.asn */
7 * Routines for IEC 61850 GOOSE packet dissection
10 * Routines for IEC 61850 R-GOOSE packet dissection
11 * Dordije Manojlovic 2020
13 * Wireshark - Network traffic analyzer
14 * By Gerald Combs <gerald@wireshark.org>
15 * Copyright 1998 Gerald Combs
17 * SPDX-License-Identifier: GPL-2.0-or-later
22 #include <epan/packet.h>
23 #include <epan/asn1.h>
24 #include <epan/proto_data.h>
25 #include <epan/etypes.h>
26 #include <epan/expert.h>
27 #include <wsutil/array.h>
29 #include "packet-ber.h"
30 #include "packet-acse.h"
32 #define GOOSE_PNAME "GOOSE"
33 #define GOOSE_PSNAME "GOOSE"
34 #define GOOSE_PFNAME "goose"
36 #define R_GOOSE_PNAME "R-GOOSE"
37 #define R_GOOSE_PSNAME "R-GOOSE"
38 #define R_GOOSE_PFNAME "r-goose"
40 void proto_register_goose(void);
41 void proto_reg_handoff_goose(void);
43 /* Initialize the protocol and registered fields */
44 static int proto_goose
;
45 static int proto_r_goose
;
47 static int hf_goose_session_header
;
48 static int hf_goose_spdu_id
;
49 static int hf_goose_session_hdr_length
;
50 static int hf_goose_hdr_length
;
51 static int hf_goose_content_id
;
52 static int hf_goose_spdu_lenth
;
53 static int hf_goose_spdu_num
;
54 static int hf_goose_version
;
55 static int hf_goose_security_info
;
56 static int hf_goose_current_key_t
;
57 static int hf_goose_next_key_t
;
58 static int hf_goose_key_id
;
59 static int hf_goose_init_vec_length
;
60 static int hf_goose_init_vec
;
61 static int hf_goose_session_user_info
;
62 static int hf_goose_payload
;
63 static int hf_goose_payload_length
;
64 static int hf_goose_apdu_tag
;
65 static int hf_goose_apdu_simulation
;
66 static int hf_goose_apdu_appid
;
67 static int hf_goose_apdu_length
;
68 static int hf_goose_padding_tag
;
69 static int hf_goose_padding_length
;
70 static int hf_goose_padding
;
71 static int hf_goose_hmac
;
72 static int hf_goose_appid
;
73 static int hf_goose_length
;
74 static int hf_goose_reserve1
;
75 static int hf_goose_reserve1_s_bit
;
76 static int hf_goose_reserve2
;
77 static int hf_goose_float_value
;
80 /* Bit fields in the Reserved fields */
81 #define F_RESERVE1_S_BIT 0x8000
83 /* GOOSE stored data for expert info verifications */
84 typedef struct _goose_chk_data
{
87 #define GOOSE_CHK_DATA_LEN (sizeof(goose_chk_data_t))
89 static expert_field ei_goose_mal_utctime
;
90 static expert_field ei_goose_zero_pdu
;
91 static expert_field ei_goose_invalid_sim
;
92 static expert_field ei_goose_bogus_length
;
94 #define SINGLE_FLOAT_EXP_BITS 8
95 #define FLOAT_ENC_LENGTH 5
97 static int hf_goose_gseMngtPdu
; /* GSEMngtPdu */
98 static int hf_goose_goosePdu
; /* IECGoosePdu */
99 static int hf_goose_stateID
; /* INTEGER */
100 static int hf_goose_requestResp
; /* RequestResponse */
101 static int hf_goose_requests
; /* GSEMngtRequests */
102 static int hf_goose_responses
; /* GSEMngtResponses */
103 static int hf_goose_getGoReference
; /* GetReferenceRequestPdu */
104 static int hf_goose_getGOOSEElementNumber
; /* GetElementRequestPdu */
105 static int hf_goose_getGsReference
; /* GetReferenceRequestPdu */
106 static int hf_goose_getGSSEDataOffset
; /* GetElementRequestPdu */
107 static int hf_goose_gseMngtNotSupported
; /* NULL */
108 static int hf_goose_gseMngtResponses_GetGOReference
; /* GSEMngtResponsePdu */
109 static int hf_goose_gseMngtResponses_GetGOOSEElementNumber
; /* GSEMngtResponsePdu */
110 static int hf_goose_gseMngtResponses_GetGSReference
; /* GSEMngtResponsePdu */
111 static int hf_goose_gseMngtResponses_GetGSSEDataOffset
; /* GSEMngtResponsePdu */
112 static int hf_goose_ident
; /* VisibleString */
113 static int hf_goose_getReferenceRequest_offset
; /* T_getReferenceRequest_offset */
114 static int hf_goose_getReferenceRequest_offset_item
; /* INTEGER */
115 static int hf_goose_references
; /* T_references */
116 static int hf_goose_references_item
; /* VisibleString */
117 static int hf_goose_confRev
; /* INTEGER */
118 static int hf_goose_posNeg
; /* PositiveNegative */
119 static int hf_goose_responsePositive
; /* T_responsePositive */
120 static int hf_goose_datSet
; /* VisibleString */
121 static int hf_goose_result
; /* SEQUENCE_OF_RequestResults */
122 static int hf_goose_result_item
; /* RequestResults */
123 static int hf_goose_responseNegative
; /* GlbErrors */
124 static int hf_goose_offset
; /* INTEGER */
125 static int hf_goose_reference
; /* IA5String */
126 static int hf_goose_error
; /* ErrorReason */
127 static int hf_goose_gocbRef
; /* VisibleString */
128 static int hf_goose_timeAllowedtoLive
; /* INTEGER */
129 static int hf_goose_goID
; /* VisibleString */
130 static int hf_goose_t
; /* UtcTime */
131 static int hf_goose_stNum
; /* INTEGER */
132 static int hf_goose_sqNum
; /* INTEGER */
133 static int hf_goose_simulation
; /* T_simulation */
134 static int hf_goose_ndsCom
; /* BOOLEAN */
135 static int hf_goose_numDatSetEntries
; /* INTEGER */
136 static int hf_goose_allData
; /* SEQUENCE_OF_Data */
137 static int hf_goose_allData_item
; /* Data */
138 static int hf_goose_array
; /* SEQUENCE_OF_Data */
139 static int hf_goose_array_item
; /* Data */
140 static int hf_goose_structure
; /* SEQUENCE_OF_Data */
141 static int hf_goose_structure_item
; /* Data */
142 static int hf_goose_boolean
; /* BOOLEAN */
143 static int hf_goose_bit_string
; /* BIT_STRING */
144 static int hf_goose_integer
; /* INTEGER */
145 static int hf_goose_unsigned
; /* INTEGER */
146 static int hf_goose_floating_point
; /* FloatingPoint */
147 static int hf_goose_real
; /* REAL */
148 static int hf_goose_octet_string
; /* OCTET_STRING */
149 static int hf_goose_visible_string
; /* VisibleString */
150 static int hf_goose_binary_time
; /* TimeOfDay */
151 static int hf_goose_bcd
; /* INTEGER */
152 static int hf_goose_booleanArray
; /* BIT_STRING */
153 static int hf_goose_objId
; /* OBJECT_IDENTIFIER */
154 static int hf_goose_mMSString
; /* MMSString */
155 static int hf_goose_utc_time
; /* UtcTime */
157 /* Initialize the subtree pointers */
158 static int ett_r_goose
;
159 static int ett_session_header
;
160 static int ett_security_info
;
161 static int ett_session_user_info
;
162 static int ett_payload
;
163 static int ett_padding
;
164 static int ett_goose
;
165 static int ett_reserve1
;
166 static int ett_expert_inf_sim
;
168 static int ett_goose_GOOSEpdu
;
169 static int ett_goose_GSEMngtPdu
;
170 static int ett_goose_RequestResponse
;
171 static int ett_goose_GSEMngtRequests
;
172 static int ett_goose_GSEMngtResponses
;
173 static int ett_goose_GetReferenceRequestPdu
;
174 static int ett_goose_T_getReferenceRequest_offset
;
175 static int ett_goose_GetElementRequestPdu
;
176 static int ett_goose_T_references
;
177 static int ett_goose_GSEMngtResponsePdu
;
178 static int ett_goose_PositiveNegative
;
179 static int ett_goose_T_responsePositive
;
180 static int ett_goose_SEQUENCE_OF_RequestResults
;
181 static int ett_goose_RequestResults
;
182 static int ett_goose_IECGoosePdu
;
183 static int ett_goose_SEQUENCE_OF_Data
;
184 static int ett_goose_Data
;
186 /*--- Cyclic dependencies ---*/
188 /* Data -> Data/array -> Data */
189 static int dissect_goose_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_
);
195 dissect_goose_INTEGER(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
196 offset
= dissect_ber_integer(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
,
205 dissect_goose_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_
) {
206 offset
= dissect_ber_restricted_string(implicit_tag
, BER_UNI_TAG_VisibleString
,
207 actx
, tree
, tvb
, offset
, hf_index
,
214 static const ber_sequence_t T_getReferenceRequest_offset_sequence_of
[1] = {
215 { &hf_goose_getReferenceRequest_offset_item
, BER_CLASS_UNI
, BER_UNI_TAG_INTEGER
, BER_FLAGS_NOOWNTAG
, dissect_goose_INTEGER
},
219 dissect_goose_T_getReferenceRequest_offset(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
220 offset
= dissect_ber_sequence_of(implicit_tag
, actx
, tree
, tvb
, offset
,
221 T_getReferenceRequest_offset_sequence_of
, hf_index
, ett_goose_T_getReferenceRequest_offset
);
227 static const ber_sequence_t GetReferenceRequestPdu_sequence
[] = {
228 { &hf_goose_ident
, BER_CLASS_CON
, 0, BER_FLAGS_IMPLTAG
, dissect_goose_VisibleString
},
229 { &hf_goose_getReferenceRequest_offset
, BER_CLASS_CON
, 1, BER_FLAGS_IMPLTAG
, dissect_goose_T_getReferenceRequest_offset
},
230 { NULL
, 0, 0, 0, NULL
}
234 dissect_goose_GetReferenceRequestPdu(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
235 offset
= dissect_ber_sequence(implicit_tag
, actx
, tree
, tvb
, offset
,
236 GetReferenceRequestPdu_sequence
, hf_index
, ett_goose_GetReferenceRequestPdu
);
242 static const ber_sequence_t T_references_sequence_of
[1] = {
243 { &hf_goose_references_item
, BER_CLASS_UNI
, BER_UNI_TAG_VisibleString
, BER_FLAGS_NOOWNTAG
, dissect_goose_VisibleString
},
247 dissect_goose_T_references(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
248 offset
= dissect_ber_sequence_of(implicit_tag
, actx
, tree
, tvb
, offset
,
249 T_references_sequence_of
, hf_index
, ett_goose_T_references
);
255 static const ber_sequence_t GetElementRequestPdu_sequence
[] = {
256 { &hf_goose_ident
, BER_CLASS_CON
, 0, BER_FLAGS_IMPLTAG
, dissect_goose_VisibleString
},
257 { &hf_goose_references
, BER_CLASS_CON
, 1, BER_FLAGS_IMPLTAG
, dissect_goose_T_references
},
258 { NULL
, 0, 0, 0, NULL
}
262 dissect_goose_GetElementRequestPdu(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
263 offset
= dissect_ber_sequence(implicit_tag
, actx
, tree
, tvb
, offset
,
264 GetElementRequestPdu_sequence
, hf_index
, ett_goose_GetElementRequestPdu
);
270 static const value_string goose_GSEMngtRequests_vals
[] = {
271 { 1, "getGoReference" },
272 { 2, "getGOOSEElementNumber" },
273 { 3, "getGsReference" },
274 { 4, "getGSSEDataOffset" },
278 static const ber_choice_t GSEMngtRequests_choice
[] = {
279 { 1, &hf_goose_getGoReference
, BER_CLASS_CON
, 1, BER_FLAGS_IMPLTAG
, dissect_goose_GetReferenceRequestPdu
},
280 { 2, &hf_goose_getGOOSEElementNumber
, BER_CLASS_CON
, 2, BER_FLAGS_IMPLTAG
, dissect_goose_GetElementRequestPdu
},
281 { 3, &hf_goose_getGsReference
, BER_CLASS_CON
, 3, BER_FLAGS_IMPLTAG
, dissect_goose_GetReferenceRequestPdu
},
282 { 4, &hf_goose_getGSSEDataOffset
, BER_CLASS_CON
, 4, BER_FLAGS_IMPLTAG
, dissect_goose_GetElementRequestPdu
},
283 { 0, NULL
, 0, 0, 0, NULL
}
287 dissect_goose_GSEMngtRequests(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
288 offset
= dissect_ber_choice(actx
, tree
, tvb
, offset
,
289 GSEMngtRequests_choice
, hf_index
, ett_goose_GSEMngtRequests
,
298 dissect_goose_NULL(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
299 offset
= dissect_ber_null(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
);
307 dissect_goose_IA5String(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
308 offset
= dissect_ber_restricted_string(implicit_tag
, BER_UNI_TAG_IA5String
,
309 actx
, tree
, tvb
, offset
, hf_index
,
316 static const value_string goose_ErrorReason_vals
[] = {
324 dissect_goose_ErrorReason(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
325 offset
= dissect_ber_integer(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
,
332 static const value_string goose_RequestResults_vals
[] = {
339 static const ber_choice_t RequestResults_choice
[] = {
340 { 0, &hf_goose_offset
, BER_CLASS_CON
, 0, BER_FLAGS_IMPLTAG
, dissect_goose_INTEGER
},
341 { 1, &hf_goose_reference
, BER_CLASS_CON
, 1, BER_FLAGS_IMPLTAG
, dissect_goose_IA5String
},
342 { 2, &hf_goose_error
, BER_CLASS_CON
, 2, BER_FLAGS_IMPLTAG
, dissect_goose_ErrorReason
},
343 { 0, NULL
, 0, 0, 0, NULL
}
347 dissect_goose_RequestResults(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
348 offset
= dissect_ber_choice(actx
, tree
, tvb
, offset
,
349 RequestResults_choice
, hf_index
, ett_goose_RequestResults
,
356 static const ber_sequence_t SEQUENCE_OF_RequestResults_sequence_of
[1] = {
357 { &hf_goose_result_item
, BER_CLASS_ANY
/*choice*/, -1/*choice*/, BER_FLAGS_NOOWNTAG
|BER_FLAGS_NOTCHKTAG
, dissect_goose_RequestResults
},
361 dissect_goose_SEQUENCE_OF_RequestResults(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
362 offset
= dissect_ber_sequence_of(implicit_tag
, actx
, tree
, tvb
, offset
,
363 SEQUENCE_OF_RequestResults_sequence_of
, hf_index
, ett_goose_SEQUENCE_OF_RequestResults
);
369 static const ber_sequence_t T_responsePositive_sequence
[] = {
370 { &hf_goose_datSet
, BER_CLASS_CON
, 0, BER_FLAGS_OPTIONAL
|BER_FLAGS_IMPLTAG
, dissect_goose_VisibleString
},
371 { &hf_goose_result
, BER_CLASS_CON
, 1, BER_FLAGS_IMPLTAG
, dissect_goose_SEQUENCE_OF_RequestResults
},
372 { NULL
, 0, 0, 0, NULL
}
376 dissect_goose_T_responsePositive(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
377 offset
= dissect_ber_sequence(implicit_tag
, actx
, tree
, tvb
, offset
,
378 T_responsePositive_sequence
, hf_index
, ett_goose_T_responsePositive
);
384 static const value_string goose_GlbErrors_vals
[] = {
386 { 1, "unknownControlBlock" },
387 { 2, "responseTooLarge" },
388 { 3, "controlBlockConfigurationError" },
394 dissect_goose_GlbErrors(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
395 offset
= dissect_ber_integer(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
,
402 static const value_string goose_PositiveNegative_vals
[] = {
403 { 2, "responsePositive" },
404 { 3, "responseNegative" },
408 static const ber_choice_t PositiveNegative_choice
[] = {
409 { 2, &hf_goose_responsePositive
, BER_CLASS_CON
, 2, BER_FLAGS_IMPLTAG
, dissect_goose_T_responsePositive
},
410 { 3, &hf_goose_responseNegative
, BER_CLASS_CON
, 3, BER_FLAGS_IMPLTAG
, dissect_goose_GlbErrors
},
411 { 0, NULL
, 0, 0, 0, NULL
}
415 dissect_goose_PositiveNegative(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
416 offset
= dissect_ber_choice(actx
, tree
, tvb
, offset
,
417 PositiveNegative_choice
, hf_index
, ett_goose_PositiveNegative
,
424 static const ber_sequence_t GSEMngtResponsePdu_sequence
[] = {
425 { &hf_goose_ident
, BER_CLASS_CON
, 0, BER_FLAGS_IMPLTAG
, dissect_goose_VisibleString
},
426 { &hf_goose_confRev
, BER_CLASS_CON
, 1, BER_FLAGS_OPTIONAL
|BER_FLAGS_IMPLTAG
, dissect_goose_INTEGER
},
427 { &hf_goose_posNeg
, BER_CLASS_ANY
/*choice*/, -1/*choice*/, BER_FLAGS_NOOWNTAG
|BER_FLAGS_NOTCHKTAG
, dissect_goose_PositiveNegative
},
428 { NULL
, 0, 0, 0, NULL
}
432 dissect_goose_GSEMngtResponsePdu(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
433 offset
= dissect_ber_sequence(implicit_tag
, actx
, tree
, tvb
, offset
,
434 GSEMngtResponsePdu_sequence
, hf_index
, ett_goose_GSEMngtResponsePdu
);
440 static const value_string goose_GSEMngtResponses_vals
[] = {
441 { 0, "gseMngtNotSupported" },
442 { 1, "getGoReference" },
443 { 2, "getGOOSEElementNumber" },
444 { 3, "getGsReference" },
445 { 4, "getGSSEDataOffset" },
449 static const ber_choice_t GSEMngtResponses_choice
[] = {
450 { 0, &hf_goose_gseMngtNotSupported
, BER_CLASS_CON
, 0, BER_FLAGS_IMPLTAG
, dissect_goose_NULL
},
451 { 1, &hf_goose_gseMngtResponses_GetGOReference
, BER_CLASS_CON
, 1, BER_FLAGS_IMPLTAG
, dissect_goose_GSEMngtResponsePdu
},
452 { 2, &hf_goose_gseMngtResponses_GetGOOSEElementNumber
, BER_CLASS_CON
, 2, BER_FLAGS_IMPLTAG
, dissect_goose_GSEMngtResponsePdu
},
453 { 3, &hf_goose_gseMngtResponses_GetGSReference
, BER_CLASS_CON
, 3, BER_FLAGS_IMPLTAG
, dissect_goose_GSEMngtResponsePdu
},
454 { 4, &hf_goose_gseMngtResponses_GetGSSEDataOffset
, BER_CLASS_CON
, 4, BER_FLAGS_IMPLTAG
, dissect_goose_GSEMngtResponsePdu
},
455 { 0, NULL
, 0, 0, 0, NULL
}
459 dissect_goose_GSEMngtResponses(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
460 offset
= dissect_ber_choice(actx
, tree
, tvb
, offset
,
461 GSEMngtResponses_choice
, hf_index
, ett_goose_GSEMngtResponses
,
468 static const value_string goose_RequestResponse_vals
[] = {
474 static const ber_choice_t RequestResponse_choice
[] = {
475 { 1, &hf_goose_requests
, BER_CLASS_CON
, 1, BER_FLAGS_IMPLTAG
, dissect_goose_GSEMngtRequests
},
476 { 2, &hf_goose_responses
, BER_CLASS_CON
, 2, BER_FLAGS_IMPLTAG
, dissect_goose_GSEMngtResponses
},
477 { 0, NULL
, 0, 0, 0, NULL
}
481 dissect_goose_RequestResponse(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
482 offset
= dissect_ber_choice(actx
, tree
, tvb
, offset
,
483 RequestResponse_choice
, hf_index
, ett_goose_RequestResponse
,
490 static const ber_sequence_t GSEMngtPdu_sequence
[] = {
491 { &hf_goose_stateID
, BER_CLASS_CON
, 0, BER_FLAGS_IMPLTAG
, dissect_goose_INTEGER
},
492 { &hf_goose_requestResp
, BER_CLASS_ANY
/*choice*/, -1/*choice*/, BER_FLAGS_NOOWNTAG
|BER_FLAGS_NOTCHKTAG
, dissect_goose_RequestResponse
},
493 { NULL
, 0, 0, 0, NULL
}
497 dissect_goose_GSEMngtPdu(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
498 offset
= dissect_ber_sequence(implicit_tag
, actx
, tree
, tvb
, offset
,
499 GSEMngtPdu_sequence
, hf_index
, ett_goose_GSEMngtPdu
);
507 dissect_goose_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_
) {
512 uint32_t nanoseconds
;
516 len
= tvb_reported_length_remaining(tvb
, offset
);
520 proto_tree_add_expert(tree
, actx
->pinfo
, &ei_goose_mal_utctime
, tvb
, offset
, len
);
523 proto_tree_add_string(tree
, hf_index
, tvb
, offset
, len
, "????");
528 seconds
= tvb_get_ntohl(tvb
, offset
);
529 fraction
= tvb_get_ntoh24(tvb
, offset
+4) * 0x100; /* Only 3 bytes are recommended */
530 nanoseconds
= (uint32_t)( ((uint64_t)fraction
* UINT64_C(1000000000)) / UINT64_C(0x100000000) ) ;
533 ts
.nsecs
= nanoseconds
;
535 ptime
= abs_time_to_str(actx
->pinfo
->pool
, &ts
, ABSOLUTE_TIME_UTC
, true);
539 proto_tree_add_string(tree
, hf_index
, tvb
, offset
, len
, ptime
);
549 dissect_goose_T_simulation(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
551 uint32_t len
= tvb_reported_length_remaining(tvb
, offset
);
552 int origin_offset
= offset
;
553 offset
= dissect_ber_boolean(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
, &value
);
555 if((actx
->private_data
) && (actx
->created_item
)){
556 goose_chk_data_t
*data_chk
= (goose_chk_data_t
*)actx
->private_data
;
557 proto_tree
*expert_inf_tree
= NULL
;
558 /* S bit set and Simulation attribute clear: reject as invalid GOOSE */
559 if((data_chk
->s_bit
== true) && (value
== false)){
560 /* It really looks better showed as a new subtree */
561 expert_inf_tree
= proto_item_add_subtree(actx
->created_item
, ett_expert_inf_sim
);
562 proto_tree_add_expert(expert_inf_tree
, actx
->pinfo
, &ei_goose_invalid_sim
, tvb
, origin_offset
, len
);
572 dissect_goose_BOOLEAN(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
573 offset
= dissect_ber_boolean(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
, NULL
);
579 static const ber_sequence_t SEQUENCE_OF_Data_sequence_of
[1] = {
580 { &hf_goose_allData_item
, BER_CLASS_ANY
/*choice*/, -1/*choice*/, BER_FLAGS_NOOWNTAG
|BER_FLAGS_NOTCHKTAG
, dissect_goose_Data
},
584 dissect_goose_SEQUENCE_OF_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_
) {
585 offset
= dissect_ber_sequence_of(implicit_tag
, actx
, tree
, tvb
, offset
,
586 SEQUENCE_OF_Data_sequence_of
, hf_index
, ett_goose_SEQUENCE_OF_Data
);
594 dissect_goose_BIT_STRING(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
595 offset
= dissect_ber_bitstring(implicit_tag
, actx
, tree
, tvb
, offset
,
596 NULL
, 0, hf_index
, -1,
605 dissect_goose_FloatingPoint(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
607 int len
= tvb_reported_length_remaining(tvb
, offset
);
609 offset
= dissect_ber_octet_string(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
,
612 if ((len
== FLOAT_ENC_LENGTH
) && (tvb_get_uint8(tvb
,0) == SINGLE_FLOAT_EXP_BITS
) ){
613 /* IEEE 754 single precision floating point */
614 proto_item_set_hidden(actx
->created_item
);
615 proto_tree_add_item(tree
, hf_goose_float_value
, tvb
, 1, (FLOAT_ENC_LENGTH
-1), ENC_BIG_ENDIAN
);
625 dissect_goose_REAL(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
626 offset
= dissect_ber_real(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
,
635 dissect_goose_OCTET_STRING(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
636 offset
= dissect_ber_octet_string(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
,
645 dissect_goose_TimeOfDay(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
646 offset
= dissect_ber_octet_string(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
,
655 dissect_goose_OBJECT_IDENTIFIER(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
656 offset
= dissect_ber_object_identifier(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
, NULL
);
664 dissect_goose_MMSString(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
665 offset
= dissect_ber_restricted_string(implicit_tag
, BER_UNI_TAG_UTF8String
,
666 actx
, tree
, tvb
, offset
, hf_index
,
673 static const value_string goose_Data_vals
[] = {
680 { 7, "floating-point" },
682 { 9, "octet-string" },
683 { 10, "visible-string" },
684 { 12, "binary-time" },
686 { 14, "booleanArray" },
693 static const ber_choice_t Data_choice
[] = {
694 { 1, &hf_goose_array
, BER_CLASS_CON
, 1, BER_FLAGS_IMPLTAG
, dissect_goose_SEQUENCE_OF_Data
},
695 { 2, &hf_goose_structure
, BER_CLASS_CON
, 2, BER_FLAGS_IMPLTAG
, dissect_goose_SEQUENCE_OF_Data
},
696 { 3, &hf_goose_boolean
, BER_CLASS_CON
, 3, BER_FLAGS_IMPLTAG
, dissect_goose_BOOLEAN
},
697 { 4, &hf_goose_bit_string
, BER_CLASS_CON
, 4, BER_FLAGS_IMPLTAG
, dissect_goose_BIT_STRING
},
698 { 5, &hf_goose_integer
, BER_CLASS_CON
, 5, BER_FLAGS_IMPLTAG
, dissect_goose_INTEGER
},
699 { 6, &hf_goose_unsigned
, BER_CLASS_CON
, 6, BER_FLAGS_IMPLTAG
, dissect_goose_INTEGER
},
700 { 7, &hf_goose_floating_point
, BER_CLASS_CON
, 7, BER_FLAGS_IMPLTAG
, dissect_goose_FloatingPoint
},
701 { 8, &hf_goose_real
, BER_CLASS_CON
, 8, BER_FLAGS_IMPLTAG
, dissect_goose_REAL
},
702 { 9, &hf_goose_octet_string
, BER_CLASS_CON
, 9, BER_FLAGS_IMPLTAG
, dissect_goose_OCTET_STRING
},
703 { 10, &hf_goose_visible_string
, BER_CLASS_CON
, 10, BER_FLAGS_IMPLTAG
, dissect_goose_VisibleString
},
704 { 12, &hf_goose_binary_time
, BER_CLASS_CON
, 12, BER_FLAGS_IMPLTAG
, dissect_goose_TimeOfDay
},
705 { 13, &hf_goose_bcd
, BER_CLASS_CON
, 13, BER_FLAGS_IMPLTAG
, dissect_goose_INTEGER
},
706 { 14, &hf_goose_booleanArray
, BER_CLASS_CON
, 14, BER_FLAGS_IMPLTAG
, dissect_goose_BIT_STRING
},
707 { 15, &hf_goose_objId
, BER_CLASS_CON
, 15, BER_FLAGS_IMPLTAG
, dissect_goose_OBJECT_IDENTIFIER
},
708 { 16, &hf_goose_mMSString
, BER_CLASS_CON
, 16, BER_FLAGS_IMPLTAG
, dissect_goose_MMSString
},
709 { 17, &hf_goose_utc_time
, BER_CLASS_CON
, 17, BER_FLAGS_IMPLTAG
, dissect_goose_UtcTime
},
710 { 0, NULL
, 0, 0, 0, NULL
}
714 dissect_goose_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_
) {
715 // Data -> Data/array -> Data
716 actx
->pinfo
->dissection_depth
+= 2;
717 increment_dissection_depth(actx
->pinfo
);
718 offset
= dissect_ber_choice(actx
, tree
, tvb
, offset
,
719 Data_choice
, hf_index
, ett_goose_Data
,
722 actx
->pinfo
->dissection_depth
-= 2;
723 decrement_dissection_depth(actx
->pinfo
);
728 static const ber_sequence_t IECGoosePdu_sequence
[] = {
729 { &hf_goose_gocbRef
, BER_CLASS_CON
, 0, BER_FLAGS_IMPLTAG
, dissect_goose_VisibleString
},
730 { &hf_goose_timeAllowedtoLive
, BER_CLASS_CON
, 1, BER_FLAGS_IMPLTAG
, dissect_goose_INTEGER
},
731 { &hf_goose_datSet
, BER_CLASS_CON
, 2, BER_FLAGS_IMPLTAG
, dissect_goose_VisibleString
},
732 { &hf_goose_goID
, BER_CLASS_CON
, 3, BER_FLAGS_OPTIONAL
|BER_FLAGS_IMPLTAG
, dissect_goose_VisibleString
},
733 { &hf_goose_t
, BER_CLASS_CON
, 4, BER_FLAGS_IMPLTAG
, dissect_goose_UtcTime
},
734 { &hf_goose_stNum
, BER_CLASS_CON
, 5, BER_FLAGS_IMPLTAG
, dissect_goose_INTEGER
},
735 { &hf_goose_sqNum
, BER_CLASS_CON
, 6, BER_FLAGS_IMPLTAG
, dissect_goose_INTEGER
},
736 { &hf_goose_simulation
, BER_CLASS_CON
, 7, BER_FLAGS_OPTIONAL
|BER_FLAGS_IMPLTAG
, dissect_goose_T_simulation
},
737 { &hf_goose_confRev
, BER_CLASS_CON
, 8, BER_FLAGS_IMPLTAG
, dissect_goose_INTEGER
},
738 { &hf_goose_ndsCom
, BER_CLASS_CON
, 9, BER_FLAGS_OPTIONAL
|BER_FLAGS_IMPLTAG
, dissect_goose_BOOLEAN
},
739 { &hf_goose_numDatSetEntries
, BER_CLASS_CON
, 10, BER_FLAGS_IMPLTAG
, dissect_goose_INTEGER
},
740 { &hf_goose_allData
, BER_CLASS_CON
, 11, BER_FLAGS_IMPLTAG
, dissect_goose_SEQUENCE_OF_Data
},
741 { NULL
, 0, 0, 0, NULL
}
745 dissect_goose_IECGoosePdu(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
746 offset
= dissect_ber_sequence(implicit_tag
, actx
, tree
, tvb
, offset
,
747 IECGoosePdu_sequence
, hf_index
, ett_goose_IECGoosePdu
);
753 static const ber_choice_t GOOSEpdu_choice
[] = {
754 { 0, &hf_goose_gseMngtPdu
, BER_CLASS_APP
, 0, BER_FLAGS_IMPLTAG
, dissect_goose_GSEMngtPdu
},
755 { 1, &hf_goose_goosePdu
, BER_CLASS_APP
, 1, BER_FLAGS_IMPLTAG
, dissect_goose_IECGoosePdu
},
756 { 0, NULL
, 0, 0, 0, NULL
}
760 dissect_goose_GOOSEpdu(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
761 offset
= dissect_ber_choice(actx
, tree
, tvb
, offset
,
762 GOOSEpdu_choice
, hf_index
, ett_goose_GOOSEpdu
,
769 static dissector_handle_t goose_handle
;
772 #define OSI_SPDU_TUNNELED 0xA0 /* Tunneled */
773 #define OSI_SPDU_GOOSE 0xA1 /* GOOSE */
774 #define OSI_SPDU_SV 0xA2 /* Sample Value */
775 #define OSI_SPDU_MNGT 0xA3 /* Management */
777 static const value_string ositp_spdu_id
[] = {
778 { OSI_SPDU_TUNNELED
, "Tunneled" },
779 { OSI_SPDU_GOOSE
, "GOOSE" },
780 { OSI_SPDU_SV
, "Sample value" },
781 { OSI_SPDU_MNGT
, "Management" },
785 #define OSI_PDU_GOOSE 0x81
786 #define OSI_PDU_SV 0x82
787 #define OSI_PDU_TUNNELED 0x83
788 #define OSI_PDU_MNGT 0x84
790 static const value_string ositp_pdu_id
[] = {
791 { OSI_PDU_GOOSE
, "GOOSE" },
792 { OSI_PDU_SV
, "SV" },
793 { OSI_PDU_TUNNELED
, "Tunnel" },
794 { OSI_PDU_MNGT
, "MNGT" },
798 #define APDU_HEADER_SIZE 6
801 * Dissect GOOSE PDUs inside a PPDU.
804 dissect_goose(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
,
810 uint32_t reserve1_val
;
811 proto_item
*item
= NULL
;
812 proto_item
*tree_item
= NULL
;
813 proto_tree
*tree
= NULL
;
814 goose_chk_data_t
*data_chk
= NULL
;
816 asn1_ctx_init(&asn1_ctx
, ASN1_ENC_BER
, true, pinfo
);
818 static int * const reserve1_flags
[] = {
819 &hf_goose_reserve1_s_bit
,
823 asn1_ctx
.private_data
= wmem_alloc(pinfo
->pool
, GOOSE_CHK_DATA_LEN
);
824 data_chk
= (goose_chk_data_t
*)asn1_ctx
.private_data
;
826 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, GOOSE_PNAME
);
827 col_clear(pinfo
->cinfo
, COL_INFO
);
829 tree_item
= proto_tree_add_item(parent_tree
, proto_goose
, tvb
, 0, -1, ENC_NA
);
830 tree
= proto_item_add_subtree(tree_item
, ett_goose
);
831 add_ber_encoded_label(tvb
, pinfo
, parent_tree
);
835 proto_tree_add_item(tree
, hf_goose_appid
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
838 item
= proto_tree_add_item_ret_uint(tree
, hf_goose_length
, tvb
, offset
+ 2, 2,
839 ENC_BIG_ENDIAN
, &length
);
841 expert_add_info(pinfo
, item
, &ei_goose_bogus_length
);
843 set_actual_length(tvb
, length
);
844 proto_item_set_len(tree_item
, length
);
847 reserve1_val
= tvb_get_uint16(tvb
, offset
+ 4, ENC_BIG_ENDIAN
);
848 proto_tree_add_bitmask_value(tree
, tvb
, offset
+ 4, hf_goose_reserve1
, ett_reserve1
,
849 reserve1_flags
, reserve1_val
);
851 /* Store the header sim value for later expert info checks */
853 if(reserve1_val
& F_RESERVE1_S_BIT
){
854 data_chk
->s_bit
= true;
856 data_chk
->s_bit
= false;
862 proto_tree_add_item(tree
, hf_goose_reserve2
, tvb
, offset
+ 6, 2,
866 while (offset
< length
){
868 offset
= dissect_goose_GOOSEpdu(false, tvb
, offset
, &asn1_ctx
, tree
, -1);
869 if (offset
== old_offset
) {
870 proto_tree_add_expert(tree
, pinfo
, &ei_goose_zero_pdu
, tvb
, offset
, -1);
875 return tvb_captured_length(tvb
);
879 * Dissect RGOOSE PDUs inside ISO 8602/X.234 CLTP ConnecteionLess
880 * Transport Protocol.
883 dissect_rgoose(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
,
886 unsigned offset
= 0, old_offset
= 0;
887 uint32_t init_v_length
, payload_tag
, padding_length
, length
;
888 uint32_t payload_length
, apdu_offset
= 0, apdu_length
, apdu_simulation
;
889 proto_item
*item
= NULL
;
890 proto_tree
*tree
= NULL
, *r_goose_tree
= NULL
, *sess_user_info_tree
= NULL
;
891 goose_chk_data_t
*data_chk
= NULL
;
893 asn1_ctx_init(&asn1_ctx
, ASN1_ENC_BER
, true, pinfo
);
895 asn1_ctx
.private_data
= wmem_alloc(pinfo
->pool
, GOOSE_CHK_DATA_LEN
);
896 data_chk
= (goose_chk_data_t
*)asn1_ctx
.private_data
;
898 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, R_GOOSE_PNAME
);
899 col_clear(pinfo
->cinfo
, COL_INFO
);
901 item
= proto_tree_add_item(parent_tree
, proto_r_goose
, tvb
, 0, -1, ENC_NA
);
902 r_goose_tree
= proto_item_add_subtree(item
, ett_r_goose
);
904 /* Session header subtree */
905 item
= proto_tree_add_item(r_goose_tree
, hf_goose_session_header
, tvb
, 0,
907 tree
= proto_item_add_subtree(item
, ett_session_header
);
910 proto_tree_add_item(tree
, hf_goose_spdu_id
, tvb
, offset
++, 1,
912 /* Session header length */
913 proto_tree_add_item_ret_uint(tree
, hf_goose_session_hdr_length
, tvb
, offset
++, 1,
914 ENC_BIG_ENDIAN
, &length
);
915 proto_item_set_len(item
, length
+ 2);
917 /* Header content indicator */
918 proto_tree_add_item(tree
, hf_goose_content_id
, tvb
, offset
++, 1,
921 proto_tree_add_item(tree
, hf_goose_hdr_length
, tvb
, offset
++, 1,
924 proto_tree_add_item(tree
, hf_goose_spdu_lenth
, tvb
, offset
, 4,
928 proto_tree_add_item(tree
, hf_goose_spdu_num
, tvb
, offset
, 4,
932 proto_tree_add_item(tree
, hf_goose_version
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
935 /* Security information subtree */
936 item
= proto_tree_add_item(tree
, hf_goose_security_info
, tvb
, offset
, -1,
938 tree
= proto_item_add_subtree(item
, ett_security_info
);
939 /* Time of current key */
940 proto_tree_add_item(tree
, hf_goose_current_key_t
, tvb
, offset
, 4,
943 /* Time of next key */
944 proto_tree_add_item(tree
, hf_goose_next_key_t
, tvb
, offset
, 2,
948 proto_tree_add_item(tree
, hf_goose_key_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
950 /* Initialization vector length */
951 proto_tree_add_item_ret_uint(tree
, hf_goose_init_vec_length
, tvb
, offset
++, 1,
952 ENC_BIG_ENDIAN
, &init_v_length
);
953 proto_item_set_len(item
, init_v_length
+ 11);
955 if (init_v_length
> 0) {
956 /* Initialization vector bytes */
957 proto_tree_add_item(tree
, hf_goose_init_vec
, tvb
, offset
, init_v_length
,
960 offset
+= init_v_length
;
962 /* Session user information subtree */
963 item
= proto_tree_add_item(r_goose_tree
, hf_goose_session_user_info
, tvb
,
965 sess_user_info_tree
= proto_item_add_subtree(item
, ett_payload
);
967 /* Payload subtree */
968 item
= proto_tree_add_item(sess_user_info_tree
, hf_goose_payload
, tvb
,
970 tree
= proto_item_add_subtree(item
, ett_payload
);
972 proto_tree_add_item_ret_uint(tree
, hf_goose_payload_length
, tvb
, offset
, 4,
973 ENC_BIG_ENDIAN
, &payload_length
);
976 while (apdu_offset
< payload_length
){
978 proto_tree_add_item_ret_uint(tree
, hf_goose_apdu_tag
, tvb
, offset
++, 1,
979 ENC_BIG_ENDIAN
, &payload_tag
);
980 /* Simulation flag */
981 proto_tree_add_item_ret_uint(tree
, hf_goose_apdu_simulation
, tvb
, offset
++,
982 1, ENC_BIG_ENDIAN
, &apdu_simulation
);
984 proto_tree_add_item(tree
, hf_goose_apdu_appid
, tvb
, offset
, 2,
988 if (payload_tag
!= OSI_PDU_GOOSE
) {
989 return tvb_captured_length(tvb
);
992 /* Store the header sim value for later expert info checks */
995 data_chk
->s_bit
= true;
997 data_chk
->s_bit
= false;
1002 proto_tree_add_item_ret_uint(tree
, hf_goose_apdu_length
, tvb
, offset
, 2,
1003 ENC_BIG_ENDIAN
, &apdu_length
);
1005 apdu_offset
+= (APDU_HEADER_SIZE
+ apdu_length
);
1008 old_offset
= offset
;
1009 offset
= dissect_goose_GOOSEpdu(false, tvb
, offset
, &asn1_ctx
, tree
, -1);
1010 if (offset
== old_offset
) {
1011 proto_tree_add_expert(tree
, pinfo
, &ei_goose_zero_pdu
, tvb
, offset
, -1);
1016 /* Check do we have padding bytes */
1017 if ((tvb_captured_length(tvb
) > offset
) &&
1018 (tvb_get_uint8(tvb
, offset
) == 0xAF)) {
1019 /* Padding subtree */
1020 item
= proto_tree_add_item(sess_user_info_tree
, hf_goose_padding
, tvb
,
1021 offset
, -1, ENC_NA
);
1022 tree
= proto_item_add_subtree(item
, ett_padding
);
1025 proto_tree_add_item(tree
, hf_goose_padding_tag
, tvb
, offset
++, 1,
1027 /* Padding length */
1028 proto_tree_add_item_ret_uint(tree
, hf_goose_padding_length
, tvb
, offset
++, 1,
1029 ENC_BIG_ENDIAN
, &padding_length
);
1030 proto_item_set_len(item
, padding_length
+ 1);
1033 proto_tree_add_item(tree
, hf_goose_padding
, tvb
, offset
, padding_length
,
1035 offset
+= padding_length
;
1038 /* Check do we have HMAC bytes */
1039 if (tvb_captured_length(tvb
) > offset
) {
1041 proto_tree_add_item(sess_user_info_tree
, hf_goose_hmac
, tvb
, offset
,
1042 tvb_captured_length(tvb
) - offset
, ENC_NA
);
1045 return tvb_captured_length(tvb
);
1049 dissect_rgoose_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
,
1054 /* Check do we have at least min size of Session header bytes */
1055 if (tvb_captured_length(tvb
) < 27) {
1059 /* Is it R-GOOSE? */
1060 spdu
= tvb_get_uint8(tvb
, 0);
1061 if (spdu
!= OSI_SPDU_GOOSE
) {
1065 dissect_rgoose(tvb
, pinfo
, parent_tree
, data
);
1069 /*--- proto_register_goose -------------------------------------------*/
1070 void proto_register_goose(void) {
1072 /* List of fields */
1073 static hf_register_info hf
[] =
1075 { &hf_goose_session_header
,
1076 { "Session header", "rgoose.session_hdr",
1077 FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1079 { &hf_goose_spdu_id
,
1080 { "Session identifier", "rgoose.spdu_id",
1081 FT_UINT8
, BASE_HEX_DEC
, VALS(ositp_spdu_id
), 0x0, NULL
, HFILL
}},
1083 { &hf_goose_session_hdr_length
,
1084 { "Session header length", "rgoose.session_hdr_len",
1085 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1087 { &hf_goose_content_id
,
1088 { "Common session header identifier", "rgoose.common_session_id",
1089 FT_UINT8
, BASE_HEX_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1091 { &hf_goose_hdr_length
,
1092 { "Header length", "rgoose.hdr_len",
1093 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1095 { &hf_goose_spdu_lenth
,
1096 { "SPDU length", "rgoose.spdu_len",
1097 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1099 { &hf_goose_spdu_num
,
1100 { "SPDU number", "rgoose.spdu_num",
1101 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1103 { &hf_goose_version
,
1104 { "Version", "rgoose.version",
1105 FT_UINT16
, BASE_HEX_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1107 { &hf_goose_security_info
,
1108 { "Security information", "rgoose.sec_info",
1109 FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1111 { &hf_goose_current_key_t
,
1112 { "Time of current key", "rgoose.curr_key_t",
1113 FT_UINT32
, BASE_HEX_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1115 { &hf_goose_next_key_t
,
1116 { "Time of next key", "rgoose.next_key_t",
1117 FT_UINT16
, BASE_HEX_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1120 { "Key ID", "rgoose.key_id",
1121 FT_UINT32
, BASE_HEX_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1123 { &hf_goose_init_vec_length
,
1124 { "Initialization vector length", "rgoose.init_v_len",
1125 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1127 { &hf_goose_init_vec
,
1128 { "Initialization vector", "rgoose.init_v",
1129 FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1131 { &hf_goose_session_user_info
,
1132 { "Session user information", "rgoose.session_user_info",
1133 FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1135 { &hf_goose_payload
,
1136 { "Payload", "rgoose.payload",
1137 FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1139 { &hf_goose_payload_length
,
1140 { "Payload length", "rgoose.payload_len",
1141 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1143 { &hf_goose_apdu_tag
,
1144 { "Payload type tag", "rgoose.pdu_tag",
1145 FT_UINT8
, BASE_HEX_DEC
, VALS(ositp_pdu_id
), 0x0, NULL
, HFILL
}},
1147 { &hf_goose_apdu_simulation
,
1148 { "Simulation flag", "rgoose.simulation",
1149 FT_UINT8
, BASE_HEX_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1151 { &hf_goose_apdu_appid
,
1152 { "APPID", "rgoose.appid",
1153 FT_UINT16
, BASE_HEX_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1155 { &hf_goose_apdu_length
,
1156 { "APDU length", "rgoose.apdu_len",
1157 FT_UINT16
, BASE_HEX_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1159 { &hf_goose_padding_tag
,
1160 { "Padding", "rgoose.padding_tag",
1161 FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1163 { &hf_goose_padding_length
,
1164 { "Padding length", "rgoose.padding_len",
1165 FT_UINT8
, BASE_HEX_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1167 { &hf_goose_padding
,
1168 { "Padding", "rgoose.padding",
1169 FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1172 { "HMAC", "rgoose.hmac",
1173 FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1176 { "APPID", "goose.appid",
1177 FT_UINT16
, BASE_HEX_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1180 { "Length", "goose.length",
1181 FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1183 { &hf_goose_reserve1
,
1184 { "Reserved 1", "goose.reserve1",
1185 FT_UINT16
, BASE_HEX_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1187 { &hf_goose_reserve1_s_bit
,
1188 { "Simulated", "goose.reserve1.s_bit",
1189 FT_BOOLEAN
, 16, NULL
, F_RESERVE1_S_BIT
, NULL
, HFILL
} },
1191 { &hf_goose_reserve2
,
1192 { "Reserved 2", "goose.reserve2",
1193 FT_UINT16
, BASE_HEX_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1195 { &hf_goose_float_value
,
1196 { "float value", "goose.float_value",
1197 FT_FLOAT
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1199 { &hf_goose_gseMngtPdu
,
1200 { "gseMngtPdu", "goose.gseMngtPdu_element",
1201 FT_NONE
, BASE_NONE
, NULL
, 0,
1203 { &hf_goose_goosePdu
,
1204 { "goosePdu", "goose.goosePdu_element",
1205 FT_NONE
, BASE_NONE
, NULL
, 0,
1206 "IECGoosePdu", HFILL
}},
1207 { &hf_goose_stateID
,
1208 { "stateID", "goose.stateID",
1209 FT_INT32
, BASE_DEC
, NULL
, 0,
1210 "INTEGER", HFILL
}},
1211 { &hf_goose_requestResp
,
1212 { "requestResp", "goose.requestResp",
1213 FT_UINT32
, BASE_DEC
, VALS(goose_RequestResponse_vals
), 0,
1214 "RequestResponse", HFILL
}},
1215 { &hf_goose_requests
,
1216 { "requests", "goose.requests",
1217 FT_UINT32
, BASE_DEC
, VALS(goose_GSEMngtRequests_vals
), 0,
1218 "GSEMngtRequests", HFILL
}},
1219 { &hf_goose_responses
,
1220 { "responses", "goose.responses",
1221 FT_UINT32
, BASE_DEC
, VALS(goose_GSEMngtResponses_vals
), 0,
1222 "GSEMngtResponses", HFILL
}},
1223 { &hf_goose_getGoReference
,
1224 { "getGoReference", "goose.getGoReference_element",
1225 FT_NONE
, BASE_NONE
, NULL
, 0,
1226 "GetReferenceRequestPdu", HFILL
}},
1227 { &hf_goose_getGOOSEElementNumber
,
1228 { "getGOOSEElementNumber", "goose.getGOOSEElementNumber_element",
1229 FT_NONE
, BASE_NONE
, NULL
, 0,
1230 "GetElementRequestPdu", HFILL
}},
1231 { &hf_goose_getGsReference
,
1232 { "getGsReference", "goose.getGsReference_element",
1233 FT_NONE
, BASE_NONE
, NULL
, 0,
1234 "GetReferenceRequestPdu", HFILL
}},
1235 { &hf_goose_getGSSEDataOffset
,
1236 { "getGSSEDataOffset", "goose.getGSSEDataOffset_element",
1237 FT_NONE
, BASE_NONE
, NULL
, 0,
1238 "GetElementRequestPdu", HFILL
}},
1239 { &hf_goose_gseMngtNotSupported
,
1240 { "gseMngtNotSupported", "goose.gseMngtNotSupported_element",
1241 FT_NONE
, BASE_NONE
, NULL
, 0,
1243 { &hf_goose_gseMngtResponses_GetGOReference
,
1244 { "getGoReference", "goose.gseMngtResponses_GetGOReference_element",
1245 FT_NONE
, BASE_NONE
, NULL
, 0,
1246 "GSEMngtResponsePdu", HFILL
}},
1247 { &hf_goose_gseMngtResponses_GetGOOSEElementNumber
,
1248 { "getGOOSEElementNumber", "goose.gseMngtResponses_GetGOOSEElementNumber_element",
1249 FT_NONE
, BASE_NONE
, NULL
, 0,
1250 "GSEMngtResponsePdu", HFILL
}},
1251 { &hf_goose_gseMngtResponses_GetGSReference
,
1252 { "getGsReference", "goose.gseMngtResponses_GetGSReference_element",
1253 FT_NONE
, BASE_NONE
, NULL
, 0,
1254 "GSEMngtResponsePdu", HFILL
}},
1255 { &hf_goose_gseMngtResponses_GetGSSEDataOffset
,
1256 { "getGSSEDataOffset", "goose.gseMngtResponses_GetGSSEDataOffset_element",
1257 FT_NONE
, BASE_NONE
, NULL
, 0,
1258 "GSEMngtResponsePdu", HFILL
}},
1260 { "ident", "goose.ident",
1261 FT_STRING
, BASE_NONE
, NULL
, 0,
1262 "VisibleString", HFILL
}},
1263 { &hf_goose_getReferenceRequest_offset
,
1264 { "offset", "goose.getReferenceRequest.offset",
1265 FT_UINT32
, BASE_DEC
, NULL
, 0,
1266 "T_getReferenceRequest_offset", HFILL
}},
1267 { &hf_goose_getReferenceRequest_offset_item
,
1268 { "offset item", "goose.getReferenceRequest_offset_item",
1269 FT_INT32
, BASE_DEC
, NULL
, 0,
1270 "INTEGER", HFILL
}},
1271 { &hf_goose_references
,
1272 { "references", "goose.references",
1273 FT_UINT32
, BASE_DEC
, NULL
, 0,
1275 { &hf_goose_references_item
,
1276 { "references item", "goose.references_item",
1277 FT_STRING
, BASE_NONE
, NULL
, 0,
1278 "VisibleString", HFILL
}},
1279 { &hf_goose_confRev
,
1280 { "confRev", "goose.confRev",
1281 FT_INT32
, BASE_DEC
, NULL
, 0,
1282 "INTEGER", HFILL
}},
1284 { "posNeg", "goose.posNeg",
1285 FT_UINT32
, BASE_DEC
, VALS(goose_PositiveNegative_vals
), 0,
1286 "PositiveNegative", HFILL
}},
1287 { &hf_goose_responsePositive
,
1288 { "responsePositive", "goose.responsePositive_element",
1289 FT_NONE
, BASE_NONE
, NULL
, 0,
1292 { "datSet", "goose.datSet",
1293 FT_STRING
, BASE_NONE
, NULL
, 0,
1294 "VisibleString", HFILL
}},
1296 { "result", "goose.result",
1297 FT_UINT32
, BASE_DEC
, NULL
, 0,
1298 "SEQUENCE_OF_RequestResults", HFILL
}},
1299 { &hf_goose_result_item
,
1300 { "RequestResults", "goose.RequestResults",
1301 FT_UINT32
, BASE_DEC
, VALS(goose_RequestResults_vals
), 0,
1303 { &hf_goose_responseNegative
,
1304 { "responseNegative", "goose.responseNegative",
1305 FT_INT32
, BASE_DEC
, VALS(goose_GlbErrors_vals
), 0,
1306 "GlbErrors", HFILL
}},
1308 { "offset", "goose.offset",
1309 FT_INT32
, BASE_DEC
, NULL
, 0,
1310 "INTEGER", HFILL
}},
1311 { &hf_goose_reference
,
1312 { "reference", "goose.reference",
1313 FT_STRING
, BASE_NONE
, NULL
, 0,
1314 "IA5String", HFILL
}},
1316 { "error", "goose.error",
1317 FT_INT32
, BASE_DEC
, VALS(goose_ErrorReason_vals
), 0,
1318 "ErrorReason", HFILL
}},
1319 { &hf_goose_gocbRef
,
1320 { "gocbRef", "goose.gocbRef",
1321 FT_STRING
, BASE_NONE
, NULL
, 0,
1322 "VisibleString", HFILL
}},
1323 { &hf_goose_timeAllowedtoLive
,
1324 { "timeAllowedtoLive", "goose.timeAllowedtoLive",
1325 FT_INT32
, BASE_DEC
, NULL
, 0,
1326 "INTEGER", HFILL
}},
1328 { "goID", "goose.goID",
1329 FT_STRING
, BASE_NONE
, NULL
, 0,
1330 "VisibleString", HFILL
}},
1333 FT_STRING
, BASE_NONE
, NULL
, 0,
1334 "UtcTime", HFILL
}},
1336 { "stNum", "goose.stNum",
1337 FT_UINT32
, BASE_DEC
, NULL
, 0,
1338 "INTEGER", HFILL
}},
1340 { "sqNum", "goose.sqNum",
1341 FT_UINT32
, BASE_DEC
, NULL
, 0,
1342 "INTEGER", HFILL
}},
1343 { &hf_goose_simulation
,
1344 { "simulation", "goose.simulation",
1345 FT_BOOLEAN
, BASE_NONE
, NULL
, 0,
1346 "BOOLEAN", HFILL
}},
1348 { "ndsCom", "goose.ndsCom",
1349 FT_BOOLEAN
, BASE_NONE
, NULL
, 0,
1350 "BOOLEAN", HFILL
}},
1351 { &hf_goose_numDatSetEntries
,
1352 { "numDatSetEntries", "goose.numDatSetEntries",
1353 FT_INT32
, BASE_DEC
, NULL
, 0,
1354 "INTEGER", HFILL
}},
1355 { &hf_goose_allData
,
1356 { "allData", "goose.allData",
1357 FT_UINT32
, BASE_DEC
, NULL
, 0,
1358 "SEQUENCE_OF_Data", HFILL
}},
1359 { &hf_goose_allData_item
,
1360 { "Data", "goose.Data",
1361 FT_UINT32
, BASE_DEC
, VALS(goose_Data_vals
), 0,
1364 { "array", "goose.array",
1365 FT_UINT32
, BASE_DEC
, NULL
, 0,
1366 "SEQUENCE_OF_Data", HFILL
}},
1367 { &hf_goose_array_item
,
1368 { "Data", "goose.Data",
1369 FT_UINT32
, BASE_DEC
, VALS(goose_Data_vals
), 0,
1371 { &hf_goose_structure
,
1372 { "structure", "goose.structure",
1373 FT_UINT32
, BASE_DEC
, NULL
, 0,
1374 "SEQUENCE_OF_Data", HFILL
}},
1375 { &hf_goose_structure_item
,
1376 { "Data", "goose.Data",
1377 FT_UINT32
, BASE_DEC
, VALS(goose_Data_vals
), 0,
1379 { &hf_goose_boolean
,
1380 { "boolean", "goose.boolean",
1381 FT_BOOLEAN
, BASE_NONE
, NULL
, 0,
1383 { &hf_goose_bit_string
,
1384 { "bit-string", "goose.bit_string",
1385 FT_BYTES
, BASE_NONE
, NULL
, 0,
1387 { &hf_goose_integer
,
1388 { "integer", "goose.integer",
1389 FT_INT32
, BASE_DEC
, NULL
, 0,
1391 { &hf_goose_unsigned
,
1392 { "unsigned", "goose.unsigned",
1393 FT_INT32
, BASE_DEC
, NULL
, 0,
1394 "INTEGER", HFILL
}},
1395 { &hf_goose_floating_point
,
1396 { "floating-point", "goose.floating_point",
1397 FT_BYTES
, BASE_NONE
, NULL
, 0,
1398 "FloatingPoint", HFILL
}},
1400 { "real", "goose.real",
1401 FT_DOUBLE
, BASE_NONE
, NULL
, 0,
1403 { &hf_goose_octet_string
,
1404 { "octet-string", "goose.octet_string",
1405 FT_BYTES
, BASE_NONE
, NULL
, 0,
1407 { &hf_goose_visible_string
,
1408 { "visible-string", "goose.visible_string",
1409 FT_STRING
, BASE_NONE
, NULL
, 0,
1410 "VisibleString", HFILL
}},
1411 { &hf_goose_binary_time
,
1412 { "binary-time", "goose.binary_time",
1413 FT_BYTES
, BASE_NONE
, NULL
, 0,
1414 "TimeOfDay", HFILL
}},
1416 { "bcd", "goose.bcd",
1417 FT_INT32
, BASE_DEC
, NULL
, 0,
1418 "INTEGER", HFILL
}},
1419 { &hf_goose_booleanArray
,
1420 { "booleanArray", "goose.booleanArray",
1421 FT_BYTES
, BASE_NONE
, NULL
, 0,
1422 "BIT_STRING", HFILL
}},
1424 { "objId", "goose.objId",
1425 FT_OID
, BASE_NONE
, NULL
, 0,
1426 "OBJECT_IDENTIFIER", HFILL
}},
1427 { &hf_goose_mMSString
,
1428 { "mMSString", "goose.mMSString",
1429 FT_STRING
, BASE_NONE
, NULL
, 0,
1431 { &hf_goose_utc_time
,
1432 { "utc-time", "goose.utc_time",
1433 FT_STRING
, BASE_NONE
, NULL
, 0,
1434 "UtcTime", HFILL
}},
1437 /* List of subtrees */
1438 static int *ett
[] = {
1440 &ett_session_header
,
1442 &ett_session_user_info
,
1447 &ett_expert_inf_sim
,
1448 &ett_goose_GOOSEpdu
,
1449 &ett_goose_GSEMngtPdu
,
1450 &ett_goose_RequestResponse
,
1451 &ett_goose_GSEMngtRequests
,
1452 &ett_goose_GSEMngtResponses
,
1453 &ett_goose_GetReferenceRequestPdu
,
1454 &ett_goose_T_getReferenceRequest_offset
,
1455 &ett_goose_GetElementRequestPdu
,
1456 &ett_goose_T_references
,
1457 &ett_goose_GSEMngtResponsePdu
,
1458 &ett_goose_PositiveNegative
,
1459 &ett_goose_T_responsePositive
,
1460 &ett_goose_SEQUENCE_OF_RequestResults
,
1461 &ett_goose_RequestResults
,
1462 &ett_goose_IECGoosePdu
,
1463 &ett_goose_SEQUENCE_OF_Data
,
1467 static ei_register_info ei
[] = {
1468 { &ei_goose_mal_utctime
,
1469 { "goose.malformed.utctime", PI_MALFORMED
, PI_WARN
,
1470 "BER Error: malformed UTCTime encoding", EXPFILL
}},
1471 { &ei_goose_zero_pdu
,
1472 { "goose.zero_pdu", PI_PROTOCOL
, PI_ERROR
,
1473 "Internal error, zero-byte GOOSE PDU", EXPFILL
}},
1474 { &ei_goose_invalid_sim
,
1475 { "goose.invalid_sim", PI_PROTOCOL
, PI_WARN
,
1476 "Invalid GOOSE: S bit set and Simulation attribute clear", EXPFILL
}},
1477 { &ei_goose_bogus_length
,
1478 { "goose.bogus_length", PI_PROTOCOL
, PI_ERROR
,
1479 "GOOSE length must be at least 8 (includes header)", EXPFILL
}},
1482 expert_module_t
* expert_goose
;
1484 /* Register protocol */
1485 proto_goose
= proto_register_protocol(GOOSE_PNAME
, GOOSE_PSNAME
, GOOSE_PFNAME
);
1486 proto_r_goose
= proto_register_protocol(R_GOOSE_PNAME
, R_GOOSE_PSNAME
, R_GOOSE_PFNAME
);
1488 goose_handle
= register_dissector("goose", dissect_goose
, proto_goose
);
1490 /* Register fields and subtrees */
1491 proto_register_field_array(proto_goose
, hf
, array_length(hf
));
1492 proto_register_subtree_array(ett
, array_length(ett
));
1493 expert_goose
= expert_register_protocol(proto_goose
);
1494 expert_register_field_array(expert_goose
, ei
, array_length(ei
));
1498 /*--- proto_reg_handoff_goose --- */
1499 void proto_reg_handoff_goose(void) {
1501 dissector_add_uint("ethertype", ETHERTYPE_IEC61850_GOOSE
, goose_handle
);
1503 heur_dissector_add("cltp", dissect_rgoose_heur
,
1504 "R-GOOSE (GOOSE over CLTP)", "rgoose_cltp", proto_goose
, HEURISTIC_ENABLE
);