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