1 /******************************************************************************
4 ** Copyright (C) 2006-2007 ascolab GmbH. All Rights Reserved.
5 ** Web: http://www.ascolab.com
7 ** This program is free software; you can redistribute it and/or
8 ** modify it under the terms of the GNU General Public License
9 ** as published by the Free Software Foundation; either version 2
10 ** of the License, or (at your option) any later version.
12 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
13 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
15 ** Project: OpcUa Wireshark Plugin
17 ** Description: Implementation of OpcUa built-in type parsers.
18 ** This contains all the simple types and some complex types.
20 ** Author: Gerhard Gappmeier <gerhard.gappmeier@ascolab.com>
21 ** Last change by: $Author: gergap $
23 ******************************************************************************/
30 #include <epan/packet.h>
31 #include <epan/dissectors/packet-windows-common.h>
32 #include "opcua_simpletypes.h"
33 #include "opcua_hfindeces.h"
35 #include <epan/emem.h>
38 #define MAX_BUFFER 256
40 #define DIAGNOSTICINFO_ENCODINGMASK_SYMBOLICID_FLAG 0x01
41 #define DIAGNOSTICINFO_ENCODINGMASK_NAMESPACE_FLAG 0x02
42 #define DIAGNOSTICINFO_ENCODINGMASK_LOCALIZEDTEXT_FLAG 0x04
43 #define DIAGNOSTICINFO_ENCODINGMASK_ADDITIONALINFO_FLAG 0x08
44 #define DIAGNOSTICINFO_ENCODINGMASK_INNERSTATUSCODE_FLAG 0x10
45 #define DIAGNOSTICINFO_ENCODINGMASK_INNERDIAGNOSTICINFO_FLAG 0x20
46 #define LOCALIZEDTEXT_ENCODINGBYTE_LOCALE 0x01
47 #define LOCALIZEDTEXT_ENCODINGBYTE_TEXT 0x02
48 #define NODEID_URIMASK 0x80
49 #define DATAVALUE_ENCODINGBYTE_VALUE 0x01
50 #define DATAVALUE_ENCODINGBYTE_STATUSCODE 0x02
51 #define DATAVALUE_ENCODINGBYTE_SOURCETIMESTAMP 0x04
52 #define DATAVALUE_ENCODINGBYTE_SERVERTIMESTAMP 0x08
53 #define EXTOBJ_ENCODINGMASK_BINBODY_FLAG 0x01
54 #define EXTOBJ_ENCODINGMASK_XMLBODY_FLAG 0x02
56 static int hf_opcua_diag_mask_symbolicflag = -1;
57 static int hf_opcua_diag_mask_namespaceflag = -1;
58 static int hf_opcua_diag_mask_localizedtextflag = -1;
59 static int hf_opcua_diag_mask_additionalinfoflag = -1;
60 static int hf_opcua_diag_mask_innerstatuscodeflag = -1;
61 static int hf_opcua_diag_mask_innerdiaginfoflag = -1;
62 static int hf_opcua_loctext_mask_localeflag = -1;
63 static int hf_opcua_loctext_mask_textflag = -1;
64 static int hf_opcua_datavalue_mask_valueflag = -1;
65 static int hf_opcua_datavalue_mask_statuscodeflag = -1;
66 static int hf_opcua_datavalue_mask_sourcetimestampflag = -1;
67 static int hf_opcua_datavalue_mask_servertimestampflag = -1;
68 static int hf_opcua_nodeid_encodingmask = -1;
69 static int hf_opcua_variant_encodingmask = -1;
70 static int hf_opcua_nodeid_nsid = -1;
71 static int hf_opcua_nodeid_numeric = -1;
72 static int hf_opcua_Locale = -1;
73 static int hf_opcua_Text = -1;
74 static int hf_opcua_SourceTimestamp = -1;
75 static int hf_opcua_ServerTimestamp = -1;
76 static int hf_opcua_diag_symbolicid = -1;
77 static int hf_opcua_diag_namespace = -1;
78 static int hf_opcua_diag_localizedtext = -1;
79 static int hf_opcua_diag_additionalinfo = -1;
80 static int hf_opcua_diag_innerstatuscode = -1;
81 static int hf_opcua_extobj_mask_binbodyflag = -1;
82 static int hf_opcua_extobj_mask_xmlbodyflag = -1;
84 /** NodeId encoding mask table */
85 static const value_string g_nodeidmasks[] = {
86 { 0, "Two byte encoded Numeric" },
87 { 1, "Four byte encoded Numeric" },
88 { 2, "Numeric of arbitrary length" },
97 /** UA Variant Type enum */
98 typedef enum _OpcUa_BuiltInType
101 OpcUaType_Boolean = 1,
105 OpcUaType_UInt16 = 5,
107 OpcUaType_UInt32 = 7,
109 OpcUaType_UInt64 = 9,
110 OpcUaType_Float = 10,
111 OpcUaType_Double = 11,
112 OpcUaType_String = 12,
113 OpcUaType_DateTime = 13,
115 OpcUaType_ByteString = 15,
116 OpcUaType_XmlElement = 16,
117 OpcUaType_NodeId = 17,
118 OpcUaType_ExpandedNodeId = 18,
119 OpcUaType_StatusCode = 19,
120 OpcUaType_DiagnosticInfo = 20,
121 OpcUaType_QualifiedName = 21,
122 OpcUaType_LocalizedText = 22,
123 OpcUaType_ExtensionObject = 23,
124 OpcUaType_DataValue = 24,
125 OpcUaType_Variant = 25
129 /** Variant encoding mask table */
130 static const value_string g_VariantTypes[] = {
146 { 15, "ByteString" },
147 { 16, "XmlElement" },
149 { 18, "ExpandedNodeId" },
150 { 19, "StatusCode" },
151 { 20, "DiagnosticInfo" },
152 { 21, "QualifiedName" },
153 { 22, "LocalizedText" },
154 { 23, "ExtensionObject" },
157 { 0x80, "Array of Null" },
158 { 0x80+1, "Array of Boolean" },
159 { 0x80+2, "Array of SByte" },
160 { 0x80+3, "Array of Byte" },
161 { 0x80+4, "Array of Int16" },
162 { 0x80+5, "Array of UInt16" },
163 { 0x80+6, "Array of Int32" },
164 { 0x80+7, "Array of UInt32" },
165 { 0x80+8, "Array of Int64" },
166 { 0x80+9, "Array of UInt64" },
167 { 0x80+10, "Array of Float" },
168 { 0x80+11, "Array of Double" },
169 { 0x80+12, "Array of String" },
170 { 0x80+13, "Array of DateTime" },
171 { 0x80+14, "Array of Guid" },
172 { 0x80+15, "Array of ByteString" },
173 { 0x80+16, "Array of XmlElement" },
174 { 0x80+17, "Array of NodeId" },
175 { 0x80+18, "Array of ExpandedNodeId" },
176 { 0x80+19, "Array of StatusCode" },
177 { 0x80+20, "Array of DiagnosticInfo" },
178 { 0x80+21, "Array of QualifiedName" },
179 { 0x80+22, "Array of LocalizedText" },
180 { 0x80+23, "Array of ExtensionObject" },
181 { 0x80+24, "Array of DataValue" },
182 { 0x80+25, "Array of Variant" },
185 #define VARIANT_ARRAYMASK 0x80
188 static gint ett_opcua_array = -1;
189 static gint ett_opcua_diagnosticinfo = -1;
190 static gint ett_opcua_nodeid = -1;
191 static gint ett_opcua_localeid = -1;
192 static gint ett_opcua_localizedtext = -1;
193 static gint ett_opcua_qualifiedname = -1;
194 static gint ett_opcua_datavalue = -1;
195 static gint ett_opcua_variant = -1;
196 static gint ett_opcua_extensionobject = -1;
197 static gint ett_opcua_extobj_encodingmask = -1;
201 &ett_opcua_diagnosticinfo,
204 &ett_opcua_localizedtext,
205 &ett_opcua_qualifiedname,
206 &ett_opcua_datavalue,
208 &ett_opcua_extensionobject,
209 &ett_opcua_extobj_encodingmask
213 static hf_register_info hf[] =
215 /* full name , abbreviation , type , display , strings, bitmask, blurb, id, parent, ref_count, bitshift */
216 { &hf_opcua_diag_mask_symbolicflag,
217 { "has symbolic id", "", FT_BOOLEAN, 8, NULL, DIAGNOSTICINFO_ENCODINGMASK_SYMBOLICID_FLAG, "", HFILL }
219 { &hf_opcua_diag_mask_namespaceflag,
220 { "has namespace", "", FT_BOOLEAN, 8, NULL, DIAGNOSTICINFO_ENCODINGMASK_NAMESPACE_FLAG, "", HFILL }
222 { &hf_opcua_diag_mask_localizedtextflag,
223 { "has localizedtext", "", FT_BOOLEAN, 8, NULL, DIAGNOSTICINFO_ENCODINGMASK_LOCALIZEDTEXT_FLAG, "", HFILL }
225 { &hf_opcua_diag_mask_additionalinfoflag,
226 { "has additional info", "", FT_BOOLEAN, 8, NULL, DIAGNOSTICINFO_ENCODINGMASK_ADDITIONALINFO_FLAG, "", HFILL }
228 { &hf_opcua_diag_mask_innerstatuscodeflag,
229 { "has inner statuscode", "", FT_BOOLEAN, 8, NULL, DIAGNOSTICINFO_ENCODINGMASK_INNERSTATUSCODE_FLAG, "", HFILL }
231 { &hf_opcua_diag_mask_innerdiaginfoflag,
232 { "has inner diagnostic info", "", FT_BOOLEAN, 8, NULL, DIAGNOSTICINFO_ENCODINGMASK_INNERDIAGNOSTICINFO_FLAG, "", HFILL }
234 { &hf_opcua_loctext_mask_localeflag,
235 { "has locale information", "", FT_BOOLEAN, 8, NULL, LOCALIZEDTEXT_ENCODINGBYTE_LOCALE, "", HFILL }
237 { &hf_opcua_loctext_mask_textflag,
238 { "has text", "", FT_BOOLEAN, 8, NULL, LOCALIZEDTEXT_ENCODINGBYTE_TEXT, "", HFILL }
240 { &hf_opcua_nodeid_encodingmask,
241 { "NodeId EncodingMask", "application.nodeid.encodingmask", FT_UINT8, BASE_HEX, VALS(g_nodeidmasks), 0x0, "", HFILL }
243 { &hf_opcua_nodeid_nsid,
244 { "NodeId Namespace Id", "application.nodeid.nsid", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
246 { &hf_opcua_nodeid_numeric,
247 { "NodeId Identifier Numeric", "application.nodeid.numeric", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
249 { &hf_opcua_Locale, { "Locale", "", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL } },
250 { &hf_opcua_Text, { "Text", "", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL } },
251 { &hf_opcua_datavalue_mask_valueflag, { "has value", "", FT_BOOLEAN, 8, NULL, DATAVALUE_ENCODINGBYTE_VALUE, "", HFILL } },
252 { &hf_opcua_datavalue_mask_statuscodeflag, { "has statuscode", "", FT_BOOLEAN, 8, NULL, DATAVALUE_ENCODINGBYTE_STATUSCODE, "", HFILL } },
253 { &hf_opcua_datavalue_mask_sourcetimestampflag, { "has source timestamp", "", FT_BOOLEAN, 8, NULL, DATAVALUE_ENCODINGBYTE_SOURCETIMESTAMP, "", HFILL } },
254 { &hf_opcua_datavalue_mask_servertimestampflag, { "has server timestamp", "", FT_BOOLEAN, 8, NULL, DATAVALUE_ENCODINGBYTE_SERVERTIMESTAMP, "", HFILL } },
255 { &hf_opcua_variant_encodingmask, { "Variant Type", "", FT_UINT8, BASE_HEX, VALS(g_VariantTypes), 0x0, "", HFILL } },
256 { &hf_opcua_SourceTimestamp, { "SourceTimestamp", "", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0, "", HFILL } },
257 { &hf_opcua_ServerTimestamp, { "ServerTimestamp", "", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0, "", HFILL } },
258 { &hf_opcua_diag_symbolicid, { "SymblicId", "", FT_INT32, BASE_DEC, NULL, 0x0, "", HFILL } },
259 { &hf_opcua_diag_namespace, { "Namespace", "", FT_INT32, BASE_DEC, NULL, 0x0, "", HFILL } },
260 { &hf_opcua_diag_localizedtext, { "LocaliezdText", "", FT_INT32, BASE_DEC, NULL, 0x0, "", HFILL } },
261 { &hf_opcua_diag_additionalinfo, { "AdditionalInfo", "", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL } },
262 { &hf_opcua_diag_innerstatuscode, { "InnerStatusCode", "", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL } },
263 { &hf_opcua_extobj_mask_binbodyflag, { "has binary body", "", FT_BOOLEAN, 8, NULL, EXTOBJ_ENCODINGMASK_BINBODY_FLAG, "", HFILL } },
264 { &hf_opcua_extobj_mask_xmlbodyflag, { "has xml body", "", FT_BOOLEAN, 8, NULL, EXTOBJ_ENCODINGMASK_XMLBODY_FLAG, "", HFILL } }
267 void registerSimpleTypes(int proto)
269 proto_register_field_array(proto, hf, array_length(hf));
270 proto_register_subtree_array(ett, array_length(ett));
273 void parseBoolean(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, int hfIndex)
275 proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 1, TRUE); *pOffset+=1;
278 void parseByte(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, int hfIndex)
280 proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 1, TRUE); *pOffset+=1;
283 void parseSByte(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, int hfIndex)
285 proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 1, TRUE); *pOffset+=1;
288 void parseUInt16(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, int hfIndex)
290 proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 2, TRUE); *pOffset+=2;
293 void parseInt16(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, int hfIndex)
295 proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 2, TRUE); *pOffset+=2;
298 void parseUInt32(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, int hfIndex)
300 proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 4, TRUE); *pOffset+=4;
303 void parseInt32(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, int hfIndex)
305 proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 4, TRUE); *pOffset+=4;
308 void parseUInt64(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, int hfIndex)
310 proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 8, TRUE); *pOffset+=8;
313 void parseInt64(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, int hfIndex)
315 proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 8, TRUE); *pOffset+=8;
318 void parseString(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, int hfIndex)
320 char *szValue = ep_alloc(MAX_BUFFER);
321 gint iOffset = *pOffset;
322 gint32 iLen = tvb_get_letohl(tvb, *pOffset);
329 g_snprintf(szValue, MAX_BUFFER, "[OpcUa Null String]");
334 if (iStrLen > (MAX_BUFFER-1)) iStrLen = MAX_BUFFER - 1;
335 /* copy non null terminated string of length iStrlen */
336 strncpy(szValue, (char*)&tvb->real_data[iOffset], iStrLen);
337 /* set null terminator */
338 szValue[iStrLen] = 0;
339 iOffset += iLen; /* eat the whole string */
343 g_snprintf(szValue, MAX_BUFFER, "[Invalid String] Ups, something is wrong with this message.");
346 proto_tree_add_string(tree, hfIndex, tvb, *pOffset, (iOffset - *pOffset), szValue);
351 void parseStatusCode(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, int hfIndex)
353 proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 4, TRUE);
357 void parseLocalizedText(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, char *szFieldName)
359 gint iOffset = *pOffset;
361 proto_tree *mask_tree;
365 ti = proto_tree_add_text(tree, tvb, 0, -1, "%s: LocalizedText", szFieldName);
366 subtree = proto_item_add_subtree(ti, ett_opcua_localizedtext);
368 /* parse encoding mask */
369 EncodingMask = tvb_get_guint8(tvb, iOffset);
370 ti = proto_tree_add_text(subtree, tvb, 0, -1, "EncodingMask");
371 mask_tree = proto_item_add_subtree(ti, ett_opcua_localizedtext);
372 proto_tree_add_item(mask_tree, hf_opcua_loctext_mask_localeflag, tvb, iOffset, 1, TRUE);
373 proto_tree_add_item(mask_tree, hf_opcua_loctext_mask_textflag, tvb, iOffset, 1, TRUE);
376 if (EncodingMask & LOCALIZEDTEXT_ENCODINGBYTE_LOCALE)
378 parseString(subtree, tvb, &iOffset, hf_opcua_Locale);
381 if (EncodingMask & LOCALIZEDTEXT_ENCODINGBYTE_TEXT)
383 parseString(subtree, tvb, &iOffset, hf_opcua_Text);
389 void parseGuid(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, int hfIndex)
391 proto_tree_add_item(tree, hfIndex, tvb, *pOffset, GUID_LEN, TRUE); *pOffset+=GUID_LEN;
394 void parseByteString(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, int hfIndex)
396 int iOffset = *pOffset;
397 gint32 iLen = tvb_get_letohl(tvb, iOffset);
407 proto_tree_add_item(tree, hfIndex, tvb, *pOffset, (iOffset - *pOffset), TRUE);
411 void parseXmlElement(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, int hfIndex)
413 parseByteString(tree, tvb, pOffset, hfIndex);
416 void parseFloat(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, int hfIndex)
418 proto_tree_add_item(tree, hfIndex, tvb, *pOffset, sizeof(gfloat), TRUE);
419 *pOffset += sizeof(gfloat);
422 void parseDouble(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, int hfIndex)
424 proto_tree_add_item(tree, hfIndex, tvb, *pOffset, sizeof(gdouble), TRUE);
425 *pOffset += sizeof(gdouble);
428 void parseDateTime(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, int hfIndex)
430 *pOffset = dissect_nt_64bit_time(tvb, tree, *pOffset, hfIndex);
433 void parseDiagnosticInfo(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, char *szFieldName)
435 gint iOffset = *pOffset;
437 proto_tree *mask_tree;
441 ti = proto_tree_add_text(tree, tvb, 0, -1, "%s: DiagnosticInfo", szFieldName);
442 subtree = proto_item_add_subtree(ti, ett_opcua_diagnosticinfo);
444 /* parse encoding mask */
445 EncodingMask = tvb_get_guint8(tvb, iOffset);
446 ti = proto_tree_add_text(subtree, tvb, 0, -1, "EncodingMask");
447 mask_tree = proto_item_add_subtree(ti, ett_opcua_diagnosticinfo);
448 proto_tree_add_item(mask_tree, hf_opcua_diag_mask_symbolicflag, tvb, iOffset, 1, TRUE);
449 proto_tree_add_item(mask_tree, hf_opcua_diag_mask_namespaceflag, tvb, iOffset, 1, TRUE);
450 proto_tree_add_item(mask_tree, hf_opcua_diag_mask_localizedtextflag, tvb, iOffset, 1, TRUE);
451 proto_tree_add_item(mask_tree, hf_opcua_diag_mask_additionalinfoflag, tvb, iOffset, 1, TRUE);
452 proto_tree_add_item(mask_tree, hf_opcua_diag_mask_innerstatuscodeflag, tvb, iOffset, 1, TRUE);
453 proto_tree_add_item(mask_tree, hf_opcua_diag_mask_innerdiaginfoflag, tvb, iOffset, 1, TRUE);
456 if (EncodingMask & DIAGNOSTICINFO_ENCODINGMASK_SYMBOLICID_FLAG)
458 parseInt32(subtree, tvb, &iOffset, hf_opcua_diag_symbolicid);
460 if (EncodingMask & DIAGNOSTICINFO_ENCODINGMASK_NAMESPACE_FLAG)
462 parseInt32(subtree, tvb, &iOffset, hf_opcua_diag_namespace);
464 if (EncodingMask & DIAGNOSTICINFO_ENCODINGMASK_LOCALIZEDTEXT_FLAG)
466 parseInt32(subtree, tvb, &iOffset, hf_opcua_diag_localizedtext);
468 if (EncodingMask & DIAGNOSTICINFO_ENCODINGMASK_ADDITIONALINFO_FLAG)
470 parseString(subtree, tvb, &iOffset, hf_opcua_diag_additionalinfo);
472 if (EncodingMask & DIAGNOSTICINFO_ENCODINGMASK_INNERSTATUSCODE_FLAG)
474 parseStatusCode(subtree, tvb, &iOffset, hf_opcua_diag_innerstatuscode);
476 if (EncodingMask & DIAGNOSTICINFO_ENCODINGMASK_INNERDIAGNOSTICINFO_FLAG)
478 parseDiagnosticInfo(subtree, tvb, &iOffset, "Inner DiagnosticInfo");
484 void parseQualifiedName(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, char *szFieldName)
486 proto_item *ti = proto_tree_add_text(tree, tvb, 0, -1, "%s: QualifiedName", szFieldName);
487 proto_tree *subtree = proto_item_add_subtree(ti, ett_opcua_qualifiedname);
489 parseInt32(subtree, tvb, pOffset, hf_opcua_Id);
490 parseString(subtree, tvb, pOffset, hf_opcua_Name);
493 void parseDataValue(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, char *szFieldName)
495 proto_item *ti = proto_tree_add_text(tree, tvb, 0, -1, "%s: DataValue", szFieldName);
496 proto_tree *subtree = proto_item_add_subtree(ti, ett_opcua_datavalue);
497 proto_tree *mask_tree;
498 gint iOffset = *pOffset;
501 EncodingMask = tvb_get_guint8(tvb, iOffset);
502 ti = proto_tree_add_text(subtree, tvb, 0, -1, "EncodingMask");
503 mask_tree = proto_item_add_subtree(ti, ett_opcua_datavalue);
504 proto_tree_add_item(mask_tree, hf_opcua_datavalue_mask_valueflag, tvb, iOffset, 1, TRUE);
505 proto_tree_add_item(mask_tree, hf_opcua_datavalue_mask_statuscodeflag, tvb, iOffset, 1, TRUE);
506 proto_tree_add_item(mask_tree, hf_opcua_datavalue_mask_sourcetimestampflag, tvb, iOffset, 1, TRUE);
507 proto_tree_add_item(mask_tree, hf_opcua_datavalue_mask_servertimestampflag, tvb, iOffset, 1, TRUE);
510 if (EncodingMask & DATAVALUE_ENCODINGBYTE_VALUE)
512 parseVariant(subtree, tvb, &iOffset, "Value");
514 if (EncodingMask & DATAVALUE_ENCODINGBYTE_STATUSCODE)
516 parseStatusCode(subtree, tvb, &iOffset, hf_opcua_StatusCode);
518 if (EncodingMask & DATAVALUE_ENCODINGBYTE_SOURCETIMESTAMP)
520 parseDateTime(subtree, tvb, &iOffset, hf_opcua_SourceTimestamp);
522 if (EncodingMask & DATAVALUE_ENCODINGBYTE_SERVERTIMESTAMP)
524 parseDateTime(subtree, tvb, &iOffset, hf_opcua_ServerTimestamp);
530 void parseVariant(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, char *szFieldName)
532 proto_item *ti = proto_tree_add_text(tree, tvb, 0, -1, "%s: Variant", szFieldName);
533 proto_tree *subtree = proto_item_add_subtree(ti, ett_opcua_variant);
534 gint iOffset = *pOffset;
537 EncodingMask = tvb_get_guint8(tvb, iOffset);
538 proto_tree_add_item(subtree, hf_opcua_variant_encodingmask, tvb, iOffset, 1, TRUE);
541 if (EncodingMask & VARIANT_ARRAYMASK)
543 EncodingMask &= ~VARIANT_ARRAYMASK;
547 case OpcUaType_Null: break;
548 case OpcUaType_Boolean: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_Boolean, parseBoolean); break;
549 case OpcUaType_SByte: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_SByte, parseSByte); break;
550 case OpcUaType_Byte: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_Byte, parseByte); break;
551 case OpcUaType_Int16: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_Int16, parseInt16); break;
552 case OpcUaType_UInt16: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_UInt16, parseUInt16); break;
553 case OpcUaType_Int32: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_Int32, parseInt32); break;
554 case OpcUaType_UInt32: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_UInt32, parseUInt32); break;
555 case OpcUaType_Int64: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_Int64, parseInt64); break;
556 case OpcUaType_UInt64: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_UInt64, parseUInt64); break;
557 case OpcUaType_Float: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_Float, parseFloat); break;
558 case OpcUaType_Double: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_Double, parseDouble); break;
559 case OpcUaType_String: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_String, parseString); break;
560 case OpcUaType_DateTime: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_DateTime, parseDateTime); break;
561 case OpcUaType_Guid: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_Guid, parseGuid); break;
562 case OpcUaType_ByteString: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_ByteString, parseByteString); break;
563 case OpcUaType_XmlElement: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_XmlElement, parseXmlElement); break;
564 case OpcUaType_NodeId: parseArrayComplex(subtree, tvb, &iOffset, "NodeId", parseNodeId); break;
565 case OpcUaType_ExpandedNodeId: parseArrayComplex(subtree, tvb, &iOffset, "ExpandedNodeId", parseExpandedNodeId); break;
566 case OpcUaType_StatusCode: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_StatusCode, parseStatusCode); break;
567 case OpcUaType_DiagnosticInfo: parseArrayComplex(subtree, tvb, &iOffset, "DiagnosticInfo", parseDiagnosticInfo); break;
568 case OpcUaType_QualifiedName: parseArrayComplex(subtree, tvb, &iOffset, "QualifiedName", parseQualifiedName); break;
569 case OpcUaType_LocalizedText: parseArrayComplex(subtree, tvb, &iOffset, "LocalizedText", parseLocalizedText); break;
570 case OpcUaType_ExtensionObject: parseArrayComplex(subtree, tvb, &iOffset, "ExtensionObject", parseExtensionObject); break;
571 case OpcUaType_DataValue: parseArrayComplex(subtree, tvb, &iOffset, "DataValue", parseDataValue); break;
572 case OpcUaType_Variant: parseArrayComplex(subtree, tvb, &iOffset, "Variant", parseVariant); break;
579 case OpcUaType_Null: break;
580 case OpcUaType_Boolean: parseBoolean(subtree, tvb, &iOffset, hf_opcua_Boolean); break;
581 case OpcUaType_SByte: parseSByte(subtree, tvb, &iOffset, hf_opcua_SByte); break;
582 case OpcUaType_Byte: parseByte(subtree, tvb, &iOffset, hf_opcua_Byte); break;
583 case OpcUaType_Int16: parseInt16(subtree, tvb, &iOffset, hf_opcua_Int16); break;
584 case OpcUaType_UInt16: parseUInt16(subtree, tvb, &iOffset, hf_opcua_UInt16); break;
585 case OpcUaType_Int32: parseInt32(subtree, tvb, &iOffset, hf_opcua_Int32); break;
586 case OpcUaType_UInt32: parseUInt32(subtree, tvb, &iOffset, hf_opcua_UInt32); break;
587 case OpcUaType_Int64: parseInt64(subtree, tvb, &iOffset, hf_opcua_Int64); break;
588 case OpcUaType_UInt64: parseUInt64(subtree, tvb, &iOffset, hf_opcua_UInt64); break;
589 case OpcUaType_Float: parseFloat(subtree, tvb, &iOffset, hf_opcua_Float); break;
590 case OpcUaType_Double: parseDouble(subtree, tvb, &iOffset, hf_opcua_Double); break;
591 case OpcUaType_String: parseString(subtree, tvb, &iOffset, hf_opcua_String); break;
592 case OpcUaType_DateTime: parseDateTime(subtree, tvb, &iOffset, hf_opcua_DateTime); break;
593 case OpcUaType_Guid: parseGuid(subtree, tvb, &iOffset, hf_opcua_Guid); break;
594 case OpcUaType_ByteString: parseByteString(subtree, tvb, &iOffset, hf_opcua_ByteString); break;
595 case OpcUaType_XmlElement: parseXmlElement(subtree, tvb, &iOffset, hf_opcua_XmlElement); break;
596 case OpcUaType_NodeId: parseNodeId(subtree, tvb, &iOffset, "Value"); break;
597 case OpcUaType_ExpandedNodeId: parseExpandedNodeId(subtree, tvb, &iOffset, "Value"); break;
598 case OpcUaType_StatusCode: parseStatusCode(subtree, tvb, &iOffset, hf_opcua_StatusCode); break;
599 case OpcUaType_DiagnosticInfo: parseDiagnosticInfo(subtree, tvb, &iOffset, "Value"); break;
600 case OpcUaType_QualifiedName: parseQualifiedName(subtree, tvb, &iOffset, "Value"); break;
601 case OpcUaType_LocalizedText: parseLocalizedText(subtree, tvb, &iOffset, "Value"); break;
602 case OpcUaType_ExtensionObject: parseExtensionObject(subtree, tvb, &iOffset, "Value"); break;
603 case OpcUaType_DataValue: parseDataValue(subtree, tvb, &iOffset, "Value"); break;
604 case OpcUaType_Variant: parseVariant(subtree, tvb, &iOffset, "Value"); break;
611 /** General parsing function for arrays of simple types.
612 * All arrays have one 4 byte signed integer length information,
613 * followed by n data elements.
615 void parseArraySimple(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, int hfIndex, fctSimpleTypeParser pParserFunction)
617 char szFieldName[] = "Array of Simple Type";
618 proto_item *ti = proto_tree_add_text(tree, tvb, 0, -1, szFieldName);
619 proto_tree *subtree = proto_item_add_subtree(ti, ett_opcua_array);
623 /* read array length */
624 iLen = tvb_get_letohl(tvb, *pOffset);
625 proto_tree_add_item(subtree, hf_opcua_ArraySize, tvb, *pOffset, 4, TRUE);
628 if (iLen == -1) return; /* no array */
629 if (iLen == 0) return; /* array with zero elements*/
631 for (i=0; i<iLen; i++)
633 (*pParserFunction)(subtree, tvb, pOffset, hfIndex);
637 /** General parsing function for arrays of enums.
638 * All arrays have one 4 byte signed integer length information,
639 * followed by n data elements.
641 void parseArrayEnum(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, fctEnumParser pParserFunction)
643 char szFieldName[] = "Array of Enum Type";
644 proto_item *ti = proto_tree_add_text(tree, tvb, 0, -1, szFieldName);
645 proto_tree *subtree = proto_item_add_subtree(ti, ett_opcua_array);
649 /* read array length */
650 iLen = tvb_get_letohl(tvb, *pOffset);
651 proto_tree_add_item(subtree, hf_opcua_ArraySize, tvb, *pOffset, 4, TRUE);
654 if (iLen == -1) return; /* no array */
655 if (iLen == 0) return; /* array with zero elements*/
657 for (i=0; i<iLen; i++)
659 (*pParserFunction)(subtree, tvb, pOffset);
663 /** General parsing function for arrays of complex types.
664 * All arrays have one 4 byte signed integer length information,
665 * followed by n data elements.
667 void parseArrayComplex(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, char *szFieldName, fctComplexTypeParser pParserFunction)
669 proto_item *ti = proto_tree_add_text(tree, tvb, 0, -1, "Array of %s", szFieldName);
670 proto_tree *subtree = proto_item_add_subtree(ti, ett_opcua_array);
674 /* read array length */
675 iLen = tvb_get_letohl(tvb, *pOffset);
676 proto_tree_add_item(subtree, hf_opcua_ArraySize, tvb, *pOffset, 4, TRUE);
679 if (iLen == -1) return; /* no array */
680 if (iLen == 0) return; /* array with zero elements*/
682 for (i=0; i<iLen; i++)
685 g_snprintf(szNum, 20, "[%i]", i);
686 (*pParserFunction)(subtree, tvb, pOffset, szNum);
690 void parseNodeId(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, char *szFieldName)
692 proto_item *ti = proto_tree_add_text(tree, tvb, 0, -1, "%s: NodeId", szFieldName);
693 proto_tree *subtree = proto_item_add_subtree(ti, ett_opcua_nodeid);
694 gint iOffset = *pOffset;
696 guint32 Numeric = 0, NSId = 0;
698 EncodingMask = tvb_get_guint8(tvb, iOffset);
699 proto_tree_add_item(subtree, hf_opcua_nodeid_encodingmask, tvb, iOffset, 1, TRUE);
704 case 0x00: /* two byte node id */
705 Numeric = tvb_get_guint8(tvb, iOffset);
706 proto_tree_add_item(subtree, hf_opcua_nodeid_numeric, tvb, iOffset, 1, TRUE);
709 case 0x01: /* four byte node id */
710 NSId = tvb_get_guint8(tvb, iOffset);
711 proto_tree_add_item(subtree, hf_opcua_nodeid_nsid, tvb, iOffset, 1, TRUE);
713 Numeric = tvb_get_letohs(tvb, iOffset);
714 proto_tree_add_item(subtree, hf_opcua_nodeid_numeric, tvb, iOffset, 2, TRUE);
717 case 0x02: /* numeric, that does not fit into four bytes */
718 NSId = tvb_get_letohl(tvb, iOffset);
719 proto_tree_add_item(subtree, hf_opcua_nodeid_nsid, tvb, iOffset, 4, TRUE);
721 Numeric = tvb_get_letohl(tvb, iOffset);
722 proto_tree_add_item(subtree, hf_opcua_nodeid_numeric, tvb, iOffset, 4, TRUE);
725 case 0x03: /* string */
726 NSId = tvb_get_letohl(tvb, iOffset);
727 proto_tree_add_item(subtree, hf_opcua_nodeid_nsid, tvb, iOffset, 4, TRUE);
729 parseString(subtree, tvb, &iOffset, hf_opcua_String);
732 parseString(subtree, tvb, &iOffset, hf_opcua_Uri);
734 case 0x05: /* guid */
735 parseGuid(subtree, tvb, &iOffset, hf_opcua_Guid);
737 case 0x06: /* byte string */
738 NSId = tvb_get_letohl(tvb, iOffset);
739 proto_tree_add_item(subtree, hf_opcua_nodeid_nsid, tvb, iOffset, 4, TRUE);
741 parseByteString(subtree, tvb, &iOffset, hf_opcua_ByteString);
748 void parseExtensionObject(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, char *szFieldName)
750 gint iOffset = *pOffset;
752 proto_tree *extobj_tree;
753 proto_tree *mask_tree;
756 /* add extension object subtree */
757 ti = proto_tree_add_text(tree, tvb, 0, -1, "%s : ExtensionObject", szFieldName);
758 extobj_tree = proto_item_add_subtree(ti, ett_opcua_extensionobject);
760 /* add nodeid subtree */
761 parseExpandedNodeId(extobj_tree, tvb, &iOffset, "TypeId");
763 /* parse encoding mask */
764 EncodingMask = tvb_get_guint8(tvb, iOffset);
765 ti = proto_tree_add_text(extobj_tree, tvb, 0, -1, "EncodingMask");
766 mask_tree = proto_item_add_subtree(ti, ett_opcua_extobj_encodingmask);
767 proto_tree_add_item(mask_tree, hf_opcua_extobj_mask_binbodyflag, tvb, iOffset, 1, TRUE);
768 proto_tree_add_item(mask_tree, hf_opcua_extobj_mask_xmlbodyflag, tvb, iOffset, 1, TRUE);
771 if (EncodingMask & EXTOBJ_ENCODINGMASK_BINBODY_FLAG) /* has binary body ? */
773 parseByteString(extobj_tree, tvb, &iOffset, hf_opcua_ByteString);
779 void parseExpandedNodeId(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, char *szFieldName)
781 proto_item *ti = proto_tree_add_text(tree, tvb, 0, -1, "%s: ExpandedNodeId", szFieldName);
782 proto_tree *subtree = proto_item_add_subtree(ti, ett_opcua_nodeid);
783 gint iOffset = *pOffset;
784 guint8 EncodingMask, NSId = 0;
787 EncodingMask = tvb_get_guint8(tvb, iOffset);
788 proto_tree_add_item(subtree, hf_opcua_nodeid_encodingmask, tvb, iOffset, 1, TRUE);
793 case 0x00: /* two byte node id */
794 Numeric = tvb_get_guint8(tvb, iOffset);
795 proto_tree_add_item(subtree, hf_opcua_nodeid_numeric, tvb, iOffset, 1, TRUE);
798 case 0x01: /* four byte node id */
799 NSId = tvb_get_guint8(tvb, iOffset);
800 proto_tree_add_item(subtree, hf_opcua_nodeid_nsid, tvb, iOffset, 1, TRUE);
802 Numeric = tvb_get_letohs(tvb, iOffset);
803 proto_tree_add_item(subtree, hf_opcua_nodeid_numeric, tvb, iOffset, 2, TRUE);
806 case 0x02: /* numeric, that does not fit into four bytes */
807 NSId = tvb_get_letohl(tvb, iOffset);
808 proto_tree_add_item(subtree, hf_opcua_nodeid_nsid, tvb, iOffset, 4, TRUE);
810 Numeric = tvb_get_letohl(tvb, iOffset);
811 proto_tree_add_item(subtree, hf_opcua_nodeid_numeric, tvb, iOffset, 4, TRUE);
814 case 0x03: /* string */
815 NSId = tvb_get_letohl(tvb, iOffset);
816 proto_tree_add_item(subtree, hf_opcua_nodeid_nsid, tvb, iOffset, 4, TRUE);
818 parseString(subtree, tvb, &iOffset, hf_opcua_String);
821 parseString(subtree, tvb, &iOffset, hf_opcua_Uri);
823 case 0x05: /* guid */
824 parseGuid(subtree, tvb, &iOffset, hf_opcua_Guid);
826 case 0x06: /* byte string */
827 NSId = tvb_get_letohl(tvb, iOffset);
828 proto_tree_add_item(subtree, hf_opcua_nodeid_nsid, tvb, iOffset, 4, TRUE);
830 parseByteString(subtree, tvb, &iOffset, hf_opcua_ByteString);
834 if (EncodingMask & NODEID_URIMASK)
836 parseString(subtree, tvb, &iOffset, hf_opcua_Uri);