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