nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /****************************************************************************** |
2 | ** Copyright (C) 2006-2007 ascolab GmbH. All Rights Reserved. |
||
3 | ** Web: http://www.ascolab.com |
||
4 | ** |
||
5 | ** This program is free software; you can redistribute it and/or |
||
6 | ** modify it under the terms of the GNU General Public License |
||
7 | ** as published by the Free Software Foundation; either version 2 |
||
8 | ** of the License, or (at your option) any later version. |
||
9 | ** |
||
10 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE |
||
11 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
||
12 | ** |
||
13 | ** Project: OpcUa Wireshark Plugin |
||
14 | ** |
||
15 | ** Description: Implementation of OpcUa built-in type parsers. |
||
16 | ** This contains all the simple types and some complex types. |
||
17 | ** |
||
18 | ** Author: Gerhard Gappmeier <gerhard.gappmeier@ascolab.com> |
||
19 | ******************************************************************************/ |
||
20 | |||
21 | #include "config.h" |
||
22 | |||
23 | #include <epan/packet.h> |
||
24 | #include <epan/expert.h> |
||
25 | #include <epan/dissectors/packet-windows-common.h> |
||
26 | #include "opcua_simpletypes.h" |
||
27 | #include "opcua_hfindeces.h" |
||
28 | #include "opcua_statuscode.h" |
||
29 | |||
30 | #define DIAGNOSTICINFO_ENCODINGMASK_SYMBOLICID_FLAG 0x01 |
||
31 | #define DIAGNOSTICINFO_ENCODINGMASK_NAMESPACE_FLAG 0x02 |
||
32 | #define DIAGNOSTICINFO_ENCODINGMASK_LOCALIZEDTEXT_FLAG 0x04 |
||
33 | #define DIAGNOSTICINFO_ENCODINGMASK_LOCALE_FLAG 0x08 |
||
34 | #define DIAGNOSTICINFO_ENCODINGMASK_ADDITIONALINFO_FLAG 0x10 |
||
35 | #define DIAGNOSTICINFO_ENCODINGMASK_INNERSTATUSCODE_FLAG 0x20 |
||
36 | #define DIAGNOSTICINFO_ENCODINGMASK_INNERDIAGNOSTICINFO_FLAG 0x40 |
||
37 | #define LOCALIZEDTEXT_ENCODINGBYTE_LOCALE 0x01 |
||
38 | #define LOCALIZEDTEXT_ENCODINGBYTE_TEXT 0x02 |
||
39 | #define NODEID_NAMESPACEURIFLAG 0x80 |
||
40 | #define NODEID_SERVERINDEXFLAG 0x40 |
||
41 | #define DATAVALUE_ENCODINGBYTE_VALUE 0x01 |
||
42 | #define DATAVALUE_ENCODINGBYTE_STATUSCODE 0x02 |
||
43 | #define DATAVALUE_ENCODINGBYTE_SOURCETIMESTAMP 0x04 |
||
44 | #define DATAVALUE_ENCODINGBYTE_SERVERTIMESTAMP 0x08 |
||
45 | #define DATAVALUE_ENCODINGBYTE_SOURCEPICOSECONDS 0x10 |
||
46 | #define DATAVALUE_ENCODINGBYTE_SERVERPICOSECONDS 0x20 |
||
47 | #define EXTOBJ_ENCODINGMASK_BINBODY_FLAG 0x01 |
||
48 | #define EXTOBJ_ENCODINGMASK_XMLBODY_FLAG 0x02 |
||
49 | #define STATUSCODE_STRUCTURECHANGED 0x8000 |
||
50 | #define STATUSCODE_SEMANTICSCHANGED 0x4000 |
||
51 | #define STATUSCODE_INFOTYPE_DATAVALUE 0x00000400 |
||
52 | #define STATUSCODE_INFOBIT_OVERFLOW 0x0080 |
||
53 | #define STATUSCODE_INFOBIT_HISTORIAN_PARTIAL 0x0004 |
||
54 | #define STATUSCODE_INFOBIT_HISTORIAN_EXTRADATA 0x0008 |
||
55 | #define STATUSCODE_INFOBIT_HISTORIAN_MULTIVALUE 0x0010 |
||
56 | #define RETURNDIAGNOSTICS_SERVICELEVEL_SYMBOLICID 0x0001 |
||
57 | #define RETURNDIAGNOSTICS_SERVICELEVEL_LOCALIZEDTEXT 0x0002 |
||
58 | #define RETURNDIAGNOSTICS_SERVICELEVEL_ADDITIONALINFO 0x0004 |
||
59 | #define RETURNDIAGNOSTICS_SERVICELEVEL_INNERSTATUSCODE 0x0008 |
||
60 | #define RETURNDIAGNOSTICS_SERVICELEVEL_INNERDIAGNOSTICS 0x0010 |
||
61 | #define RETURNDIAGNOSTICS_OPERATIONLEVEL_SYMBOLICID 0x0020 |
||
62 | #define RETURNDIAGNOSTICS_OPERATIONLEVEL_LOCALIZEDTEXT 0x0040 |
||
63 | #define RETURNDIAGNOSTICS_OPERATIONLEVEL_ADDITIONALINFO 0x0080 |
||
64 | #define RETURNDIAGNOSTICS_OPERATIONLEVEL_INNERSTATUSCODE 0x0100 |
||
65 | #define RETURNDIAGNOSTICS_OPERATIONLEVEL_INNERDIAGNOSTICS 0x0200 |
||
66 | |||
67 | /* Chosen arbitrarily */ |
||
68 | #define MAX_ARRAY_LEN 10000 |
||
69 | |||
70 | static int hf_opcua_diag_mask = -1; |
||
71 | static int hf_opcua_diag_mask_symbolicflag = -1; |
||
72 | static int hf_opcua_diag_mask_namespaceflag = -1; |
||
73 | static int hf_opcua_diag_mask_localizedtextflag = -1; |
||
74 | static int hf_opcua_diag_mask_localeflag = -1; |
||
75 | static int hf_opcua_diag_mask_additionalinfoflag = -1; |
||
76 | static int hf_opcua_diag_mask_innerstatuscodeflag = -1; |
||
77 | static int hf_opcua_diag_mask_innerdiaginfoflag = -1; |
||
78 | static int hf_opcua_loctext_mask = -1; |
||
79 | static int hf_opcua_loctext_mask_localeflag = -1; |
||
80 | static int hf_opcua_loctext_mask_textflag = -1; |
||
81 | static int hf_opcua_datavalue_mask = -1; |
||
82 | static int hf_opcua_datavalue_mask_valueflag = -1; |
||
83 | static int hf_opcua_datavalue_mask_statuscodeflag = -1; |
||
84 | static int hf_opcua_datavalue_mask_sourcetimestampflag = -1; |
||
85 | static int hf_opcua_datavalue_mask_servertimestampflag = -1; |
||
86 | static int hf_opcua_datavalue_mask_sourcepicoseconds = -1; |
||
87 | static int hf_opcua_datavalue_mask_serverpicoseconds = -1; |
||
88 | static int hf_opcua_nodeid_encodingmask = -1; |
||
89 | static int hf_opcua_expandednodeid_mask = -1; |
||
90 | static int hf_opcua_expandednodeid_mask_namespaceuri = -1; |
||
91 | static int hf_opcua_expandednodeid_mask_serverindex = -1; |
||
92 | static int hf_opcua_variant_encodingmask = -1; |
||
93 | static int hf_opcua_nodeid_nsindex = -1; |
||
94 | static int hf_opcua_nodeid_numeric = -1; |
||
95 | static int hf_opcua_nodeid_string = -1; |
||
96 | static int hf_opcua_nodeid_guid = -1; |
||
97 | static int hf_opcua_nodeid_bytestring = -1; |
||
98 | static int hf_opcua_localizedtext_locale = -1; |
||
99 | static int hf_opcua_localizedtext_text = -1; |
||
100 | static int hf_opcua_qualifiedname_id = -1; |
||
101 | static int hf_opcua_qualifiedname_name = -1; |
||
102 | static int hf_opcua_SourceTimestamp = -1; |
||
103 | static int hf_opcua_SourcePicoseconds = -1; |
||
104 | static int hf_opcua_ServerTimestamp = -1; |
||
105 | static int hf_opcua_ServerPicoseconds = -1; |
||
106 | static int hf_opcua_diag_symbolicid = -1; |
||
107 | static int hf_opcua_diag_namespace = -1; |
||
108 | static int hf_opcua_diag_localizedtext = -1; |
||
109 | static int hf_opcua_diag_locale = -1; |
||
110 | static int hf_opcua_diag_additionalinfo = -1; |
||
111 | static int hf_opcua_diag_innerstatuscode = -1; |
||
112 | static int hf_opcua_extobj_mask = -1; |
||
113 | static int hf_opcua_extobj_mask_binbodyflag = -1; |
||
114 | static int hf_opcua_extobj_mask_xmlbodyflag = -1; |
||
115 | static int hf_opcua_ArraySize = -1; |
||
116 | static int hf_opcua_ServerIndex = -1; |
||
117 | static int hf_opcua_status_StructureChanged = -1; |
||
118 | static int hf_opcua_status_SemanticsChanged = -1; |
||
119 | static int hf_opcua_status_InfoBit_Limit_Overflow = -1; |
||
120 | static int hf_opcua_status_InfoBit_Historian_Partial = -1; |
||
121 | static int hf_opcua_status_InfoBit_Historian_ExtraData = -1; |
||
122 | static int hf_opcua_status_InfoBit_Historian_MultiValue = -1; |
||
123 | static int hf_opcua_status_InfoType = -1; |
||
124 | static int hf_opcua_status_Limit = -1; |
||
125 | static int hf_opcua_status_Historian = -1; |
||
126 | int hf_opcua_returnDiag = -1; |
||
127 | int hf_opcua_returnDiag_mask_sl_symbolicId = -1; |
||
128 | int hf_opcua_returnDiag_mask_sl_localizedText = -1; |
||
129 | int hf_opcua_returnDiag_mask_sl_additionalinfo = -1; |
||
130 | int hf_opcua_returnDiag_mask_sl_innerstatuscode = -1; |
||
131 | int hf_opcua_returnDiag_mask_sl_innerdiagnostics = -1; |
||
132 | int hf_opcua_returnDiag_mask_ol_symbolicId = -1; |
||
133 | int hf_opcua_returnDiag_mask_ol_localizedText = -1; |
||
134 | int hf_opcua_returnDiag_mask_ol_additionalinfo = -1; |
||
135 | int hf_opcua_returnDiag_mask_ol_innerstatuscode = -1; |
||
136 | int hf_opcua_returnDiag_mask_ol_innerdiagnostics = -1; |
||
137 | |||
138 | static expert_field ei_array_length = EI_INIT; |
||
139 | |||
140 | /** NodeId encoding mask table */ |
||
141 | static const value_string g_nodeidmasks[] = { |
||
142 | { 0x00, "Two byte encoded Numeric" }, |
||
143 | { 0x01, "Four byte encoded Numeric" }, |
||
144 | { 0x02, "Numeric of arbitrary length" }, |
||
145 | { 0x03, "String" }, |
||
146 | { 0x04, "GUID" }, |
||
147 | { 0x05, "Opaque" }, |
||
148 | { 0, NULL } |
||
149 | }; |
||
150 | |||
151 | /** StatusCode info types */ |
||
152 | static const value_string g_infotype[] = { |
||
153 | { 0x00, "Not used" }, |
||
154 | { 0x01, "DataValue" }, |
||
155 | { 0x02, "Reserved" }, |
||
156 | { 0x03, "Reserved" }, |
||
157 | { 0, NULL } |
||
158 | }; |
||
159 | |||
160 | /** StatusCode Limit types */ |
||
161 | static const value_string g_limit[] = { |
||
162 | { 0x00, "None" }, |
||
163 | { 0x01, "Low" }, |
||
164 | { 0x02, "High" }, |
||
165 | { 0x03, "Constant" }, |
||
166 | { 0, NULL } |
||
167 | }; |
||
168 | |||
169 | /** StatusCode Historian types */ |
||
170 | static const value_string g_historian[] = { |
||
171 | { 0x00, "Raw" }, |
||
172 | { 0x01, "Calculated" }, |
||
173 | { 0x02, "Interpolated" }, |
||
174 | { 0x03, "Reserved" }, |
||
175 | { 0, NULL } |
||
176 | }; |
||
177 | |||
178 | /** UA Variant Type enum */ |
||
179 | typedef enum _OpcUa_BuiltInType |
||
180 | { |
||
181 | OpcUaType_Null = 0, |
||
182 | OpcUaType_Boolean = 1, |
||
183 | OpcUaType_SByte = 2, |
||
184 | OpcUaType_Byte = 3, |
||
185 | OpcUaType_Int16 = 4, |
||
186 | OpcUaType_UInt16 = 5, |
||
187 | OpcUaType_Int32 = 6, |
||
188 | OpcUaType_UInt32 = 7, |
||
189 | OpcUaType_Int64 = 8, |
||
190 | OpcUaType_UInt64 = 9, |
||
191 | OpcUaType_Float = 10, |
||
192 | OpcUaType_Double = 11, |
||
193 | OpcUaType_String = 12, |
||
194 | OpcUaType_DateTime = 13, |
||
195 | OpcUaType_Guid = 14, |
||
196 | OpcUaType_ByteString = 15, |
||
197 | OpcUaType_XmlElement = 16, |
||
198 | OpcUaType_NodeId = 17, |
||
199 | OpcUaType_ExpandedNodeId = 18, |
||
200 | OpcUaType_StatusCode = 19, |
||
201 | OpcUaType_QualifiedName = 20, |
||
202 | OpcUaType_LocalizedText = 21, |
||
203 | OpcUaType_ExtensionObject = 22, |
||
204 | OpcUaType_DataValue = 23, |
||
205 | OpcUaType_Variant = 24, |
||
206 | OpcUaType_DiagnosticInfo = 25 |
||
207 | } |
||
208 | OpcUa_BuiltInType; |
||
209 | |||
210 | /** Variant encoding mask table */ |
||
211 | static const value_string g_VariantTypes[] = { |
||
212 | { 0, "Null" }, |
||
213 | { 1, "Boolean" }, |
||
214 | { 2, "SByte" }, |
||
215 | { 3, "Byte" }, |
||
216 | { 4, "Int16" }, |
||
217 | { 5, "UInt16" }, |
||
218 | { 6, "Int32" }, |
||
219 | { 7, "UInt32" }, |
||
220 | { 8, "Int64" }, |
||
221 | { 9, "UInt64" }, |
||
222 | { 10, "Float" }, |
||
223 | { 11, "Double" }, |
||
224 | { 12, "String" }, |
||
225 | { 13, "DateTime" }, |
||
226 | { 14, "Guid" }, |
||
227 | { 15, "ByteString" }, |
||
228 | { 16, "XmlElement" }, |
||
229 | { 17, "NodeId" }, |
||
230 | { 18, "ExpandedNodeId" }, |
||
231 | { 19, "StatusCode" }, |
||
232 | { 20, "QualifiedName" }, |
||
233 | { 21, "LocalizedText" }, |
||
234 | { 22, "ExtensionObject" }, |
||
235 | { 23, "DataValue" }, |
||
236 | { 24, "Variant" }, |
||
237 | { 25, "DiagnosticInfo" }, |
||
238 | { 0x80, "Array of Null" }, |
||
239 | { 0x80+1, "Array of Boolean" }, |
||
240 | { 0x80+2, "Array of SByte" }, |
||
241 | { 0x80+3, "Array of Byte" }, |
||
242 | { 0x80+4, "Array of Int16" }, |
||
243 | { 0x80+5, "Array of UInt16" }, |
||
244 | { 0x80+6, "Array of Int32" }, |
||
245 | { 0x80+7, "Array of UInt32" }, |
||
246 | { 0x80+8, "Array of Int64" }, |
||
247 | { 0x80+9, "Array of UInt64" }, |
||
248 | { 0x80+10, "Array of Float" }, |
||
249 | { 0x80+11, "Array of Double" }, |
||
250 | { 0x80+12, "Array of String" }, |
||
251 | { 0x80+13, "Array of DateTime" }, |
||
252 | { 0x80+14, "Array of Guid" }, |
||
253 | { 0x80+15, "Array of ByteString" }, |
||
254 | { 0x80+16, "Array of XmlElement" }, |
||
255 | { 0x80+17, "Array of NodeId" }, |
||
256 | { 0x80+18, "Array of ExpandedNodeId" }, |
||
257 | { 0x80+19, "Array of StatusCode" }, |
||
258 | { 0x80+20, "Array of QualifiedName" }, |
||
259 | { 0x80+21, "Array of LocalizedText" }, |
||
260 | { 0x80+22, "Array of ExtensionObject" }, |
||
261 | { 0x80+23, "Array of DataValue" }, |
||
262 | { 0x80+24, "Array of Variant" }, |
||
263 | { 0x80+25, "Array of DiagnosticInfo" }, |
||
264 | { 0xC0, "Matrix of Null" }, |
||
265 | { 0xC0+1, "Matrix of Boolean" }, |
||
266 | { 0xC0+2, "Matrix of SByte" }, |
||
267 | { 0xC0+3, "Matrix of Byte" }, |
||
268 | { 0xC0+4, "Matrix of Int16" }, |
||
269 | { 0xC0+5, "Matrix of UInt16" }, |
||
270 | { 0xC0+6, "Matrix of Int32" }, |
||
271 | { 0xC0+7, "Matrix of UInt32" }, |
||
272 | { 0xC0+8, "Matrix of Int64" }, |
||
273 | { 0xC0+9, "Matrix of UInt64" }, |
||
274 | { 0xC0+10, "Matrix of Float" }, |
||
275 | { 0xC0+11, "Matrix of Double" }, |
||
276 | { 0xC0+12, "Matrix of String" }, |
||
277 | { 0xC0+13, "Matrix of DateTime" }, |
||
278 | { 0xC0+14, "Matrix of Guid" }, |
||
279 | { 0xC0+15, "Matrix of ByteString" }, |
||
280 | { 0xC0+16, "Matrix of XmlElement" }, |
||
281 | { 0xC0+17, "Matrix of NodeId" }, |
||
282 | { 0xC0+18, "Matrix of ExpandedNodeId" }, |
||
283 | { 0xC0+19, "Matrix of StatusCode" }, |
||
284 | { 0xC0+20, "Matrix of QualifiedName" }, |
||
285 | { 0xC0+21, "Matrix of LocalizedText" }, |
||
286 | { 0xC0+22, "Matrix of ExtensionObject" }, |
||
287 | { 0xC0+23, "Matrix of DataValue" }, |
||
288 | { 0xC0+24, "Matrix of Variant" }, |
||
289 | { 0xC0+25, "Matrix of DiagnosticInfo" }, |
||
290 | { 0, NULL } |
||
291 | }; |
||
292 | #define VARIANT_ARRAYDIMENSIONS 0x40 |
||
293 | #define VARIANT_ARRAYMASK 0x80 |
||
294 | |||
295 | /* trees */ |
||
296 | static gint ett_opcua_diagnosticinfo = -1; |
||
297 | static gint ett_opcua_diagnosticinfo_encodingmask = -1; |
||
298 | static gint ett_opcua_nodeid = -1; |
||
299 | static gint ett_opcua_expandednodeid = -1; |
||
300 | static gint ett_opcua_expandednodeid_encodingmask = -1; |
||
301 | static gint ett_opcua_localizedtext = -1; |
||
302 | static gint ett_opcua_localizedtext_encodingmask = -1; |
||
303 | static gint ett_opcua_qualifiedname = -1; |
||
304 | static gint ett_opcua_datavalue = -1; |
||
305 | static gint ett_opcua_datavalue_encodingmask = -1; |
||
306 | static gint ett_opcua_variant = -1; |
||
307 | static gint ett_opcua_variant_arraydims = -1; |
||
308 | static gint ett_opcua_extensionobject = -1; |
||
309 | static gint ett_opcua_extensionobject_encodingmask = -1; |
||
310 | static gint ett_opcua_statuscode = -1; |
||
311 | static gint ett_opcua_statuscode_info = -1; |
||
312 | gint ett_opcua_array_Boolean = -1; |
||
313 | gint ett_opcua_array_SByte = -1; |
||
314 | gint ett_opcua_array_Byte = -1; |
||
315 | gint ett_opcua_array_Int16 = -1; |
||
316 | gint ett_opcua_array_UInt16 = -1; |
||
317 | gint ett_opcua_array_Int32 = -1; |
||
318 | gint ett_opcua_array_UInt32 = -1; |
||
319 | gint ett_opcua_array_Int64 = -1; |
||
320 | gint ett_opcua_array_UInt64 = -1; |
||
321 | gint ett_opcua_array_Float = -1; |
||
322 | gint ett_opcua_array_Double = -1; |
||
323 | gint ett_opcua_array_String = -1; |
||
324 | gint ett_opcua_array_DateTime = -1; |
||
325 | gint ett_opcua_array_Guid = -1; |
||
326 | gint ett_opcua_array_ByteString = -1; |
||
327 | gint ett_opcua_array_XmlElement = -1; |
||
328 | gint ett_opcua_array_NodeId = -1; |
||
329 | gint ett_opcua_array_ExpandedNodeId = -1; |
||
330 | gint ett_opcua_array_StatusCode = -1; |
||
331 | gint ett_opcua_array_DiagnosticInfo = -1; |
||
332 | gint ett_opcua_array_QualifiedName = -1; |
||
333 | gint ett_opcua_array_LocalizedText = -1; |
||
334 | gint ett_opcua_array_ExtensionObject = -1; |
||
335 | gint ett_opcua_array_DataValue = -1; |
||
336 | gint ett_opcua_array_Variant = -1; |
||
337 | gint ett_opcua_returnDiagnostics = -1; |
||
338 | static gint *ett[] = |
||
339 | { |
||
340 | &ett_opcua_diagnosticinfo, |
||
341 | &ett_opcua_diagnosticinfo_encodingmask, |
||
342 | &ett_opcua_nodeid, |
||
343 | &ett_opcua_expandednodeid, |
||
344 | &ett_opcua_expandednodeid_encodingmask, |
||
345 | &ett_opcua_localizedtext, |
||
346 | &ett_opcua_localizedtext_encodingmask, |
||
347 | &ett_opcua_qualifiedname, |
||
348 | &ett_opcua_datavalue, |
||
349 | &ett_opcua_datavalue_encodingmask, |
||
350 | &ett_opcua_variant, |
||
351 | &ett_opcua_variant_arraydims, |
||
352 | &ett_opcua_extensionobject, |
||
353 | &ett_opcua_extensionobject_encodingmask, |
||
354 | &ett_opcua_statuscode, |
||
355 | &ett_opcua_statuscode_info, |
||
356 | &ett_opcua_array_Boolean, |
||
357 | &ett_opcua_array_SByte, |
||
358 | &ett_opcua_array_Byte, |
||
359 | &ett_opcua_array_Int16, |
||
360 | &ett_opcua_array_UInt16, |
||
361 | &ett_opcua_array_Int32, |
||
362 | &ett_opcua_array_UInt32, |
||
363 | &ett_opcua_array_Int64, |
||
364 | &ett_opcua_array_UInt64, |
||
365 | &ett_opcua_array_Float, |
||
366 | &ett_opcua_array_Double, |
||
367 | &ett_opcua_array_String, |
||
368 | &ett_opcua_array_DateTime, |
||
369 | &ett_opcua_array_Guid, |
||
370 | &ett_opcua_array_ByteString, |
||
371 | &ett_opcua_array_XmlElement, |
||
372 | &ett_opcua_array_NodeId, |
||
373 | &ett_opcua_array_ExpandedNodeId, |
||
374 | &ett_opcua_array_StatusCode, |
||
375 | &ett_opcua_array_DiagnosticInfo, |
||
376 | &ett_opcua_array_QualifiedName, |
||
377 | &ett_opcua_array_LocalizedText, |
||
378 | &ett_opcua_array_ExtensionObject, |
||
379 | &ett_opcua_array_DataValue, |
||
380 | &ett_opcua_array_Variant, |
||
381 | &ett_opcua_returnDiagnostics |
||
382 | }; |
||
383 | |||
384 | void registerSimpleTypes(int proto) |
||
385 | { |
||
386 | expert_module_t* expert_proto; |
||
387 | |||
388 | static hf_register_info hf[] = |
||
389 | { |
||
390 | /* id full name abbreviation type display strings bitmask blurb HFILL */ |
||
391 | {&hf_opcua_diag_mask, {"EncodingMask", "opcua.diag.mask", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}}, |
||
392 | {&hf_opcua_diag_mask_symbolicflag, {"has symbolic id", "opcua.diag.has_symbolic_id", FT_BOOLEAN, 8, NULL, DIAGNOSTICINFO_ENCODINGMASK_SYMBOLICID_FLAG, NULL, HFILL}}, |
||
393 | {&hf_opcua_diag_mask_namespaceflag, {"has namespace", "opcua.diag.has_namespace", FT_BOOLEAN, 8, NULL, DIAGNOSTICINFO_ENCODINGMASK_NAMESPACE_FLAG, NULL, HFILL}}, |
||
394 | {&hf_opcua_diag_mask_localizedtextflag, {"has localizedtext", "opcua.diag.has_localizedtext", FT_BOOLEAN, 8, NULL, DIAGNOSTICINFO_ENCODINGMASK_LOCALIZEDTEXT_FLAG, NULL, HFILL}}, |
||
395 | {&hf_opcua_diag_mask_localeflag, {"has locale", "opcua.diag.has_locale", FT_BOOLEAN, 8, NULL, DIAGNOSTICINFO_ENCODINGMASK_LOCALE_FLAG, NULL, HFILL}}, |
||
396 | {&hf_opcua_diag_mask_additionalinfoflag, {"has additional info", "opcua.diag.has_additional_info", FT_BOOLEAN, 8, NULL, DIAGNOSTICINFO_ENCODINGMASK_ADDITIONALINFO_FLAG, NULL, HFILL}}, |
||
397 | {&hf_opcua_diag_mask_innerstatuscodeflag, {"has inner statuscode", "opcua.diag.has_inner_statuscode", FT_BOOLEAN, 8, NULL, DIAGNOSTICINFO_ENCODINGMASK_INNERSTATUSCODE_FLAG, NULL, HFILL}}, |
||
398 | {&hf_opcua_diag_mask_innerdiaginfoflag, {"has inner diagnostic info", "opcua.diag.has_inner_diagnostic_code", FT_BOOLEAN, 8, NULL, DIAGNOSTICINFO_ENCODINGMASK_INNERDIAGNOSTICINFO_FLAG, NULL, HFILL}}, |
||
399 | {&hf_opcua_loctext_mask, {"EncodingMask", "opcua.loctext.mask", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}}, |
||
400 | {&hf_opcua_loctext_mask_localeflag, {"has locale information", "opcua.loctext.has_locale_information", FT_BOOLEAN, 8, NULL, LOCALIZEDTEXT_ENCODINGBYTE_LOCALE, NULL, HFILL}}, |
||
401 | {&hf_opcua_loctext_mask_textflag, {"has text", "opcua.loctext.has_text", FT_BOOLEAN, 8, NULL, LOCALIZEDTEXT_ENCODINGBYTE_TEXT, NULL, HFILL}}, |
||
402 | {&hf_opcua_nodeid_encodingmask, {"EncodingMask", "opcua.nodeid.encodingmask", FT_UINT8, BASE_HEX, VALS(g_nodeidmasks), 0x0F, NULL, HFILL}}, |
||
403 | {&hf_opcua_nodeid_nsindex, {"Namespace Index", "opcua.nodeid.nsindex", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}}, |
||
404 | {&hf_opcua_nodeid_numeric, {"Identifier Numeric", "opcua.nodeid.numeric", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}}, |
||
405 | {&hf_opcua_nodeid_string, {"Identifier String", "opcua.nodeid.string", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}}, |
||
406 | {&hf_opcua_nodeid_guid, {"Identifier Guid", "opcua.nodeid.guid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL}}, |
||
407 | {&hf_opcua_nodeid_bytestring, {"Identifier ByteString", "opcua.nodeid.bytestring", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}}, |
||
408 | {&hf_opcua_expandednodeid_mask, {"EncodingMask", "opcua.expandednodeid.mask", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}}, |
||
409 | {&hf_opcua_expandednodeid_mask_namespaceuri, {"has namespace uri", "opcua.expandednodeid.has_namespace_uri", FT_BOOLEAN, 8, NULL, NODEID_NAMESPACEURIFLAG, NULL, HFILL}}, |
||
410 | {&hf_opcua_expandednodeid_mask_serverindex, {"has server index", "opcua.expandednodeid.has_server_index", FT_BOOLEAN, 8, NULL, NODEID_SERVERINDEXFLAG, NULL, HFILL}}, |
||
411 | {&hf_opcua_localizedtext_locale, {"Locale", "opcua.loctext.Locale", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}}, |
||
412 | {&hf_opcua_localizedtext_text, {"Text", "opcua.loctext.Text", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}}, |
||
413 | {&hf_opcua_qualifiedname_id, {"Id", "opcua.qualname.Id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}}, |
||
414 | {&hf_opcua_qualifiedname_name, {"Name", "opcua.qualname.Name", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}}, |
||
415 | {&hf_opcua_datavalue_mask, {"EncodingMask", "opcua.datavalue.mask", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}}, |
||
416 | {&hf_opcua_datavalue_mask_valueflag, {"has value", "opcua.datavalue.has_value", FT_BOOLEAN, 8, NULL, DATAVALUE_ENCODINGBYTE_VALUE, NULL, HFILL}}, |
||
417 | {&hf_opcua_datavalue_mask_statuscodeflag, {"has statuscode", "opcua.datavalue.has_statuscode", FT_BOOLEAN, 8, NULL, DATAVALUE_ENCODINGBYTE_STATUSCODE, NULL, HFILL}}, |
||
418 | {&hf_opcua_datavalue_mask_sourcetimestampflag, {"has source timestamp", "opcua.datavalue.has_source_timestamp", FT_BOOLEAN, 8, NULL, DATAVALUE_ENCODINGBYTE_SOURCETIMESTAMP, NULL, HFILL}}, |
||
419 | {&hf_opcua_datavalue_mask_servertimestampflag, {"has server timestamp", "opcua.datavalue.has_server_timestamp", FT_BOOLEAN, 8, NULL, DATAVALUE_ENCODINGBYTE_SERVERTIMESTAMP, NULL, HFILL}}, |
||
420 | {&hf_opcua_datavalue_mask_sourcepicoseconds, {"has source picoseconds", "opcua.datavalue.has_source_picoseconds", FT_BOOLEAN, 8, NULL, DATAVALUE_ENCODINGBYTE_SOURCEPICOSECONDS, NULL, HFILL}}, |
||
421 | {&hf_opcua_datavalue_mask_serverpicoseconds, {"has server picoseconds", "opcua.datavalue.has_server_picoseconds", FT_BOOLEAN, 8, NULL, DATAVALUE_ENCODINGBYTE_SERVERPICOSECONDS, NULL, HFILL}}, |
||
422 | {&hf_opcua_variant_encodingmask, {"Variant Type", "opcua.variant.has_value", FT_UINT8, BASE_HEX, VALS(g_VariantTypes), 0x0, NULL, HFILL}}, |
||
423 | {&hf_opcua_SourceTimestamp, {"SourceTimestamp", "opcua.datavalue.SourceTimestamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL}}, |
||
424 | {&hf_opcua_SourcePicoseconds, {"SourcePicoseconds", "opcua.datavalue.SourcePicoseconds", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}}, |
||
425 | {&hf_opcua_ServerTimestamp, {"ServerTimestamp", "opcua.datavalue.ServerTimestamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL}}, |
||
426 | {&hf_opcua_ServerPicoseconds, {"ServerPicoseconds", "opcua.datavalue.ServerPicoseconds", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}}, |
||
427 | {&hf_opcua_diag_symbolicid, {"SymbolicId", "opcua.diag.SymbolicId", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}}, |
||
428 | {&hf_opcua_diag_namespace, {"Namespace", "opcua.diag.Namespace", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}}, |
||
429 | {&hf_opcua_diag_localizedtext, {"LocalizedText", "opcua.diag.LocalizedText", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}}, |
||
430 | {&hf_opcua_diag_locale, {"Locale", "opcua.diag.Locale", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}}, |
||
431 | {&hf_opcua_diag_additionalinfo, {"AdditionalInfo", "opcua.diag.AdditionalInfo", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}}, |
||
432 | {&hf_opcua_diag_innerstatuscode, {"InnerStatusCode", "opcua.diag.InnerStatusCode", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL}}, |
||
433 | {&hf_opcua_extobj_mask, {"EncodingMask", "opcua.extobj.mask", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}}, |
||
434 | {&hf_opcua_extobj_mask_binbodyflag, {"has binary body", "opcua.extobj.has_binary_body", FT_BOOLEAN, 8, NULL, EXTOBJ_ENCODINGMASK_BINBODY_FLAG, NULL, HFILL}}, |
||
435 | {&hf_opcua_extobj_mask_xmlbodyflag, {"has xml body", "opcua.extobj.has_xml_body", FT_BOOLEAN, 8, NULL, EXTOBJ_ENCODINGMASK_XMLBODY_FLAG, NULL, HFILL}}, |
||
436 | {&hf_opcua_ArraySize, {"ArraySize", "opcua.variant.ArraySize", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}}, |
||
437 | {&hf_opcua_ServerIndex, {"ServerIndex", "opcua.expandednodeid.ServerIndex", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}}, |
||
438 | {&hf_opcua_status_StructureChanged, {"StructureChanged", "opcua.statuscode.structureChanged", FT_BOOLEAN, 16, NULL, STATUSCODE_STRUCTURECHANGED, NULL, HFILL}}, |
||
439 | {&hf_opcua_status_SemanticsChanged, {"SemanticsChanged", "opcua.statuscode.semanticsChanged", FT_BOOLEAN, 16, NULL, STATUSCODE_SEMANTICSCHANGED, NULL, HFILL}}, |
||
440 | {&hf_opcua_status_InfoBit_Limit_Overflow, {"Overflow", "opcua.statuscode.overflow", FT_BOOLEAN, 16, NULL, STATUSCODE_INFOBIT_OVERFLOW, NULL, HFILL}}, |
||
441 | {&hf_opcua_status_InfoBit_Historian_Partial, {"HistorianBit: Partial", "opcua.statuscode.historian.partial", FT_BOOLEAN, 16, NULL, STATUSCODE_INFOBIT_HISTORIAN_PARTIAL, NULL, HFILL}}, |
||
442 | {&hf_opcua_status_InfoBit_Historian_ExtraData, {"HistorianBit: ExtraData", "opcua.statuscode.historian.extraData", FT_BOOLEAN, 16, NULL, STATUSCODE_INFOBIT_HISTORIAN_EXTRADATA, NULL, HFILL}}, |
||
443 | {&hf_opcua_status_InfoBit_Historian_MultiValue, {"HistorianBit: MultiValue", "opcua.statuscode.historian.multiValue", FT_BOOLEAN, 16, NULL, STATUSCODE_INFOBIT_HISTORIAN_MULTIVALUE, NULL, HFILL}}, |
||
444 | {&hf_opcua_status_InfoType, {"InfoType", "opcua.statuscode.infoType", FT_UINT16, BASE_HEX, VALS(g_infotype), 0x0C00, NULL, HFILL}}, |
||
445 | {&hf_opcua_status_Limit, {"Limit", "opcua.statuscode.limit", FT_UINT16, BASE_HEX, VALS(g_limit), 0x0300, NULL, HFILL}}, |
||
446 | {&hf_opcua_status_Historian, {"Historian", "opcua.statuscode.historian", FT_UINT16, BASE_HEX, VALS(g_historian), 0x0003, NULL, HFILL}}, |
||
447 | {&hf_opcua_returnDiag, {"Return Diagnostics", "opcua.returndiag", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL}}, |
||
448 | {&hf_opcua_returnDiag_mask_sl_symbolicId, {"ServiceLevel / SymbolicId", "opcua.returndiag.servicelevel.symbolicid", FT_BOOLEAN, 16, NULL, RETURNDIAGNOSTICS_SERVICELEVEL_SYMBOLICID, NULL, HFILL}}, |
||
449 | {&hf_opcua_returnDiag_mask_sl_localizedText, {"ServiceLevel / LocalizedText", "opcua.returndiag.servicelevel.localizedtext", FT_BOOLEAN, 16, NULL, RETURNDIAGNOSTICS_SERVICELEVEL_LOCALIZEDTEXT, NULL, HFILL}}, |
||
450 | {&hf_opcua_returnDiag_mask_sl_additionalinfo, {"ServiceLevel / AdditionalInfo", "opcua.returndiag.servicelevel.additionalinfo", FT_BOOLEAN, 16, NULL, RETURNDIAGNOSTICS_SERVICELEVEL_ADDITIONALINFO, NULL, HFILL}}, |
||
451 | {&hf_opcua_returnDiag_mask_sl_innerstatuscode, {"ServiceLevel / Inner StatusCode", "opcua.returndiag.servicelevel.innerstatuscode", FT_BOOLEAN, 16, NULL, RETURNDIAGNOSTICS_SERVICELEVEL_INNERSTATUSCODE, NULL, HFILL}}, |
||
452 | {&hf_opcua_returnDiag_mask_sl_innerdiagnostics, {"ServiceLevel / Inner Diagnostics", "opcua.returndiag.servicelevel.innerdiagnostics", FT_BOOLEAN, 16, NULL, RETURNDIAGNOSTICS_SERVICELEVEL_INNERDIAGNOSTICS, NULL, HFILL}}, |
||
453 | {&hf_opcua_returnDiag_mask_ol_symbolicId, {"OperationLevel / SymbolicId", "opcua.returndiag.operationlevel.symbolicid", FT_BOOLEAN, 16, NULL, RETURNDIAGNOSTICS_OPERATIONLEVEL_SYMBOLICID, NULL, HFILL}}, |
||
454 | {&hf_opcua_returnDiag_mask_ol_localizedText, {"OperationLevel / LocalizedText", "opcua.returndiag.operationlevel.localizedtext", FT_BOOLEAN, 16, NULL, RETURNDIAGNOSTICS_OPERATIONLEVEL_LOCALIZEDTEXT, NULL, HFILL}}, |
||
455 | {&hf_opcua_returnDiag_mask_ol_additionalinfo, {"OperationLevel / AdditionalInfo", "opcua.returndiag.operationlevel.additionalinfo", FT_BOOLEAN, 16, NULL, RETURNDIAGNOSTICS_OPERATIONLEVEL_ADDITIONALINFO, NULL, HFILL}}, |
||
456 | {&hf_opcua_returnDiag_mask_ol_innerstatuscode, {"OperationLevel / Inner StatusCode", "opcua.returndiag.operationlevel.innerstatuscode", FT_BOOLEAN, 16, NULL, RETURNDIAGNOSTICS_OPERATIONLEVEL_INNERSTATUSCODE, NULL, HFILL}}, |
||
457 | {&hf_opcua_returnDiag_mask_ol_innerdiagnostics, {"OperationLevel / Inner Diagnostics", "opcua.returndiag.operationlevel.innerdiagnostics", FT_BOOLEAN, 16, NULL, RETURNDIAGNOSTICS_OPERATIONLEVEL_INNERDIAGNOSTICS, NULL, HFILL}}, |
||
458 | }; |
||
459 | |||
460 | static ei_register_info ei[] = { |
||
461 | { &ei_array_length, { "opcua.array.length", PI_UNDECODED, PI_ERROR, "Max array length exceeded", EXPFILL }}, |
||
462 | }; |
||
463 | |||
464 | proto_register_field_array(proto, hf, array_length(hf)); |
||
465 | proto_register_subtree_array(ett, array_length(ett)); |
||
466 | |||
467 | expert_proto = expert_register_protocol(proto); |
||
468 | expert_register_field_array(expert_proto, ei, array_length(ei)); |
||
469 | } |
||
470 | |||
471 | proto_item* parseBoolean(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint *pOffset, int hfIndex) |
||
472 | { |
||
473 | proto_item *item = proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 1, ENC_LITTLE_ENDIAN); |
||
474 | *pOffset+=1; |
||
475 | return item; |
||
476 | } |
||
477 | |||
478 | proto_item* parseByte(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint *pOffset, int hfIndex) |
||
479 | { |
||
480 | proto_item *item = proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 1, ENC_LITTLE_ENDIAN); |
||
481 | *pOffset+=1; |
||
482 | return item; |
||
483 | } |
||
484 | |||
485 | proto_item* parseSByte(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint *pOffset, int hfIndex) |
||
486 | { |
||
487 | proto_item *item = proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 1, ENC_LITTLE_ENDIAN); |
||
488 | *pOffset+=1; |
||
489 | return item; |
||
490 | } |
||
491 | |||
492 | proto_item* parseUInt16(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint *pOffset, int hfIndex) |
||
493 | { |
||
494 | proto_item *item = proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 2, ENC_LITTLE_ENDIAN); |
||
495 | *pOffset+=2; |
||
496 | return item; |
||
497 | } |
||
498 | |||
499 | proto_item* parseInt16(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint *pOffset, int hfIndex) |
||
500 | { |
||
501 | proto_item *item = proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 2, ENC_LITTLE_ENDIAN); |
||
502 | *pOffset+=2; |
||
503 | return item; |
||
504 | } |
||
505 | |||
506 | proto_item* parseUInt32(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint *pOffset, int hfIndex) |
||
507 | { |
||
508 | proto_item *item = proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); |
||
509 | *pOffset+=4; |
||
510 | return item; |
||
511 | } |
||
512 | |||
513 | proto_item* parseInt32(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint *pOffset, int hfIndex) |
||
514 | { |
||
515 | proto_item *item = proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); |
||
516 | *pOffset+=4; |
||
517 | return item; |
||
518 | } |
||
519 | |||
520 | proto_item* parseUInt64(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint *pOffset, int hfIndex) |
||
521 | { |
||
522 | proto_item *item = proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 8, ENC_LITTLE_ENDIAN); |
||
523 | *pOffset+=8; |
||
524 | return item; |
||
525 | } |
||
526 | |||
527 | proto_item* parseInt64(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint *pOffset, int hfIndex) |
||
528 | { |
||
529 | proto_item *item = proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 8, ENC_LITTLE_ENDIAN); |
||
530 | *pOffset+=8; |
||
531 | return item; |
||
532 | } |
||
533 | |||
534 | proto_item* parseString(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint *pOffset, int hfIndex) |
||
535 | { |
||
536 | proto_item *item = NULL; |
||
537 | char *szValue; |
||
538 | gint iOffset = *pOffset; |
||
539 | gint32 iLen = tvb_get_letohl(tvb, *pOffset); |
||
540 | iOffset+=4; |
||
541 | |||
542 | if (iLen == -1) |
||
543 | { |
||
544 | item = proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 0, ENC_NA); |
||
545 | proto_item_append_text(item, "[OpcUa Null String]"); |
||
546 | proto_item_set_end(item, tvb, *pOffset + 4); |
||
547 | } |
||
548 | else if (iLen == 0) |
||
549 | { |
||
550 | item = proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 0, ENC_NA); |
||
551 | proto_item_append_text(item, "[OpcUa Empty String]"); |
||
552 | proto_item_set_end(item, tvb, *pOffset + 4); |
||
553 | } |
||
554 | else if (iLen > 0) |
||
555 | { |
||
556 | item = proto_tree_add_item(tree, hfIndex, tvb, iOffset, iLen, ENC_UTF_8|ENC_NA); |
||
557 | iOffset += iLen; /* eat the whole string */ |
||
558 | } |
||
559 | else |
||
560 | { |
||
561 | item = proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 0, ENC_NA); |
||
562 | szValue = wmem_strdup_printf(wmem_packet_scope(), "[Invalid String] Invalid length: %d", iLen); |
||
563 | proto_item_append_text(item, "%s", szValue); |
||
564 | proto_item_set_end(item, tvb, *pOffset + 4); |
||
565 | } |
||
566 | |||
567 | *pOffset = iOffset; |
||
568 | return item; |
||
569 | } |
||
570 | |||
571 | proto_item* parseStatusCode(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint *pOffset, int hfIndex) |
||
572 | { |
||
573 | proto_item *item = NULL; |
||
574 | guint32 uStatusCode = 0; |
||
575 | const gchar *szStatusCode = NULL; |
||
576 | |||
577 | item = proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); |
||
578 | |||
579 | uStatusCode = tvb_get_letohl(tvb, *pOffset); |
||
580 | szStatusCode = val_to_str_const(uStatusCode & 0xFFFF0000, g_statusCodes, "Unknown Status Code"); |
||
581 | proto_item_append_text(item, " [%s]", szStatusCode); |
||
582 | |||
583 | /* check for status code info flags */ |
||
584 | if (uStatusCode & 0x0000FFFF) |
||
585 | { |
||
586 | gint iOffset = *pOffset; |
||
587 | proto_tree *flags_tree; |
||
588 | proto_item *ti_inner; |
||
589 | |||
590 | flags_tree = proto_item_add_subtree(item, ett_opcua_statuscode); |
||
591 | |||
592 | proto_tree_add_item(flags_tree, hf_opcua_status_StructureChanged, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); |
||
593 | proto_tree_add_item(flags_tree, hf_opcua_status_SemanticsChanged, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); |
||
594 | ti_inner = proto_tree_add_item(flags_tree, hf_opcua_status_InfoType, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); |
||
595 | |||
596 | switch (uStatusCode & 0x00000C00) |
||
597 | { |
||
598 | case STATUSCODE_INFOTYPE_DATAVALUE: |
||
599 | { |
||
600 | /* InfoType == DataValue */ |
||
601 | proto_tree *tree_inner; |
||
602 | |||
603 | tree_inner = proto_item_add_subtree(ti_inner, ett_opcua_statuscode_info); |
||
604 | |||
605 | proto_tree_add_item(tree_inner, hf_opcua_status_Limit, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); |
||
606 | proto_tree_add_item(tree_inner, hf_opcua_status_InfoBit_Limit_Overflow, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); |
||
607 | proto_tree_add_item(tree_inner, hf_opcua_status_InfoBit_Historian_MultiValue, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); |
||
608 | proto_tree_add_item(tree_inner, hf_opcua_status_InfoBit_Historian_ExtraData, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); |
||
609 | proto_tree_add_item(tree_inner, hf_opcua_status_InfoBit_Historian_Partial, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); |
||
610 | proto_tree_add_item(tree_inner, hf_opcua_status_Historian, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); |
||
611 | } |
||
612 | default: |
||
613 | break; |
||
614 | } |
||
615 | } |
||
616 | |||
617 | *pOffset += 4; |
||
618 | return item; |
||
619 | } |
||
620 | |||
621 | void parseLocalizedText(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOffset, const char *szFieldName) |
||
622 | { |
||
623 | static const int *loctext_mask[] = {&hf_opcua_loctext_mask_localeflag, |
||
624 | &hf_opcua_loctext_mask_textflag, |
||
625 | NULL}; |
||
626 | |||
627 | gint iOffset = *pOffset; |
||
628 | guint8 EncodingMask; |
||
629 | proto_tree *subtree; |
||
630 | proto_item *ti; |
||
631 | |||
632 | subtree = proto_tree_add_subtree_format(tree, tvb, *pOffset, -1, ett_opcua_localizedtext, &ti, "%s: LocalizedText", szFieldName); |
||
633 | |||
634 | /* parse encoding mask */ |
||
635 | EncodingMask = tvb_get_guint8(tvb, iOffset); |
||
636 | proto_tree_add_bitmask(subtree, tvb, iOffset, hf_opcua_loctext_mask, ett_opcua_localizedtext_encodingmask, loctext_mask, ENC_LITTLE_ENDIAN); |
||
637 | iOffset++; |
||
638 | |||
639 | if (EncodingMask & LOCALIZEDTEXT_ENCODINGBYTE_LOCALE) |
||
640 | { |
||
641 | parseString(subtree, tvb, pinfo, &iOffset, hf_opcua_localizedtext_locale); |
||
642 | } |
||
643 | |||
644 | if (EncodingMask & LOCALIZEDTEXT_ENCODINGBYTE_TEXT) |
||
645 | { |
||
646 | parseString(subtree, tvb, pinfo, &iOffset, hf_opcua_localizedtext_text); |
||
647 | } |
||
648 | |||
649 | proto_item_set_end(ti, tvb, iOffset); |
||
650 | *pOffset = iOffset; |
||
651 | } |
||
652 | |||
653 | proto_item* parseGuid(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint *pOffset, int hfIndex) |
||
654 | { |
||
655 | proto_item *item = proto_tree_add_item(tree, hfIndex, tvb, *pOffset, GUID_LEN, ENC_NA); |
||
656 | *pOffset+=GUID_LEN; |
||
657 | return item; |
||
658 | } |
||
659 | |||
660 | proto_item* parseByteString(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint *pOffset, int hfIndex) |
||
661 | { |
||
662 | proto_item *item = NULL; |
||
663 | char *szValue; |
||
664 | int iOffset = *pOffset; |
||
665 | gint32 iLen = tvb_get_letohl(tvb, iOffset); |
||
666 | iOffset += 4; |
||
667 | |||
668 | if (iLen == -1) |
||
669 | { |
||
670 | item = proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 0, ENC_NA); |
||
671 | proto_item_append_text(item, "[OpcUa Null ByteString]"); |
||
672 | proto_item_set_end(item, tvb, *pOffset + 4); |
||
673 | } |
||
674 | else if (iLen == 0) |
||
675 | { |
||
676 | item = proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 0, ENC_NA); |
||
677 | proto_item_append_text(item, "[OpcUa Empty ByteString]"); |
||
678 | proto_item_set_end(item, tvb, *pOffset + 4); |
||
679 | } |
||
680 | else if (iLen > 0) |
||
681 | { |
||
682 | item = proto_tree_add_item(tree, hfIndex, tvb, iOffset, iLen, ENC_NA); |
||
683 | iOffset += iLen; /* eat the whole bytestring */ |
||
684 | } |
||
685 | else |
||
686 | { |
||
687 | item = proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 0, ENC_NA); |
||
688 | szValue = wmem_strdup_printf(wmem_packet_scope(), "[Invalid ByteString] Invalid length: %d", iLen); |
||
689 | proto_item_append_text(item, "%s", szValue); |
||
690 | proto_item_set_end(item, tvb, *pOffset + 4); |
||
691 | } |
||
692 | |||
693 | *pOffset = iOffset; |
||
694 | return item; |
||
695 | } |
||
696 | |||
697 | proto_item* parseXmlElement(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOffset, int hfIndex) |
||
698 | { |
||
699 | return parseByteString(tree, tvb, pinfo, pOffset, hfIndex); |
||
700 | } |
||
701 | |||
702 | proto_item* parseFloat(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint *pOffset, int hfIndex) |
||
703 | { |
||
704 | proto_item *item = proto_tree_add_item(tree, hfIndex, tvb, *pOffset, (int)sizeof(gfloat), ENC_LITTLE_ENDIAN); |
||
705 | *pOffset += (int)sizeof(gfloat); |
||
706 | return item; |
||
707 | } |
||
708 | |||
709 | proto_item* parseDouble(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint *pOffset, int hfIndex) |
||
710 | { |
||
711 | proto_item *item = proto_tree_add_item(tree, hfIndex, tvb, *pOffset, (int)sizeof(gdouble), ENC_LITTLE_ENDIAN); |
||
712 | *pOffset += (int)sizeof(gdouble); |
||
713 | return item; |
||
714 | } |
||
715 | |||
716 | proto_item* parseDateTime(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint *pOffset, int hfIndex) |
||
717 | { |
||
718 | proto_item *item = NULL; |
||
719 | *pOffset = dissect_nt_64bit_time_ex(tvb, tree, *pOffset, hfIndex, &item, FALSE); |
||
720 | return item; |
||
721 | } |
||
722 | |||
723 | void parseDiagnosticInfo(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOffset, const char *szFieldName) |
||
724 | { |
||
725 | static const int *diag_mask[] = {&hf_opcua_diag_mask_symbolicflag, |
||
726 | &hf_opcua_diag_mask_namespaceflag, |
||
727 | &hf_opcua_diag_mask_localizedtextflag, |
||
728 | &hf_opcua_diag_mask_localeflag, |
||
729 | &hf_opcua_diag_mask_additionalinfoflag, |
||
730 | &hf_opcua_diag_mask_innerstatuscodeflag, |
||
731 | &hf_opcua_diag_mask_innerdiaginfoflag, |
||
732 | NULL}; |
||
733 | |||
734 | gint iOffset = *pOffset; |
||
735 | guint8 EncodingMask; |
||
736 | proto_tree *subtree; |
||
737 | proto_item *ti; |
||
738 | |||
739 | subtree = proto_tree_add_subtree_format(tree, tvb, *pOffset, -1, ett_opcua_diagnosticinfo, &ti, "%s: DiagnosticInfo", szFieldName); |
||
740 | |||
741 | /* parse encoding mask */ |
||
742 | EncodingMask = tvb_get_guint8(tvb, iOffset); |
||
743 | proto_tree_add_bitmask(subtree, tvb, iOffset, hf_opcua_diag_mask, ett_opcua_diagnosticinfo_encodingmask, diag_mask, ENC_LITTLE_ENDIAN); |
||
744 | iOffset++; |
||
745 | |||
746 | if (EncodingMask & DIAGNOSTICINFO_ENCODINGMASK_SYMBOLICID_FLAG) |
||
747 | { |
||
748 | parseInt32(subtree, tvb, pinfo, &iOffset, hf_opcua_diag_symbolicid); |
||
749 | } |
||
750 | if (EncodingMask & DIAGNOSTICINFO_ENCODINGMASK_NAMESPACE_FLAG) |
||
751 | { |
||
752 | parseInt32(subtree, tvb, pinfo, &iOffset, hf_opcua_diag_namespace); |
||
753 | } |
||
754 | if (EncodingMask & DIAGNOSTICINFO_ENCODINGMASK_LOCALIZEDTEXT_FLAG) |
||
755 | { |
||
756 | parseInt32(subtree, tvb, pinfo, &iOffset, hf_opcua_diag_localizedtext); |
||
757 | } |
||
758 | if (EncodingMask & DIAGNOSTICINFO_ENCODINGMASK_LOCALE_FLAG) |
||
759 | { |
||
760 | parseInt32(subtree, tvb, pinfo, &iOffset, hf_opcua_diag_locale); |
||
761 | } |
||
762 | if (EncodingMask & DIAGNOSTICINFO_ENCODINGMASK_ADDITIONALINFO_FLAG) |
||
763 | { |
||
764 | parseString(subtree, tvb, pinfo, &iOffset, hf_opcua_diag_additionalinfo); |
||
765 | } |
||
766 | if (EncodingMask & DIAGNOSTICINFO_ENCODINGMASK_INNERSTATUSCODE_FLAG) |
||
767 | { |
||
768 | parseStatusCode(subtree, tvb, pinfo, &iOffset, hf_opcua_diag_innerstatuscode); |
||
769 | } |
||
770 | if (EncodingMask & DIAGNOSTICINFO_ENCODINGMASK_INNERDIAGNOSTICINFO_FLAG) |
||
771 | { |
||
772 | parseDiagnosticInfo(subtree, tvb, pinfo, &iOffset, "Inner DiagnosticInfo"); |
||
773 | } |
||
774 | |||
775 | proto_item_set_end(ti, tvb, iOffset); |
||
776 | *pOffset = iOffset; |
||
777 | } |
||
778 | |||
779 | void parseQualifiedName(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOffset, const char *szFieldName) |
||
780 | { |
||
781 | proto_item *ti; |
||
782 | proto_tree *subtree = proto_tree_add_subtree_format(tree, tvb, *pOffset, -1, |
||
783 | ett_opcua_qualifiedname, &ti, "%s: QualifiedName", szFieldName); |
||
784 | |||
785 | parseUInt16(subtree, tvb, pinfo, pOffset, hf_opcua_qualifiedname_id); |
||
786 | parseString(subtree, tvb, pinfo, pOffset, hf_opcua_qualifiedname_name); |
||
787 | |||
788 | proto_item_set_end(ti, tvb, *pOffset); |
||
789 | } |
||
790 | |||
791 | void parseDataValue(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOffset, const char *szFieldName) |
||
792 | { |
||
793 | static const int *datavalue_mask[] = {&hf_opcua_datavalue_mask_valueflag, |
||
794 | &hf_opcua_datavalue_mask_statuscodeflag, |
||
795 | &hf_opcua_datavalue_mask_sourcetimestampflag, |
||
796 | &hf_opcua_datavalue_mask_servertimestampflag, |
||
797 | &hf_opcua_datavalue_mask_sourcepicoseconds, |
||
798 | &hf_opcua_datavalue_mask_serverpicoseconds, |
||
799 | NULL}; |
||
800 | |||
801 | proto_item *ti; |
||
802 | proto_tree *subtree = proto_tree_add_subtree_format(tree, tvb, *pOffset, -1, |
||
803 | ett_opcua_datavalue, &ti, "%s: DataValue", szFieldName); |
||
804 | gint iOffset = *pOffset; |
||
805 | guint8 EncodingMask; |
||
806 | |||
807 | EncodingMask = tvb_get_guint8(tvb, iOffset); |
||
808 | proto_tree_add_bitmask(subtree, tvb, iOffset, hf_opcua_datavalue_mask, ett_opcua_datavalue_encodingmask, datavalue_mask, ENC_LITTLE_ENDIAN); |
||
809 | iOffset++; |
||
810 | |||
811 | if (EncodingMask & DATAVALUE_ENCODINGBYTE_VALUE) |
||
812 | { |
||
813 | parseVariant(subtree, tvb, pinfo, &iOffset, "Value"); |
||
814 | } |
||
815 | if (EncodingMask & DATAVALUE_ENCODINGBYTE_STATUSCODE) |
||
816 | { |
||
817 | parseStatusCode(subtree, tvb, pinfo, &iOffset, hf_opcua_StatusCode); |
||
818 | } |
||
819 | if (EncodingMask & DATAVALUE_ENCODINGBYTE_SOURCETIMESTAMP) |
||
820 | { |
||
821 | parseDateTime(subtree, tvb, pinfo, &iOffset, hf_opcua_SourceTimestamp); |
||
822 | } |
||
823 | if (EncodingMask & DATAVALUE_ENCODINGBYTE_SOURCEPICOSECONDS) |
||
824 | { |
||
825 | parseUInt16(subtree, tvb, pinfo, &iOffset, hf_opcua_SourcePicoseconds); |
||
826 | } |
||
827 | if (EncodingMask & DATAVALUE_ENCODINGBYTE_SERVERTIMESTAMP) |
||
828 | { |
||
829 | parseDateTime(subtree, tvb, pinfo, &iOffset, hf_opcua_ServerTimestamp); |
||
830 | } |
||
831 | if (EncodingMask & DATAVALUE_ENCODINGBYTE_SERVERPICOSECONDS) |
||
832 | { |
||
833 | parseUInt16(subtree, tvb, pinfo, &iOffset, hf_opcua_ServerPicoseconds); |
||
834 | } |
||
835 | |||
836 | proto_item_set_end(ti, tvb, iOffset); |
||
837 | *pOffset = iOffset; |
||
838 | } |
||
839 | |||
840 | void parseVariant(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOffset, const char *szFieldName) |
||
841 | { |
||
842 | proto_item *ti; |
||
843 | proto_tree *subtree = proto_tree_add_subtree_format(tree, tvb, *pOffset, -1, |
||
844 | ett_opcua_variant, &ti, "%s: Variant", szFieldName); |
||
845 | gint iOffset = *pOffset; |
||
846 | guint8 EncodingMask; |
||
847 | gint32 ArrayDimensions = 0; |
||
848 | |||
849 | EncodingMask = tvb_get_guint8(tvb, iOffset); |
||
850 | proto_tree_add_item(subtree, hf_opcua_variant_encodingmask, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); |
||
851 | iOffset++; |
||
852 | |||
853 | if (EncodingMask & VARIANT_ARRAYMASK) |
||
854 | { |
||
855 | /* type is encoded in bits 0-5 */ |
||
856 | switch(EncodingMask & 0x3f) |
||
857 | { |
||
858 | case OpcUaType_Null: break; |
||
859 | case OpcUaType_Boolean: parseArraySimple(subtree, tvb, pinfo, &iOffset, "Boolean", "Boolean", hf_opcua_Boolean, parseBoolean, ett_opcua_array_Boolean); break; |
||
860 | case OpcUaType_SByte: parseArraySimple(subtree, tvb, pinfo, &iOffset, "SByte", "SByte", hf_opcua_SByte, parseSByte, ett_opcua_array_SByte); break; |
||
861 | case OpcUaType_Byte: parseArraySimple(subtree, tvb, pinfo, &iOffset, "Byte", "Byte", hf_opcua_Byte, parseByte, ett_opcua_array_Byte); break; |
||
862 | case OpcUaType_Int16: parseArraySimple(subtree, tvb, pinfo, &iOffset, "Int16", "Int16", hf_opcua_Int16, parseInt16, ett_opcua_array_Int16); break; |
||
863 | case OpcUaType_UInt16: parseArraySimple(subtree, tvb, pinfo, &iOffset, "UInt16", "UInt16", hf_opcua_UInt16, parseUInt16, ett_opcua_array_UInt16); break; |
||
864 | case OpcUaType_Int32: parseArraySimple(subtree, tvb, pinfo, &iOffset, "Int32", "Int32", hf_opcua_Int32, parseInt32, ett_opcua_array_Int32); break; |
||
865 | case OpcUaType_UInt32: parseArraySimple(subtree, tvb, pinfo, &iOffset, "UInt32", "UInt32", hf_opcua_UInt32, parseUInt32, ett_opcua_array_UInt32); break; |
||
866 | case OpcUaType_Int64: parseArraySimple(subtree, tvb, pinfo, &iOffset, "Int64", "Int64", hf_opcua_Int64, parseInt64, ett_opcua_array_Int64); break; |
||
867 | case OpcUaType_UInt64: parseArraySimple(subtree, tvb, pinfo, &iOffset, "UInt64", "UInt64", hf_opcua_UInt64, parseUInt64, ett_opcua_array_UInt64); break; |
||
868 | case OpcUaType_Float: parseArraySimple(subtree, tvb, pinfo, &iOffset, "Float", "Float", hf_opcua_Float, parseFloat, ett_opcua_array_Float); break; |
||
869 | case OpcUaType_Double: parseArraySimple(subtree, tvb, pinfo, &iOffset, "Double", "Double", hf_opcua_Double, parseDouble, ett_opcua_array_Double); break; |
||
870 | case OpcUaType_String: parseArraySimple(subtree, tvb, pinfo, &iOffset, "String", "String", hf_opcua_String, parseString, ett_opcua_array_String); break; |
||
871 | case OpcUaType_DateTime: parseArraySimple(subtree, tvb, pinfo, &iOffset, "DateTime", "DateTime", hf_opcua_DateTime, parseDateTime, ett_opcua_array_DateTime); break; |
||
872 | case OpcUaType_Guid: parseArraySimple(subtree, tvb, pinfo, &iOffset, "Guid", "Guid", hf_opcua_Guid, parseGuid, ett_opcua_array_Guid); break; |
||
873 | case OpcUaType_ByteString: parseArraySimple(subtree, tvb, pinfo, &iOffset, "ByteString", "ByteString", hf_opcua_ByteString, parseByteString, ett_opcua_array_ByteString); break; |
||
874 | case OpcUaType_XmlElement: parseArraySimple(subtree, tvb, pinfo, &iOffset, "XmlElement", "XmlElement", hf_opcua_XmlElement, parseXmlElement, ett_opcua_array_XmlElement); break; |
||
875 | case OpcUaType_NodeId: parseArrayComplex(subtree, tvb, pinfo, &iOffset, "NodeId", "NodeId", parseNodeId, ett_opcua_array_NodeId); break; |
||
876 | case OpcUaType_ExpandedNodeId: parseArrayComplex(subtree, tvb, pinfo, &iOffset, "ExpandedNodeId", "ExpandedNodeId", parseExpandedNodeId, ett_opcua_array_ExpandedNodeId); break; |
||
877 | case OpcUaType_StatusCode: parseArraySimple(subtree, tvb, pinfo, &iOffset, "StatusCode", "StatusCode", hf_opcua_StatusCode, parseStatusCode, ett_opcua_array_StatusCode); break; |
||
878 | case OpcUaType_DiagnosticInfo: parseArrayComplex(subtree, tvb, pinfo, &iOffset, "DiagnosticInfo", "DiagnosticInfo", parseDiagnosticInfo, ett_opcua_array_DiagnosticInfo); break; |
||
879 | case OpcUaType_QualifiedName: parseArrayComplex(subtree, tvb, pinfo, &iOffset, "QualifiedName", "QualifiedName", parseQualifiedName, ett_opcua_array_QualifiedName); break; |
||
880 | case OpcUaType_LocalizedText: parseArrayComplex(subtree, tvb, pinfo, &iOffset, "LocalizedText", "LocalizedText", parseLocalizedText, ett_opcua_array_LocalizedText); break; |
||
881 | case OpcUaType_ExtensionObject: parseArrayComplex(subtree, tvb, pinfo, &iOffset, "ExtensionObject", "ExtensionObject", parseExtensionObject, ett_opcua_array_ExtensionObject); break; |
||
882 | case OpcUaType_DataValue: parseArrayComplex(subtree, tvb, pinfo, &iOffset, "DataValue", "DataValue", parseDataValue, ett_opcua_array_DataValue); break; |
||
883 | case OpcUaType_Variant: parseArrayComplex(subtree, tvb, pinfo, &iOffset, "Variant", "Variant", parseVariant, ett_opcua_array_Variant); break; |
||
884 | } |
||
885 | |||
886 | if (EncodingMask & VARIANT_ARRAYDIMENSIONS) |
||
887 | { |
||
888 | proto_item *ti_2; |
||
889 | proto_tree *subtree_2 = proto_tree_add_subtree(subtree, tvb, iOffset, -1, |
||
890 | ett_opcua_variant_arraydims, &ti_2, "ArrayDimensions"); |
||
891 | int i; |
||
892 | |||
893 | /* read array length */ |
||
894 | ArrayDimensions = tvb_get_letohl(tvb, iOffset); |
||
895 | proto_tree_add_item(subtree_2, hf_opcua_ArraySize, tvb, iOffset, 4, ENC_LITTLE_ENDIAN); |
||
896 | |||
897 | if (ArrayDimensions > MAX_ARRAY_LEN) |
||
898 | { |
||
899 | proto_tree_add_expert_format(subtree_2, pinfo, &ei_array_length, tvb, iOffset, 4, "ArrayDimensions length %d too large to process", ArrayDimensions); |
||
900 | return; |
||
901 | } |
||
902 | |||
903 | iOffset += 4; |
||
904 | for (i=0; i<ArrayDimensions; i++) |
||
905 | { |
||
906 | parseInt32(subtree_2, tvb, pinfo, &iOffset, hf_opcua_Int32); |
||
907 | } |
||
908 | proto_item_set_end(ti_2, tvb, iOffset); |
||
909 | } |
||
910 | } |
||
911 | else |
||
912 | { |
||
913 | /* type is encoded in bits 0-5 */ |
||
914 | switch(EncodingMask & 0x3f) |
||
915 | { |
||
916 | case OpcUaType_Null: break; |
||
917 | case OpcUaType_Boolean: parseBoolean(subtree, tvb, pinfo, &iOffset, hf_opcua_Boolean); break; |
||
918 | case OpcUaType_SByte: parseSByte(subtree, tvb, pinfo, &iOffset, hf_opcua_SByte); break; |
||
919 | case OpcUaType_Byte: parseByte(subtree, tvb, pinfo, &iOffset, hf_opcua_Byte); break; |
||
920 | case OpcUaType_Int16: parseInt16(subtree, tvb, pinfo, &iOffset, hf_opcua_Int16); break; |
||
921 | case OpcUaType_UInt16: parseUInt16(subtree, tvb, pinfo, &iOffset, hf_opcua_UInt16); break; |
||
922 | case OpcUaType_Int32: parseInt32(subtree, tvb, pinfo, &iOffset, hf_opcua_Int32); break; |
||
923 | case OpcUaType_UInt32: parseUInt32(subtree, tvb, pinfo, &iOffset, hf_opcua_UInt32); break; |
||
924 | case OpcUaType_Int64: parseInt64(subtree, tvb, pinfo, &iOffset, hf_opcua_Int64); break; |
||
925 | case OpcUaType_UInt64: parseUInt64(subtree, tvb, pinfo, &iOffset, hf_opcua_UInt64); break; |
||
926 | case OpcUaType_Float: parseFloat(subtree, tvb, pinfo, &iOffset, hf_opcua_Float); break; |
||
927 | case OpcUaType_Double: parseDouble(subtree, tvb, pinfo, &iOffset, hf_opcua_Double); break; |
||
928 | case OpcUaType_String: parseString(subtree, tvb, pinfo, &iOffset, hf_opcua_String); break; |
||
929 | case OpcUaType_DateTime: parseDateTime(subtree, tvb, pinfo, &iOffset, hf_opcua_DateTime); break; |
||
930 | case OpcUaType_Guid: parseGuid(subtree, tvb, pinfo, &iOffset, hf_opcua_Guid); break; |
||
931 | case OpcUaType_ByteString: parseByteString(subtree, tvb, pinfo, &iOffset, hf_opcua_ByteString); break; |
||
932 | case OpcUaType_XmlElement: parseXmlElement(subtree, tvb, pinfo, &iOffset, hf_opcua_XmlElement); break; |
||
933 | case OpcUaType_NodeId: parseNodeId(subtree, tvb, pinfo, &iOffset, "Value"); break; |
||
934 | case OpcUaType_ExpandedNodeId: parseExpandedNodeId(subtree, tvb, pinfo, &iOffset, "Value"); break; |
||
935 | case OpcUaType_StatusCode: parseStatusCode(subtree, tvb, pinfo, &iOffset, hf_opcua_StatusCode); break; |
||
936 | case OpcUaType_DiagnosticInfo: parseDiagnosticInfo(subtree, tvb, pinfo, &iOffset, "Value"); break; |
||
937 | case OpcUaType_QualifiedName: parseQualifiedName(subtree, tvb, pinfo, &iOffset, "Value"); break; |
||
938 | case OpcUaType_LocalizedText: parseLocalizedText(subtree, tvb, pinfo, &iOffset, "Value"); break; |
||
939 | case OpcUaType_ExtensionObject: parseExtensionObject(subtree, tvb, pinfo, &iOffset, "Value"); break; |
||
940 | case OpcUaType_DataValue: parseDataValue(subtree, tvb, pinfo, &iOffset, "Value"); break; |
||
941 | case OpcUaType_Variant: parseVariant(subtree, tvb, pinfo, &iOffset, "Value"); break; |
||
942 | } |
||
943 | } |
||
944 | |||
945 | proto_item_set_end(ti, tvb, iOffset); |
||
946 | *pOffset = iOffset; |
||
947 | } |
||
948 | |||
949 | /** General parsing function for arrays of simple types. |
||
950 | * All arrays have one 4 byte signed integer length information, |
||
951 | * followed by n data elements. |
||
952 | */ |
||
953 | void parseArraySimple(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOffset, const char *szFieldName, const char *szTypeName, int hfIndex, fctSimpleTypeParser pParserFunction, const gint idx) |
||
954 | { |
||
955 | proto_item *ti; |
||
956 | proto_tree *subtree = proto_tree_add_subtree_format(tree, tvb, *pOffset, -1, idx, &ti, "%s: Array of %s", szFieldName, szTypeName); |
||
957 | int i; |
||
958 | gint32 iLen; |
||
959 | |||
960 | /* read array length */ |
||
961 | iLen = tvb_get_letohl(tvb, *pOffset); |
||
962 | proto_tree_add_item(subtree, hf_opcua_ArraySize, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); |
||
963 | |||
964 | if (iLen > MAX_ARRAY_LEN) |
||
965 | { |
||
966 | proto_tree_add_expert_format(subtree, pinfo, &ei_array_length, tvb, *pOffset, 4, "Array length %d too large to process", iLen); |
||
967 | return; |
||
968 | } |
||
969 | |||
970 | *pOffset += 4; |
||
971 | for (i=0; i<iLen; i++) |
||
972 | { |
||
973 | proto_item *arrayItem = (*pParserFunction)(subtree, tvb, pinfo, pOffset, hfIndex); |
||
974 | if (arrayItem != NULL) |
||
975 | { |
||
976 | proto_item_prepend_text(arrayItem, "[%i]: ", i); |
||
977 | } |
||
978 | } |
||
979 | proto_item_set_end(ti, tvb, *pOffset); |
||
980 | } |
||
981 | |||
982 | /** General parsing function for arrays of enums. |
||
983 | * All arrays have one 4 byte signed integer length information, |
||
984 | * followed by n data elements. |
||
985 | */ |
||
986 | void parseArrayEnum(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOffset, const char *szFieldName, const char *szTypeName, fctEnumParser pParserFunction, const gint idx) |
||
987 | { |
||
988 | proto_item *ti; |
||
989 | proto_tree *subtree = proto_tree_add_subtree_format(tree, tvb, *pOffset, -1, idx, &ti, "%s: Array of %s", szFieldName, szTypeName); |
||
990 | int i; |
||
991 | gint32 iLen; |
||
992 | |||
993 | /* read array length */ |
||
994 | iLen = tvb_get_letohl(tvb, *pOffset); |
||
995 | proto_tree_add_item(subtree, hf_opcua_ArraySize, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); |
||
996 | |||
997 | if (iLen > MAX_ARRAY_LEN) |
||
998 | { |
||
999 | proto_tree_add_expert_format(subtree, pinfo, &ei_array_length, tvb, *pOffset, 4, "Array length %d too large to process", iLen); |
||
1000 | return; |
||
1001 | } |
||
1002 | |||
1003 | *pOffset += 4; |
||
1004 | for (i=0; i<iLen; i++) |
||
1005 | { |
||
1006 | (*pParserFunction)(subtree, tvb, pinfo, pOffset); |
||
1007 | } |
||
1008 | proto_item_set_end(ti, tvb, *pOffset); |
||
1009 | } |
||
1010 | |||
1011 | /** General parsing function for arrays of complex types. |
||
1012 | * All arrays have one 4 byte signed integer length information, |
||
1013 | * followed by n data elements. |
||
1014 | */ |
||
1015 | void parseArrayComplex(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOffset, const char *szFieldName, const char *szTypeName, fctComplexTypeParser pParserFunction, const gint idx) |
||
1016 | { |
||
1017 | proto_item *ti; |
||
1018 | proto_tree *subtree = proto_tree_add_subtree_format(tree, tvb, *pOffset, -1, idx, &ti, "%s: Array of %s", szFieldName, szTypeName); |
||
1019 | int i; |
||
1020 | gint32 iLen; |
||
1021 | |||
1022 | /* read array length */ |
||
1023 | iLen = tvb_get_letohl(tvb, *pOffset); |
||
1024 | proto_tree_add_item(subtree, hf_opcua_ArraySize, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); |
||
1025 | |||
1026 | if (iLen > MAX_ARRAY_LEN) |
||
1027 | { |
||
1028 | proto_tree_add_expert_format(subtree, pinfo, &ei_array_length, tvb, *pOffset, 4, "Array length %d too large to process", iLen); |
||
1029 | return; |
||
1030 | } |
||
1031 | |||
1032 | *pOffset += 4; |
||
1033 | for (i=0; i<iLen; i++) |
||
1034 | { |
||
1035 | char szNum[20]; |
||
1036 | g_snprintf(szNum, 20, "[%i]", i); |
||
1037 | (*pParserFunction)(subtree, tvb, pinfo, pOffset, szNum); |
||
1038 | } |
||
1039 | proto_item_set_end(ti, tvb, *pOffset); |
||
1040 | } |
||
1041 | |||
1042 | void parseNodeId(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOffset, const char *szFieldName) |
||
1043 | { |
||
1044 | proto_item *ti; |
||
1045 | proto_tree *subtree = proto_tree_add_subtree_format(tree, tvb, *pOffset, -1, ett_opcua_nodeid, &ti, "%s: NodeId", szFieldName); |
||
1046 | gint iOffset = *pOffset; |
||
1047 | guint8 EncodingMask; |
||
1048 | |||
1049 | EncodingMask = tvb_get_guint8(tvb, iOffset); |
||
1050 | proto_tree_add_item(subtree, hf_opcua_nodeid_encodingmask, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); |
||
1051 | iOffset++; |
||
1052 | |||
1053 | switch(EncodingMask) |
||
1054 | { |
||
1055 | case 0x00: /* two byte node id */ |
||
1056 | proto_tree_add_item(subtree, hf_opcua_nodeid_numeric, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); |
||
1057 | iOffset+=1; |
||
1058 | break; |
||
1059 | case 0x01: /* four byte node id */ |
||
1060 | proto_tree_add_item(subtree, hf_opcua_nodeid_nsindex, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); |
||
1061 | iOffset+=1; |
||
1062 | proto_tree_add_item(subtree, hf_opcua_nodeid_numeric, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); |
||
1063 | iOffset+=2; |
||
1064 | break; |
||
1065 | case 0x02: /* numeric, that does not fit into four bytes */ |
||
1066 | proto_tree_add_item(subtree, hf_opcua_nodeid_nsindex, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); |
||
1067 | iOffset+=2; |
||
1068 | proto_tree_add_item(subtree, hf_opcua_nodeid_numeric, tvb, iOffset, 4, ENC_LITTLE_ENDIAN); |
||
1069 | iOffset+=4; |
||
1070 | break; |
||
1071 | case 0x03: /* string */ |
||
1072 | proto_tree_add_item(subtree, hf_opcua_nodeid_nsindex, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); |
||
1073 | iOffset+=2; |
||
1074 | parseString(subtree, tvb, pinfo, &iOffset, hf_opcua_nodeid_string); |
||
1075 | break; |
||
1076 | case 0x04: /* guid */ |
||
1077 | proto_tree_add_item(subtree, hf_opcua_nodeid_nsindex, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); |
||
1078 | iOffset+=2; |
||
1079 | parseGuid(subtree, tvb, pinfo, &iOffset, hf_opcua_nodeid_guid); |
||
1080 | break; |
||
1081 | case 0x05: /* byte string */ |
||
1082 | proto_tree_add_item(subtree, hf_opcua_nodeid_nsindex, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); |
||
1083 | iOffset+=2; |
||
1084 | parseByteString(subtree, tvb, pinfo, &iOffset, hf_opcua_nodeid_bytestring); |
||
1085 | break; |
||
1086 | }; |
||
1087 | |||
1088 | proto_item_set_end(ti, tvb, iOffset); |
||
1089 | *pOffset = iOffset; |
||
1090 | } |
||
1091 | |||
1092 | void parseExtensionObject(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOffset, const char *szFieldName) |
||
1093 | { |
||
1094 | static const int *extobj_mask[] = {&hf_opcua_extobj_mask_binbodyflag, |
||
1095 | &hf_opcua_extobj_mask_xmlbodyflag, |
||
1096 | NULL}; |
||
1097 | |||
1098 | gint iOffset = *pOffset; |
||
1099 | guint8 EncodingMask; |
||
1100 | guint32 TypeId; |
||
1101 | proto_tree *extobj_tree; |
||
1102 | proto_item *ti; |
||
1103 | |||
1104 | /* add extension object subtree */ |
||
1105 | extobj_tree = proto_tree_add_subtree_format(tree, tvb, *pOffset, -1, ett_opcua_extensionobject, &ti, "%s: ExtensionObject", szFieldName); |
||
1106 | |||
1107 | /* add nodeid subtree */ |
||
1108 | TypeId = getExtensionObjectType(tvb, &iOffset); |
||
1109 | parseExpandedNodeId(extobj_tree, tvb, pinfo, &iOffset, "TypeId"); |
||
1110 | |||
1111 | /* parse encoding mask */ |
||
1112 | EncodingMask = tvb_get_guint8(tvb, iOffset); |
||
1113 | proto_tree_add_bitmask(extobj_tree, tvb, iOffset, hf_opcua_extobj_mask, ett_opcua_extensionobject_encodingmask, extobj_mask, ENC_LITTLE_ENDIAN); |
||
1114 | iOffset++; |
||
1115 | |||
1116 | if (EncodingMask & EXTOBJ_ENCODINGMASK_BINBODY_FLAG) /* has binary body ? */ |
||
1117 | { |
||
1118 | dispatchExtensionObjectType(extobj_tree, tvb, pinfo, &iOffset, TypeId); |
||
1119 | } |
||
1120 | |||
1121 | proto_item_set_end(ti, tvb, iOffset); |
||
1122 | *pOffset = iOffset; |
||
1123 | } |
||
1124 | |||
1125 | void parseExpandedNodeId(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOffset, const char *szFieldName) |
||
1126 | { |
||
1127 | static const int *expandednodeid_mask[] = {&hf_opcua_nodeid_encodingmask, |
||
1128 | &hf_opcua_expandednodeid_mask_serverindex, |
||
1129 | &hf_opcua_expandednodeid_mask_namespaceuri, |
||
1130 | NULL}; |
||
1131 | |||
1132 | proto_item *ti; |
||
1133 | proto_tree *subtree = proto_tree_add_subtree_format(tree, tvb, *pOffset, -1, |
||
1134 | ett_opcua_expandednodeid, &ti, "%s: ExpandedNodeId", szFieldName); |
||
1135 | gint iOffset = *pOffset; |
||
1136 | guint8 EncodingMask; |
||
1137 | |||
1138 | EncodingMask = tvb_get_guint8(tvb, iOffset); |
||
1139 | proto_tree_add_bitmask(subtree, tvb, iOffset, hf_opcua_expandednodeid_mask, ett_opcua_expandednodeid_encodingmask, expandednodeid_mask, ENC_LITTLE_ENDIAN); |
||
1140 | iOffset++; |
||
1141 | |||
1142 | switch(EncodingMask & 0x0F) |
||
1143 | { |
||
1144 | case 0x00: /* two byte node id */ |
||
1145 | proto_tree_add_item(subtree, hf_opcua_nodeid_numeric, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); |
||
1146 | iOffset+=1; |
||
1147 | break; |
||
1148 | case 0x01: /* four byte node id */ |
||
1149 | proto_tree_add_item(subtree, hf_opcua_nodeid_nsindex, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); |
||
1150 | iOffset+=1; |
||
1151 | proto_tree_add_item(subtree, hf_opcua_nodeid_numeric, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); |
||
1152 | iOffset+=2; |
||
1153 | break; |
||
1154 | case 0x02: /* numeric, that does not fit into four bytes */ |
||
1155 | proto_tree_add_item(subtree, hf_opcua_nodeid_nsindex, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); |
||
1156 | iOffset+=2; |
||
1157 | proto_tree_add_item(subtree, hf_opcua_nodeid_numeric, tvb, iOffset, 4, ENC_LITTLE_ENDIAN); |
||
1158 | iOffset+=4; |
||
1159 | break; |
||
1160 | case 0x03: /* string */ |
||
1161 | proto_tree_add_item(subtree, hf_opcua_nodeid_nsindex, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); |
||
1162 | iOffset+=2; |
||
1163 | parseString(subtree, tvb, pinfo, &iOffset, hf_opcua_nodeid_string); |
||
1164 | break; |
||
1165 | case 0x04: /* guid */ |
||
1166 | proto_tree_add_item(subtree, hf_opcua_nodeid_nsindex, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); |
||
1167 | iOffset+=2; |
||
1168 | parseGuid(subtree, tvb, pinfo, &iOffset, hf_opcua_nodeid_guid); |
||
1169 | break; |
||
1170 | case 0x05: /* byte string */ |
||
1171 | proto_tree_add_item(subtree, hf_opcua_nodeid_nsindex, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); |
||
1172 | iOffset+=2; |
||
1173 | parseByteString(subtree, tvb, pinfo, &iOffset, hf_opcua_nodeid_bytestring); |
||
1174 | break; |
||
1175 | }; |
||
1176 | |||
1177 | if (EncodingMask & NODEID_NAMESPACEURIFLAG) |
||
1178 | { |
||
1179 | parseString(subtree, tvb, pinfo, &iOffset, hf_opcua_NamespaceUri); |
||
1180 | } |
||
1181 | if (EncodingMask & NODEID_SERVERINDEXFLAG) |
||
1182 | { |
||
1183 | parseUInt32(subtree, tvb, pinfo, &iOffset, hf_opcua_ServerIndex); |
||
1184 | } |
||
1185 | |||
1186 | proto_item_set_end(ti, tvb, iOffset); |
||
1187 | *pOffset = iOffset; |
||
1188 | } |
||
1189 | |||
1190 | guint32 getExtensionObjectType(tvbuff_t *tvb, gint *pOffset) |
||
1191 | { |
||
1192 | gint iOffset = *pOffset; |
||
1193 | guint8 EncodingMask; |
||
1194 | guint32 Numeric = 0; |
||
1195 | |||
1196 | EncodingMask = tvb_get_guint8(tvb, iOffset); |
||
1197 | iOffset++; |
||
1198 | |||
1199 | switch(EncodingMask) |
||
1200 | { |
||
1201 | case 0x00: /* two byte node id */ |
||
1202 | Numeric = tvb_get_guint8(tvb, iOffset); |
||
1203 | /*iOffset+=1;*/ |
||
1204 | break; |
||
1205 | case 0x01: /* four byte node id */ |
||
1206 | iOffset+=1; |
||
1207 | Numeric = tvb_get_letohs(tvb, iOffset); |
||
1208 | break; |
||
1209 | case 0x02: /* numeric, that does not fit into four bytes */ |
||
1210 | iOffset+=4; |
||
1211 | Numeric = tvb_get_letohl(tvb, iOffset); |
||
1212 | break; |
||
1213 | case 0x03: /* string */ |
||
1214 | case 0x04: /* uri */ |
||
1215 | case 0x05: /* guid */ |
||
1216 | case 0x06: /* byte string */ |
||
1217 | /* NOT USED */ |
||
1218 | break; |
||
1219 | }; |
||
1220 | |||
1221 | return Numeric; |
||
1222 | } |
||
1223 | |||
1224 | /* |
||
1225 | * Editor modelines - http://www.wireshark.org/tools/modelines.html |
||
1226 | * |
||
1227 | * Local variables: |
||
1228 | * c-basic-offset: 4 |
||
1229 | * tab-width: 8 |
||
1230 | * indent-tabs-mode: nil |
||
1231 | * End: |
||
1232 | * |
||
1233 | * vi: set shiftwidth=4 tabstop=8 expandtab: |
||
1234 | * :indentSize=4:tabSize=8:noTabs=true: |
||
1235 | */ |