b96e92adff9b76e6e31ab3b2b3f28a042aefd44d
[obnox/wireshark/wip.git] / plugins / opcua / opcua_transport_layer.c
1 /******************************************************************************
2 ** $Id$
3 **
4 ** Copyright (C) 2006-2007 ascolab GmbH. All Rights Reserved.
5 ** Web: http://www.ascolab.com
6 ** 
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.
11 ** 
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.
14 ** 
15 ** Project: OpcUa Wireshark Plugin
16 **
17 ** Description: OpcUa Transport Layer Decoder.
18 **
19 ** Author: Gerhard Gappmeier <gerhard.gappmeier@ascolab.com>
20 ** Last change by: $Author: gergap $
21 **
22 ******************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #include <gmodule.h>
29 #include <epan/packet.h>
30 #include "opcua_security_layer.h"
31 #include "opcua_application_layer.h"
32 #include "opcua_simpletypes.h"
33 #include <string.h>
34 #include <epan/emem.h>
35
36 void dispatchService(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, int ServiceId);
37
38 static int hf_opcua_transport_sig = -1;
39 static int hf_opcua_transport_len = -1;
40 static int hf_opcua_transport_ver = -1;
41 static int hf_opcua_transport_cid = -1;
42 static int hf_opcua_transport_lifetime = -1;
43 static int hf_opcua_transport_sbl = -1;
44 static int hf_opcua_transport_rbl = -1;
45 static int hf_opcua_transport_endpoint = -1;
46 static int hf_opcua_transport_rlifetime = -1;
47 static int hf_opcua_transport_rsbl = -1;
48 static int hf_opcua_transport_rrbl = -1;
49 static int hf_opcua_transport_altendpoint = -1;
50 static int hf_opcua_transport_rqid = -1;
51 static int hf_opcua_transport_status = -1;
52 extern gint ett_opcua_nodeid;
53
54 static hf_register_info hf[] =
55 {
56     { &hf_opcua_transport_sig,
57     /* full name  ,           abbreviation  ,       type     , display  , strings, bitmask, blurb, id, parent, ref_count, bitshift */
58     {  "Signature",           "transport.sig",      FT_STRING, BASE_NONE, NULL,    0x0,     "",    HFILL }
59     },
60     { &hf_opcua_transport_len,
61     {  "Message Length",      "transport.len",      FT_UINT32, BASE_DEC,  NULL, 0x0,    "",    HFILL }
62     },
63     { &hf_opcua_transport_ver,
64     {  "Version",             "transport.ver",      FT_UINT32, BASE_DEC,  NULL, 0x0,    "",    HFILL }
65     },
66     { &hf_opcua_transport_cid,
67     {  "ConnectionId",        "transport.cid",      FT_GUID,   BASE_NONE, NULL, 0x0,    "",    HFILL }
68     },
69     { &hf_opcua_transport_lifetime,
70     {  "Lifetime",            "transport.lifetime", FT_UINT32, BASE_DEC,  NULL, 0x0,    "",    HFILL }
71     },
72     { &hf_opcua_transport_sbl,
73     {  "SendBufferLength",    "transport.sbl",      FT_UINT32, BASE_DEC,  NULL, 0x0,    "",    HFILL }
74     },
75     { &hf_opcua_transport_rbl,
76     {  "ReceiveBufferLength", "transport.rbl",      FT_UINT32, BASE_DEC,  NULL, 0x0,    "",    HFILL }
77     },
78     { &hf_opcua_transport_endpoint,
79     {  "EndPoint",            "transport.endpoint", FT_STRING, BASE_NONE, NULL, 0x0,    "",    HFILL }
80     },
81     { &hf_opcua_transport_rlifetime,
82     {  "Revised Lifetime",    "transport.rlifetime", FT_UINT32, BASE_DEC,  NULL, 0x0,    "",    HFILL }
83     },
84     { &hf_opcua_transport_rsbl,
85     {  "Revised SendBufferLength", "transport.rsbl", FT_UINT32, BASE_DEC,  NULL, 0x0,    "",    HFILL }
86     },
87     { &hf_opcua_transport_rrbl,
88     {  "Revised ReceiveBufferLength", "transport.rrbl", FT_UINT32, BASE_DEC,  NULL, 0x0,    "",    HFILL }
89     },
90     { &hf_opcua_transport_altendpoint,
91     {  "Alternate EndPoint",  "transport.altendpoint", FT_STRING, BASE_NONE, NULL, 0x0,    "",    HFILL }
92     },
93     { &hf_opcua_transport_rqid,
94     {  "RequestId",           "transport.rqid",     FT_UINT32, BASE_DEC,  NULL, 0x0,    "",    HFILL }
95     },
96     { &hf_opcua_transport_status,
97     {  "StatusCode",          "transport.status",   FT_UINT32, BASE_DEC,  NULL, 0x0,    "",    HFILL }
98     }
99 };
100
101 /** subtree types */
102 extern gint ett_opcua_extensionobject;
103
104 /** Register transport layer types. */
105 void registerTransportLayerTypes(int proto)
106 {
107     proto_register_field_array(proto, hf, array_length(hf));
108 }
109
110 /** helper functions for adding strings,
111   * that are not zero terminated.
112   */
113 void addString(proto_tree *tree,  
114                int  hfindex,  
115                tvbuff_t *tvb,  
116                gint  start,  
117                gint  length,  
118                const char *value)
119 {
120     char *szValue = ep_alloc(256);
121
122     if (szValue)
123     {
124         if (length > 255) length = 255;
125         /* copy non null terminated string data */
126         strncpy(szValue, value, length);
127         /* set null terminator */
128         szValue[length] = 0;
129
130         proto_tree_add_string(tree, hfindex, tvb, start, length, szValue);
131     }
132 }
133
134 /* Transport Layer: message parsers */
135 void parseHello(proto_tree *tree, tvbuff_t *tvb, gint *pOffset)
136 {
137     addString(tree, hf_opcua_transport_sig, tvb, *pOffset, 4, tvb->real_data); *pOffset+=4;
138     proto_tree_add_item(tree, hf_opcua_transport_len, tvb, *pOffset, 4, TRUE); *pOffset+=4;
139     proto_tree_add_item(tree, hf_opcua_transport_ver, tvb, *pOffset, 4, TRUE); *pOffset+=4;
140     proto_tree_add_item(tree, hf_opcua_transport_cid, tvb, *pOffset, 16, TRUE); *pOffset+=16;
141     proto_tree_add_item(tree, hf_opcua_transport_lifetime, tvb, *pOffset, 4, TRUE); *pOffset+=4;
142     proto_tree_add_item(tree, hf_opcua_transport_sbl, tvb, *pOffset, 4, TRUE); *pOffset+=4;
143     proto_tree_add_item(tree, hf_opcua_transport_rbl, tvb, *pOffset, 4, TRUE); *pOffset+=4;
144     parseString(tree, tvb, pOffset, hf_opcua_transport_endpoint);
145 }
146
147 void parseAcknowledge(proto_tree *tree, tvbuff_t *tvb, gint *pOffset)
148 {
149     addString(tree, hf_opcua_transport_sig, tvb, *pOffset, 4, tvb->real_data); *pOffset+=4;
150     proto_tree_add_item(tree, hf_opcua_transport_len, tvb, *pOffset, 4, TRUE); *pOffset+=4;
151     proto_tree_add_item(tree, hf_opcua_transport_cid, tvb, *pOffset, 16, TRUE); *pOffset+=16;
152     proto_tree_add_item(tree, hf_opcua_transport_rlifetime, tvb, *pOffset, 4, TRUE); *pOffset+=4;
153     proto_tree_add_item(tree, hf_opcua_transport_rsbl, tvb, *pOffset, 4, TRUE); *pOffset+=4;
154     proto_tree_add_item(tree, hf_opcua_transport_rrbl, tvb, *pOffset, 4, TRUE); *pOffset+=4;
155     parseString(tree, tvb, pOffset, hf_opcua_transport_altendpoint);
156 }
157
158 void parseDisconnect(proto_tree *tree, tvbuff_t *tvb, gint *pOffset)
159 {
160     addString(tree, hf_opcua_transport_sig, tvb, *pOffset, 4, tvb->real_data); *pOffset+=4;
161     proto_tree_add_item(tree, hf_opcua_transport_len, tvb, *pOffset, 4, TRUE); *pOffset+=4;
162     proto_tree_add_item(tree, hf_opcua_transport_cid, tvb, *pOffset, 16, TRUE); *pOffset+=16;
163 }
164
165 void parseData(proto_tree *tree, tvbuff_t *tvb, gint *pOffset)
166 {
167     proto_item *ti;
168     proto_tree *encobj_tree;
169     proto_tree *nodeid_tree;
170     int ServiceId = 0;
171
172     addString(tree, hf_opcua_transport_sig, tvb, *pOffset, 4, tvb->real_data); *pOffset+=4;
173     proto_tree_add_item(tree, hf_opcua_transport_len, tvb, *pOffset, 4, TRUE); *pOffset+=4;
174     proto_tree_add_item(tree, hf_opcua_transport_cid, tvb, *pOffset, 16, TRUE); *pOffset+=16;
175     proto_tree_add_item(tree, hf_opcua_transport_rqid, tvb, *pOffset, 4, TRUE); *pOffset+=4;
176
177     /* message data contains the security layer */
178     parseSecurityLayer(tree, tvb, pOffset);
179
180     /* AT THE MOMENT NO SECURITY IS IMPLEMENTED IN UA.
181      * WE CAN JUST JUMP INTO THE APPLICATION LAYER DATA.
182      * THIS WILL CHAHNGE IN THE FUTURE. */
183
184     /* add encodeable object subtree */
185     ti = proto_tree_add_text(tree, tvb, 0, -1, "Message : Encodeable Object");
186     encobj_tree = proto_item_add_subtree(ti, ett_opcua_extensionobject);
187
188     /* add nodeid subtree */
189     ti = proto_tree_add_text(encobj_tree, tvb, 0, -1, "TypeId : ExpandedNodeId");
190     nodeid_tree = proto_item_add_subtree(ti, ett_opcua_nodeid);
191     ServiceId = parseServiceNodeId(nodeid_tree, tvb, pOffset, "NodeId") - 1;
192
193     dispatchService(encobj_tree, tvb, pOffset, ServiceId);
194 }
195
196 void parseAbort(proto_tree *tree, tvbuff_t *tvb, gint *pOffset)
197 {
198     addString(tree, hf_opcua_transport_sig, tvb, *pOffset, 4, tvb->real_data); *pOffset+=4;
199     proto_tree_add_item(tree, hf_opcua_transport_len, tvb, *pOffset, 4, TRUE); *pOffset+=4;
200     proto_tree_add_item(tree, hf_opcua_transport_cid, tvb, *pOffset, 16, TRUE); *pOffset+=16;
201     proto_tree_add_item(tree, hf_opcua_transport_rqid, tvb, *pOffset, 4, TRUE); *pOffset+=4;
202 }
203
204 void parseError(proto_tree *tree, tvbuff_t *tvb, gint *pOffset)
205 {
206     addString(tree, hf_opcua_transport_sig, tvb, *pOffset, 4, tvb->real_data); *pOffset+=4;
207     proto_tree_add_item(tree, hf_opcua_transport_len, tvb, *pOffset, 4, TRUE); *pOffset+=4;
208     proto_tree_add_item(tree, hf_opcua_transport_cid, tvb, *pOffset, 16, TRUE); *pOffset+=16;
209     proto_tree_add_item(tree, hf_opcua_transport_rqid, tvb, *pOffset, 4, TRUE); *pOffset+=4;
210     proto_tree_add_item(tree, hf_opcua_transport_status, tvb, *pOffset, 4, TRUE); *pOffset+=4;
211 }