Fixed warning "Field width should have type 'int'".
[obnox/wireshark/wip.git] / plugins / profinet / packet-pn-dcp.c
1 /* packet-pn-dcp.c
2  * Routines for PN-DCP (PROFINET Discovery and basic Configuration Protocol) 
3  * packet dissection.
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1999 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30
31 #ifdef HAVE_SYS_TYPES_H
32 #include <sys/types.h>
33 #endif
34
35 #include <string.h>
36
37 #include <glib.h>
38 #include <epan/packet.h>
39 #include <epan/emem.h>
40 #include <epan/expert.h>
41 #include <epan/dissectors/packet-dcerpc.h>
42
43 #include "packet-pn.h"
44
45
46
47 static int proto_pn_dcp = -1;
48
49 static int hf_pn_dcp = -1;
50
51 static int hf_pn_dcp_service_id = -1;
52 static int hf_pn_dcp_service_type = -1;
53 static int hf_pn_dcp_xid = -1;
54 static int hf_pn_dcp_reserved8 = -1;
55 static int hf_pn_dcp_reserved16 = -1;
56 static int hf_pn_dcp_response_delay = -1;
57 static int hf_pn_dcp_data_length = -1;
58 static int hf_pn_dcp_block_length = -1;
59
60 static int hf_pn_dcp_block = -1;
61
62 static int hf_pn_dcp_block_error = -1;
63
64 static int hf_pn_dcp_option = -1;
65 static int hf_pn_dcp_suboption = -1;
66 static int hf_pn_dcp_block_info = -1;
67 static int hf_pn_dcp_block_qualifier = -1;
68
69 static int hf_pn_dcp_suboption_ip = -1;
70 static int hf_pn_dcp_suboption_ip_block_info = -1;
71 static int hf_pn_dcp_suboption_ip_ip = -1;
72 static int hf_pn_dcp_suboption_ip_subnetmask = -1;
73 static int hf_pn_dcp_suboption_ip_standard_gateway = -1;
74
75 static int hf_pn_dcp_suboption_device = -1;
76 static int hf_pn_dcp_suboption_device_typeofstation = -1;
77 static int hf_pn_dcp_suboption_device_nameofstation = -1;
78 static int hf_pn_dcp_suboption_vendor_id = -1;
79 static int hf_pn_dcp_suboption_device_id = -1;
80 static int hf_pn_dcp_suboption_device_role = -1;
81 static int hf_pn_dcp_suboption_device_aliasname = -1;
82
83 static int hf_pn_dcp_suboption_dhcp = -1;
84 static int hf_pn_dcp_suboption_dhcp_device_id = -1;
85
86 static int hf_pn_dcp_suboption_control = -1;
87 static int hf_pn_dcp_suboption_control_response = -1;
88
89 static int hf_pn_dcp_suboption_deviceinitiative = -1;
90 static int hf_pn_dcp_deviceinitiative_value = -1;
91
92 static int hf_pn_dcp_suboption_all = -1;
93
94 static int hf_pn_dcp_suboption_manuf = -1;
95
96
97 static gint ett_pn_dcp = -1;
98 static gint ett_pn_dcp_block = -1;
99
100
101
102 #define PNDCP_SERVICE_ID_GET        0x03
103 #define PNDCP_SERVICE_ID_SET        0x04
104 #define PNDCP_SERVICE_ID_IDENTIFY   0x05
105 #define PNDCP_SERVICE_ID_HELLO      0x06
106
107 static const value_string pn_dcp_service_id[] = {
108     { 0x00,                     "reserved" },
109     { 0x01,                     "Manufacturer specific" },
110     { 0x02,                     "Manufacturer specific" },
111     { PNDCP_SERVICE_ID_GET,     "Get" },
112     { PNDCP_SERVICE_ID_SET,     "Set" },
113     { PNDCP_SERVICE_ID_IDENTIFY,"Identify" },
114     { PNDCP_SERVICE_ID_HELLO,   "Hello" },
115     /* 0x07 - 0xff reserved */
116     { 0, NULL }
117 };
118
119 #define PNDCP_SERVICE_TYPE_REQUEST              0
120 #define PNDCP_SERVICE_TYPE_RESPONSE_SUCCESS     1
121 #define PNDCP_SERVICE_TYPE_RESPONSE_UNSUPPORTED 5
122
123 static const value_string pn_dcp_service_type[] = {
124     { PNDCP_SERVICE_TYPE_REQUEST,               "Request" },
125     { PNDCP_SERVICE_TYPE_RESPONSE_SUCCESS,      "Response Success" },
126     { PNDCP_SERVICE_TYPE_RESPONSE_UNSUPPORTED,  "Response - Request not supported" },
127     /* all others reserved */
128     { 0, NULL }
129 };
130
131 static const value_string pn_dcp_block_error[] = {
132     { 0x00, "Ok" },
133     { 0x01, "Option unsupp." },
134     { 0x02, "Suboption unsupp. or no DataSet avail." },
135     { 0x03, "Suboption not set" },
136     { 0x04, "Resource Error" },
137     { 0x05, "SET not possible by local reasons" },
138     { 0x06, "In operation, SET not possible" },
139     /* all others reserved */
140     { 0, NULL }
141 };
142
143 static const value_string pn_dcp_block_info[] = {
144     { 0x0000, "Reserved" },
145     /*0x0001 - 0xffff reserved */
146     { 0, NULL }
147 };
148
149 static const value_string pn_dcp_block_qualifier[] = {
150     { 0x0000, "Use the value temporary" },
151     { 0x0001, "Save the value permanent" },
152     /*0x0002 - 0xffff reserved */
153     { 0, NULL }
154 };
155
156
157 #define PNDCP_OPTION_IP                 0x01
158 #define PNDCP_OPTION_DEVICE             0x02
159 #define PNDCP_OPTION_DHCP               0x03
160 #define PNDCP_OPTION_RESERVED           0x04
161 #define PNDCP_OPTION_CONTROL            0x05
162 #define PNDCP_OPTION_DEVICEINITIATIVE   0x06
163 #define PNDCP_OPTION_MANUF_X80          0x80
164 #define PNDCP_OPTION_MANUF_X81          0x81
165 #define PNDCP_OPTION_MANUF_X82          0x82
166 #define PNDCP_OPTION_MANUF_X83          0x83
167 #define PNDCP_OPTION_MANUF_X84          0x84
168 #define PNDCP_OPTION_MANUF_X85          0x85
169 #define PNDCP_OPTION_MANUF_X86          0x86
170 #define PNDCP_OPTION_ALLSELECTOR        0xff
171
172 static const value_string pn_dcp_option[] = {
173     { 0x00, "reserved" },
174     { PNDCP_OPTION_IP,                  "IP" },
175     { PNDCP_OPTION_DEVICE,              "Device properties" },
176     { PNDCP_OPTION_DHCP,                "DHCP" },
177     { PNDCP_OPTION_RESERVED,            "Reserved" },
178     { PNDCP_OPTION_CONTROL,             "Control" },
179     { PNDCP_OPTION_DEVICEINITIATIVE,    "Device Initiative" },
180     /*0x07 - 0x7f reserved */
181     /*0x80 - 0xfe manufacturer specific */
182     { PNDCP_OPTION_MANUF_X80,           "Manufacturer specific" },
183     { PNDCP_OPTION_MANUF_X81,           "Manufacturer specific" },
184     { PNDCP_OPTION_MANUF_X82,           "Manufacturer specific" },
185     { PNDCP_OPTION_MANUF_X83,           "Manufacturer specific" },
186     { PNDCP_OPTION_MANUF_X84,           "Manufacturer specific" },
187     { PNDCP_OPTION_MANUF_X85,           "Manufacturer specific" },
188     { PNDCP_OPTION_MANUF_X86,           "Manufacturer specific" },
189     { PNDCP_OPTION_ALLSELECTOR,         "All Selector" },
190     { 0, NULL }
191 };
192
193 #define PNDCP_SUBOPTION_IP_MAC  0x01
194 #define PNDCP_SUBOPTION_IP_IP   0x02
195
196 static const value_string pn_dcp_suboption_ip[] = {
197     { 0x00, "Reserved" },
198     { PNDCP_SUBOPTION_IP_MAC,   "MAC address" },
199     { PNDCP_SUBOPTION_IP_IP,    "IP parameter" },
200     /*0x03 - 0xff reserved */
201     { 0, NULL }
202 };
203
204 static const value_string pn_dcp_suboption_ip_block_info[] = {
205     { 0x0000, "IP not set" },
206     { 0x0001, "IP set" },
207     { 0x0002, "IP set by DHCP" },
208     { 0x0080, "IP not set (address conflict detected)" },
209     { 0x0081, "IP set (address conflict detected)" },
210     { 0x0082, "IP set by DHCP (address conflict detected)" },
211     /*0x0003 - 0xffff reserved */
212     { 0, NULL }
213 };
214
215 #define PNDCP_SUBOPTION_DEVICE_MANUF            0x01
216 #define PNDCP_SUBOPTION_DEVICE_NAMEOFSTATION    0x02
217 #define PNDCP_SUBOPTION_DEVICE_DEV_ID           0x03
218 #define PNDCP_SUBOPTION_DEVICE_DEV_ROLE         0x04
219 #define PNDCP_SUBOPTION_DEVICE_DEV_OPTIONS      0x05
220 #define PNDCP_SUBOPTION_DEVICE_ALIAS_NAME       0x06
221
222 static const value_string pn_dcp_suboption_device[] = {
223     { 0x00, "Reserved" },
224     { PNDCP_SUBOPTION_DEVICE_MANUF,         "Manufacturer specific (Type of Station)" },
225     { PNDCP_SUBOPTION_DEVICE_NAMEOFSTATION, "Name of Station" },
226     { PNDCP_SUBOPTION_DEVICE_DEV_ID,        "Device ID" },
227     { PNDCP_SUBOPTION_DEVICE_DEV_ROLE,      "Device Role" },
228     { PNDCP_SUBOPTION_DEVICE_DEV_OPTIONS,   "Device Options" },
229     { PNDCP_SUBOPTION_DEVICE_ALIAS_NAME,    "Alias Name" },
230     /*0x07 - 0xff reserved */
231     { 0, NULL }
232 };
233
234 #define PNDCP_SUBOPTION_DHCP_CLIENT_ID  61
235
236 static const value_string pn_dcp_suboption_dhcp[] = {
237     {  12, "Host name" },
238     {  43, "Vendor specific" },
239     {  54, "Server identifier" },
240     {  55, "Parameter request list" },
241     {  60, "Class identifier" },
242     {  PNDCP_SUBOPTION_DHCP_CLIENT_ID, "DHCP client identifier" },
243     {  81, "FQDN, Fully Qualified Domain Name" },
244     {  97, "UUID/GUID-based Client" },
245     { 255, "Control DHCP for address resolution" },
246     /*all others reserved */
247     { 0, NULL }
248 };
249
250 #define PNDCP_SUBOPTION_CONTROL_START_TRANS 0x01
251 #define PNDCP_SUBOPTION_CONTROL_END_TRANS   0x02
252 #define PNDCP_SUBOPTION_CONTROL_SIGNAL      0x03
253 #define PNDCP_SUBOPTION_CONTROL_RESPONSE    0x04
254 #define PNDCP_SUBOPTION_CONTROL_FACT_RESET  0x05
255
256 static const value_string pn_dcp_suboption_control[] = {
257     { 0x00, "Reserved" },
258     { PNDCP_SUBOPTION_CONTROL_START_TRANS, "Start Transaction" },
259     { PNDCP_SUBOPTION_CONTROL_END_TRANS, "End Transaction" },
260     { PNDCP_SUBOPTION_CONTROL_SIGNAL, "Signal" },
261     { PNDCP_SUBOPTION_CONTROL_RESPONSE, "Response" },
262         { PNDCP_SUBOPTION_CONTROL_FACT_RESET, "Reset Factory Settings" },
263     /*0x05 - 0xff reserved */
264     { 0, NULL }
265 };
266
267 #define PNDCP_SUBOPTION_DEVICEINITIATIVE 0x01
268
269 static const value_string pn_dcp_suboption_deviceinitiative[] = {
270     { 0x00, "Reserved" },
271     { PNDCP_SUBOPTION_DEVICEINITIATIVE, "Device Initiative" },
272     /*0x00 - 0xff reserved */
273     { 0, NULL }
274 };
275
276 static const value_string pn_dcp_deviceinitiative_value[] = {
277     { 0x00, "Device does not issue a DCP-Hello-ReqPDU after power on" },
278     { 0x01, "Device does issue a DCP-Hello-ReqPDU after power on" },
279     /*0x02 - 0xff reserved */
280     { 0, NULL }
281 };
282
283 static const value_string pn_dcp_suboption_all[] = {
284     { 0xff, "ALL Selector" },
285     /* all other reserved */
286     { 0, NULL }
287 };
288
289 static const value_string pn_dcp_suboption_manuf[] = {
290     /* none known */
291     { 0, NULL }
292 };
293
294
295
296
297
298 /* dissect the option field */
299 static int
300 dissect_PNDCP_Option(tvbuff_t *tvb, int offset, packet_info *pinfo, 
301                              proto_tree *tree, proto_item *block_item, int hfindex, gboolean append_col)
302 {
303     guint8 option;
304     guint8 suboption;
305     const value_string *val_str;
306
307     offset = dissect_pn_uint8 (tvb, offset, pinfo, tree, hfindex, &option);
308     switch(option) {
309     case(PNDCP_OPTION_IP):
310         offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip, &suboption);
311         val_str = pn_dcp_suboption_ip;
312         break;
313     case(PNDCP_OPTION_DEVICE):
314         offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device, &suboption);
315         val_str = pn_dcp_suboption_device;
316         break;
317     case(PNDCP_OPTION_DHCP):
318         offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_dhcp, &suboption);
319         val_str = pn_dcp_suboption_dhcp;
320         break;
321     case(PNDCP_OPTION_CONTROL):
322         offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_control, &suboption);
323         val_str = pn_dcp_suboption_control;
324         break;
325     case(PNDCP_OPTION_DEVICEINITIATIVE):
326         offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_deviceinitiative, &suboption);
327         val_str = pn_dcp_suboption_deviceinitiative;
328         break;
329     case(PNDCP_OPTION_ALLSELECTOR):
330         offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_all, &suboption);
331         val_str = pn_dcp_suboption_all;
332         break;
333     default:
334         offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_manuf, &suboption);
335         val_str = pn_dcp_suboption_manuf;
336     }
337
338     proto_item_append_text(block_item, ", Status from %s - %s", 
339         val_to_str(option, pn_dcp_option, "Unknown"), val_to_str(suboption, val_str, "Unknown"));
340
341     if(append_col) {
342         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", val_to_str(suboption, val_str, "Unknown"));
343     }
344
345     return offset;
346 }
347
348
349 /* dissect the "IP" suboption */
350 static int
351 dissect_PNDCP_Suboption_IP(tvbuff_t *tvb, int offset, packet_info *pinfo, 
352                             proto_tree *tree, proto_item *block_item, proto_item *dcp_item,
353                             guint8 service_id, gboolean is_response)
354 {
355     guint8 suboption;
356     guint16 block_length;
357     guint16 block_info;
358     guint16 block_qualifier;
359     guint32 ip;
360     proto_item *item = NULL;
361
362
363     /* SuboptionIPParameter */
364     offset = dissect_pn_uint8 (tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip, &suboption);
365     /* DCPBlockLength */
366     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);
367
368     switch(suboption) {
369     case(PNDCP_SUBOPTION_IP_MAC):
370         /* MACAddressValue? */
371         pn_append_info(pinfo, dcp_item, ", MAC");
372         proto_item_append_text(block_item, "IP/MAC");
373
374         offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, block_length); 
375         break;
376     case(PNDCP_SUBOPTION_IP_IP):
377         pn_append_info(pinfo, dcp_item, ", IP");
378         proto_item_append_text(block_item, "IP/IP");
379
380         /* BlockInfo? */
381         if( ((service_id == PNDCP_SERVICE_ID_IDENTIFY) &&  is_response) ||
382             ((service_id == PNDCP_SERVICE_ID_HELLO)    && !is_response) ||
383             ((service_id == PNDCP_SERVICE_ID_GET)      &&  is_response)) {
384             block_info = tvb_get_ntohs (tvb, offset);
385             if (tree) {
386                 item = proto_tree_add_uint(tree, hf_pn_dcp_suboption_ip_block_info, tvb, offset, 2, block_info);
387             }
388             offset += 2;
389             proto_item_append_text(block_item, ", BlockInfo: %s", val_to_str(block_info, pn_dcp_suboption_ip_block_info, "Undecoded"));
390             block_length -= 2;
391             if(block_info & 0x80) {
392                 expert_add_info_format(pinfo, item, PI_RESPONSE_CODE, PI_NOTE, "IP address conflict detected!");
393             }
394         }
395
396         /* BlockQualifier? */
397         if( (service_id == PNDCP_SERVICE_ID_SET) && !is_response) {
398             offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_qualifier, &block_qualifier);
399             proto_item_append_text(block_item, ", BlockQualifier: %s", val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
400             block_length -= 2;
401         }
402
403         /* IPParameterValue ... */
404
405         /* IPAddress */
406         offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_ip, &ip);
407         proto_item_append_text(block_item, ", IP: %s", ip_to_str((guint8*)&ip));
408
409         /* Subnetmask */
410         offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_subnetmask, &ip);
411         proto_item_append_text(block_item, ", Subnet: %s", ip_to_str((guint8*)&ip));
412
413         /* StandardGateway */
414         offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_standard_gateway, &ip);
415         proto_item_append_text(block_item, ", Gateway: %s", ip_to_str((guint8*)&ip));
416         break;
417     default:
418         offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, block_length); 
419     }
420
421     return offset;
422 }
423
424
425 /* dissect the "device" suboption */
426 static int
427 dissect_PNDCP_Suboption_Device(tvbuff_t *tvb, int offset, packet_info *pinfo, 
428                                proto_tree *tree, proto_item *block_item, proto_item *dcp_item, 
429                                guint8 service_id, gboolean is_response)
430 {
431     guint8 suboption;
432     guint16 block_length;
433     gchar *info_str;
434     guint8 device_role;
435     guint16 vendor_id;
436     guint16 device_id;
437     char *typeofstation;
438     char *nameofstation;
439     char *aliasname;
440     guint16 block_info;
441     guint16 block_qualifier;
442     gboolean have_block_info=FALSE;
443     gboolean have_block_qualifier=FALSE;
444
445
446     /* SuboptionDevice... */
447     offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device, &suboption);
448     /* DCPBlockLength */
449     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);
450
451     /* BlockInfo? */
452     if( ((service_id == PNDCP_SERVICE_ID_IDENTIFY) &&  is_response) ||
453         ((service_id == PNDCP_SERVICE_ID_HELLO)    && !is_response) ||
454         ((service_id == PNDCP_SERVICE_ID_GET)      &&  is_response)) {
455         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_info, &block_info);
456         have_block_info=TRUE;
457         block_length -= 2;
458     }
459
460     /* BlockQualifier? */
461     if( (service_id == PNDCP_SERVICE_ID_SET) && !is_response) {
462         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_qualifier, &block_qualifier);
463         have_block_qualifier=TRUE;
464         block_length -= 2;
465     }
466
467     switch(suboption) {
468     case(PNDCP_SUBOPTION_DEVICE_MANUF):
469         typeofstation = ep_alloc(block_length+1);
470         tvb_memcpy(tvb, (guint8 *) typeofstation, offset, block_length);
471         typeofstation[block_length] = '\0';
472         proto_tree_add_string (tree, hf_pn_dcp_suboption_device_typeofstation, tvb, offset, block_length, typeofstation);
473         pn_append_info(pinfo, dcp_item, ", TypeOfStation");
474         proto_item_append_text(block_item, "Device/Manufacturer specific");
475         if(have_block_qualifier)
476             proto_item_append_text(block_item, ", BlockQualifier: %s", val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
477         if(have_block_info)
478             proto_item_append_text(block_item, ", BlockInfo: %s", val_to_str(block_info, pn_dcp_block_info, "Unknown"));
479         proto_item_append_text(block_item, ", TypeOfStation: \"%s\"", typeofstation);
480         offset += block_length;
481         break;
482     case(PNDCP_SUBOPTION_DEVICE_NAMEOFSTATION):
483         nameofstation = ep_alloc(block_length+1);
484         tvb_memcpy(tvb, (guint8 *) nameofstation, offset, block_length);
485         nameofstation[block_length] = '\0';
486         proto_tree_add_string (tree, hf_pn_dcp_suboption_device_nameofstation, tvb, offset, block_length, nameofstation);
487         pn_append_info(pinfo, dcp_item, ep_strdup_printf(", NameOfStation:\"%s\"", nameofstation));
488         proto_item_append_text(block_item, "Device/NameOfStation");
489         if(have_block_qualifier)
490             proto_item_append_text(block_item, ", BlockQualifier: %s", val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
491         if(have_block_info)
492             proto_item_append_text(block_item, ", BlockInfo: %s", val_to_str(block_info, pn_dcp_block_info, "Unknown"));
493         proto_item_append_text(block_item, ", \"%s\"", nameofstation);
494         offset += block_length;
495         break;
496     case(PNDCP_SUBOPTION_DEVICE_DEV_ID):
497         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_vendor_id, &vendor_id);
498         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device_id, &device_id);
499         pn_append_info(pinfo, dcp_item, ", Dev-ID");
500         proto_item_append_text(block_item, "Device/Device ID");
501         if(have_block_qualifier)
502             proto_item_append_text(block_item, ", BlockQualifier: %s", val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
503         if(have_block_info)
504             proto_item_append_text(block_item, ", BlockInfo: %s", val_to_str(block_info, pn_dcp_block_info, "Unknown"));
505         proto_item_append_text(block_item, ", VendorID: 0x%04x / DeviceID: 0x%04x", vendor_id, device_id);
506         break;
507     case(PNDCP_SUBOPTION_DEVICE_DEV_ROLE):
508         offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device_role, &device_role);
509         offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_reserved8, NULL);
510         pn_append_info(pinfo, dcp_item, ", Dev-Role");
511         proto_item_append_text(block_item, "Device/Device Role");
512         if(have_block_qualifier)
513             proto_item_append_text(block_item, ", BlockQualifier: %s", val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
514         if(have_block_info)
515             proto_item_append_text(block_item, ", BlockInfo: %s", val_to_str(block_info, pn_dcp_block_info, "Unknown"));
516         if(device_role & 0x01)
517             proto_item_append_text(block_item, ", IO-Device");
518         if(device_role & 0x02)
519             proto_item_append_text(block_item, ", IO-Controller");
520         if(device_role & 0x04)
521             proto_item_append_text(block_item, ", IO-Multidevice");
522         if(device_role & 0x08)
523             proto_item_append_text(block_item, ", PN-Supervisor");
524         break;
525     case(PNDCP_SUBOPTION_DEVICE_DEV_OPTIONS):
526         info_str = ep_strdup_printf(", Dev-Options(%u)", block_length/2);
527         pn_append_info(pinfo, dcp_item, info_str);
528         proto_item_append_text(block_item, "Device/Device Options");
529         if(have_block_qualifier)
530             proto_item_append_text(block_item, ", BlockQualifier: %s", val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
531         if(have_block_info)
532             proto_item_append_text(block_item, ", BlockInfo: %s", val_to_str(block_info, pn_dcp_block_info, "Unknown"));
533         proto_item_append_text(block_item, ", %u options", block_length/2);
534         for( ; block_length != 0; block_length -= 2) {
535             offset = dissect_PNDCP_Option(tvb, offset, pinfo, tree, NULL /*block_item*/, hf_pn_dcp_option, 
536                 FALSE /* append_col */);
537         }
538         break;
539     case(PNDCP_SUBOPTION_DEVICE_ALIAS_NAME):
540         aliasname = ep_alloc(block_length+1);
541         tvb_memcpy(tvb, (guint8 *) aliasname, offset, block_length);
542         aliasname[block_length] = '\0';
543         proto_tree_add_string (tree, hf_pn_dcp_suboption_device_aliasname, tvb, offset, block_length, aliasname);
544         pn_append_info(pinfo, dcp_item, ep_strdup_printf(", AliasName:\"%s\"", aliasname));
545         proto_item_append_text(block_item, "Device/AliasName");
546         if(have_block_qualifier)
547             proto_item_append_text(block_item, ", BlockQualifier: %s", val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
548         if(have_block_info)
549             proto_item_append_text(block_item, ", BlockInfo: %s", val_to_str(block_info, pn_dcp_block_info, "Unknown"));
550         proto_item_append_text(block_item, ", \"%s\"", aliasname);
551         offset += block_length;
552         break;
553     default:
554         offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, block_length); 
555     }
556
557     return offset;
558 }
559
560
561 /* dissect the "DHCP" suboption */
562 static int
563 dissect_PNDCP_Suboption_DHCP(tvbuff_t *tvb, int offset, packet_info *pinfo, 
564                                 proto_tree *tree, proto_item *block_item, proto_item *dcp_item, 
565                                 guint8 service_id _U_, gboolean is_response _U_)
566 {
567     guint8 suboption;
568     guint16 block_length;
569     guint16 block_info;
570     guint16 block_qualifier;
571     gboolean have_block_info=FALSE;
572     gboolean have_block_qualifier=FALSE;
573
574
575     offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_dhcp, &suboption);
576     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);
577
578     /* BlockInfo? */
579     if( ((service_id == PNDCP_SERVICE_ID_IDENTIFY) &&  is_response) ||
580         ((service_id == PNDCP_SERVICE_ID_HELLO)    && !is_response) ||
581         ((service_id == PNDCP_SERVICE_ID_GET)      &&  is_response)) {
582         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_info, &block_info);
583         have_block_info=TRUE;
584         block_length -= 2;
585     }
586
587     /* BlockQualifier? */
588     if( (service_id == PNDCP_SERVICE_ID_SET) && !is_response) {
589         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_qualifier, &block_qualifier);
590         have_block_qualifier=TRUE;
591         block_length -= 2;
592     }
593
594     switch(suboption) {
595     case(PNDCP_SUBOPTION_DHCP_CLIENT_ID):
596         pn_append_info(pinfo, dcp_item, ", DHCP client identifier");
597         proto_item_append_text(block_item, "DHCP/Client-ID");
598         if(have_block_qualifier)
599             proto_item_append_text(block_item, ", BlockQualifier: %s", val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
600         if(have_block_info)
601             proto_item_append_text(block_item, ", BlockInfo: %s", val_to_str(block_info, pn_dcp_block_info, "Unknown"));
602         proto_tree_add_item(tree, hf_pn_dcp_suboption_dhcp_device_id, tvb, offset, block_length, FALSE);
603         offset += block_length;
604         break;
605     default:
606         offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, block_length); 
607     }
608
609     return offset;
610 }
611
612
613 /* dissect the "control" suboption */
614 static int
615 dissect_PNDCP_Suboption_Control(tvbuff_t *tvb, int offset, packet_info *pinfo, 
616                                 proto_tree *tree, proto_item *block_item, proto_item *dcp_item, 
617                                 guint8 service_id _U_, gboolean is_response _U_)
618 {
619     guint8 suboption;
620     guint16 block_length;
621     guint16 block_qualifier;
622     gchar *info_str;
623     guint8 block_error;
624     proto_item *item = NULL;
625
626
627     offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_control, &suboption);
628     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);
629
630     switch(suboption) {
631     case(PNDCP_SUBOPTION_CONTROL_START_TRANS):
632         pn_append_info(pinfo, dcp_item, ", Start-Trans");
633         proto_item_append_text(block_item, "Control/Start-Transaction");
634         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_qualifier, &block_qualifier);
635         break;
636     case(PNDCP_SUBOPTION_CONTROL_END_TRANS):
637         pn_append_info(pinfo, dcp_item, ", End-Trans");
638         proto_item_append_text(block_item, "Control/End-Transaction");
639         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_qualifier, &block_qualifier);
640         break;
641     case(PNDCP_SUBOPTION_CONTROL_SIGNAL):
642         pn_append_info(pinfo, dcp_item, ", Signal");
643         proto_item_append_text(block_item, "Control/Signal");
644         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_qualifier, &block_qualifier);
645         block_length -= 2;
646
647         offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, block_length); 
648         break;
649     case(PNDCP_SUBOPTION_CONTROL_RESPONSE):
650         proto_item_append_text(block_item, "Control/Response");
651         offset = dissect_PNDCP_Option(tvb, offset, pinfo, tree, block_item, hf_pn_dcp_suboption_control_response, 
652             FALSE /* append_col */);
653         block_error = tvb_get_guint8 (tvb, offset);
654         if (tree) {
655             item = proto_tree_add_uint(tree, hf_pn_dcp_block_error, tvb, offset, 1, block_error);
656         }
657         offset += 1;
658         if(block_error != 0) {
659             expert_add_info_format(pinfo, item, PI_RESPONSE_CODE, PI_CHAT,
660                 "%s", val_to_str(block_error, pn_dcp_block_error, "Unknown"));
661         }
662         info_str = ep_strdup_printf(", Response(%s)", val_to_str(block_error, pn_dcp_block_error, "Unknown"));
663         pn_append_info(pinfo, dcp_item, info_str);
664         proto_item_append_text(block_item, ", BlockError: %s", val_to_str(block_error, pn_dcp_block_error, "Unknown"));
665
666         break;
667     case(PNDCP_SUBOPTION_CONTROL_FACT_RESET):
668         pn_append_info(pinfo, dcp_item, ", Reset FactorySettings");
669         proto_item_append_text(block_item, "Control/Reset FactorySettings");
670         offset       += 2;
671         block_length -= 2;
672         break;
673     default:
674         offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, block_length); 
675     }
676
677     return offset;
678 }
679
680
681 /* dissect the "deviceinitaitve" suboption */
682 static int
683 dissect_PNDCP_Suboption_DeviceInitiative(tvbuff_t *tvb, int offset, packet_info *pinfo, 
684                             proto_tree *tree, proto_item *block_item, proto_item *dcp_item,
685                             guint8 service_id, gboolean is_response)
686 {
687     guint8 suboption;
688     guint16 block_length;
689     guint16 block_info;
690     guint16 block_qualifier;
691     guint16 value;
692
693
694     offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_deviceinitiative, &suboption);
695     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);
696
697     pn_append_info(pinfo, dcp_item, ", DeviceInitiative");
698     proto_item_append_text(block_item, "DeviceInitiative/DeviceInitiative");
699
700     /* BlockInfo? */
701     if( ((service_id == PNDCP_SERVICE_ID_IDENTIFY) &&  is_response) ||
702         ((service_id == PNDCP_SERVICE_ID_HELLO)    && !is_response) ||
703         ((service_id == PNDCP_SERVICE_ID_GET)      &&  is_response)) {
704         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_info, &block_info);
705         proto_item_append_text(block_item, ", BlockInfo: %s", val_to_str(block_info, pn_dcp_block_info, "Unknown"));
706         block_length -= 2;
707     }
708
709     /* BlockQualifier? */
710     if( (service_id == PNDCP_SERVICE_ID_SET) && !is_response) {
711         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_qualifier, &block_qualifier);
712         proto_item_append_text(block_item, ", BlockQualifier: %s", val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
713         block_length -= 2;
714     }
715
716     /* DeviceInitiativeValue */
717     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_deviceinitiative_value, &value);
718
719     return offset;
720 }
721
722
723 /* dissect the "all" suboption */
724 static int
725 dissect_PNDCP_Suboption_All(tvbuff_t *tvb, int offset, packet_info *pinfo, 
726                             proto_tree *tree, proto_item *block_item, proto_item *dcp_item,
727                             guint8 service_id _U_, gboolean is_response _U_)
728 {
729     guint8 suboption;
730     guint16 block_length;
731
732
733     offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_all, &suboption);
734     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);
735
736     switch(suboption) {
737     case(255):    /* All */
738         pn_append_info(pinfo, dcp_item, ", All");
739         proto_item_append_text(block_item, "All/All");
740         break;
741     default:
742         offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, block_length); 
743     }
744
745     return offset;
746 }
747
748
749 /* dissect the "manufacturer" suboption */
750 static int
751 dissect_PNDCP_Suboption_Manuf(tvbuff_t *tvb, int offset, packet_info *pinfo, 
752                             proto_tree *tree, proto_item *block_item, proto_item *dcp_item,
753                             guint8 service_id _U_, gboolean is_response _U_)
754 {
755     guint8 suboption;
756     guint16 block_length;
757
758
759     offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_manuf, &suboption);
760     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);
761
762     switch(suboption) {
763     default:
764         pn_append_info(pinfo, dcp_item, ", Manufacturer Specific");
765         proto_item_append_text(block_item, "Manufacturer Specific");
766         offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, block_length); 
767     }
768
769     return offset;
770 }
771
772
773 /* dissect one DCP block */
774 static int
775 dissect_PNDCP_Block(tvbuff_t *tvb, int offset, packet_info *pinfo, 
776                     proto_tree *tree, proto_item *dcp_item, 
777                     guint8 service_id, gboolean is_response)
778 {
779     guint8 option;
780     proto_item *block_item;
781     proto_tree *block_tree;
782     int ori_offset = offset;
783
784     /* subtree for block */
785     block_item = proto_tree_add_none_format(tree, hf_pn_dcp_block, 
786         tvb, offset, 0, "Block: ");
787     block_tree = proto_item_add_subtree(block_item, ett_pn_dcp_block);
788
789
790     offset = dissect_pn_uint8(tvb, offset, pinfo, block_tree, hf_pn_dcp_option, &option);
791
792     switch(option) {
793     case(PNDCP_OPTION_IP):
794         offset = dissect_PNDCP_Suboption_IP(tvb, offset, pinfo, block_tree, block_item, dcp_item, service_id, is_response);
795         break;
796     case(PNDCP_OPTION_DEVICE):
797         offset = dissect_PNDCP_Suboption_Device(tvb, offset, pinfo, block_tree, block_item, dcp_item, service_id, is_response);
798         break;
799     case(PNDCP_OPTION_DHCP):
800         offset = dissect_PNDCP_Suboption_DHCP(tvb, offset, pinfo, block_tree, block_item, dcp_item, service_id, is_response);
801         break;
802     case(PNDCP_OPTION_CONTROL):
803         offset = dissect_PNDCP_Suboption_Control(tvb, offset, pinfo, block_tree, block_item, dcp_item, service_id, is_response);
804         break;
805     case(PNDCP_OPTION_DEVICEINITIATIVE):
806         offset = dissect_PNDCP_Suboption_DeviceInitiative(tvb, offset, pinfo, block_tree, block_item, dcp_item, service_id, is_response);
807         break;
808     case(PNDCP_OPTION_ALLSELECTOR):
809         offset = dissect_PNDCP_Suboption_All(tvb, offset, pinfo, block_tree, block_item, dcp_item, service_id, is_response);
810         break;
811     case(PNDCP_OPTION_MANUF_X80):
812     case(PNDCP_OPTION_MANUF_X81):
813     default:
814         offset = dissect_PNDCP_Suboption_Manuf(tvb, offset, pinfo, block_tree, block_item, dcp_item, service_id, is_response);
815     }
816
817     proto_item_set_len(block_item, offset-ori_offset);
818
819     if((offset-ori_offset) & 1) {
820         /* we have an odd number of bytes in this block, add a padding byte */
821         offset = dissect_pn_padding(tvb, offset, pinfo, tree, 1);
822     }
823
824     return offset;
825 }
826
827
828 /* dissect a whole DCP PDU */
829 static void
830 dissect_PNDCP_PDU(tvbuff_t *tvb, 
831     packet_info *pinfo, proto_tree *tree, proto_item *dcp_item)
832 {
833     guint8 service_id;
834     guint8 service_type;
835     guint32 xid;
836     guint16 response_delay;
837     guint16 data_length;
838     int offset = 0;
839     gchar *xid_str;
840     gboolean is_response = FALSE;
841
842
843     offset = dissect_pn_uint8 (tvb, offset, pinfo, tree, hf_pn_dcp_service_id, &service_id);
844     offset = dissect_pn_uint8 (tvb, offset, pinfo, tree, hf_pn_dcp_service_type, &service_type);
845     offset = dissect_pn_uint32(tvb, offset, pinfo, tree, hf_pn_dcp_xid, &xid);
846     if(service_id == PNDCP_SERVICE_ID_IDENTIFY && service_type == PNDCP_SERVICE_TYPE_REQUEST) {
847         /* multicast header */
848         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_response_delay, &response_delay);
849     } else {
850         /* unicast header */
851         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_reserved16, NULL);
852     }
853     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_data_length, &data_length);
854
855     switch(service_id) {
856     case(PNDCP_SERVICE_ID_GET):
857         pn_append_info(pinfo, dcp_item, "Get");
858         break;
859     case(PNDCP_SERVICE_ID_SET):
860         pn_append_info(pinfo, dcp_item, "Set");
861         break;
862     case(PNDCP_SERVICE_ID_IDENTIFY):
863         pn_append_info(pinfo, dcp_item, "Ident");
864         break;
865     case(PNDCP_SERVICE_ID_HELLO):
866         pn_append_info(pinfo, dcp_item, "Hello");
867         break;
868     default:
869         offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, tvb_length_remaining(tvb, offset)); 
870         return;
871     }
872
873     switch(service_type) {
874     case(PNDCP_SERVICE_TYPE_REQUEST):
875         pn_append_info(pinfo, dcp_item, " Req");
876         break;
877     case(PNDCP_SERVICE_TYPE_RESPONSE_SUCCESS):
878         pn_append_info(pinfo, dcp_item, " Ok ");
879         is_response = TRUE;
880         break;
881     case(PNDCP_SERVICE_TYPE_RESPONSE_UNSUPPORTED):
882         pn_append_info(pinfo, dcp_item, " unsupported");
883         is_response = TRUE;
884         break;
885     default:
886         offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, tvb_length_remaining(tvb, offset)); 
887         return;
888     }
889
890     xid_str = ep_strdup_printf(", Xid:0x%x", xid);
891     pn_append_info(pinfo, dcp_item, xid_str);
892
893     /* dissect a number of blocks (depending on the remaining length) */
894     while(data_length) {
895         int ori_offset = offset;
896
897         if(service_id == PNDCP_SERVICE_ID_GET && service_type == PNDCP_SERVICE_TYPE_REQUEST) {
898             /* Selectors */
899             offset = dissect_PNDCP_Option(tvb, offset, pinfo, 
900                                  tree, dcp_item, hf_pn_dcp_option, TRUE /* append_col */);
901         } else {
902             offset = dissect_PNDCP_Block(tvb, offset, pinfo, tree, dcp_item, service_id, is_response);
903         }
904         /* prevent an infinite loop */
905         if(offset <= ori_offset || data_length < (offset - ori_offset)) {
906             THROW(ReportedBoundsError);
907         }
908         data_length -= (offset - ori_offset);
909     }
910 }
911
912
913 /* possibly dissect a PN-RT packet (frame ID must be in the appropriate range) */
914 static gboolean
915 dissect_PNDCP_Data_heur(tvbuff_t *tvb, 
916     packet_info *pinfo, proto_tree *tree)
917 {
918     guint16 u16FrameID;
919     proto_item *item = NULL;
920     proto_tree *dcp_tree = NULL;
921
922
923     /* the tvb will NOT contain the frame_id here, so get it from our private data! */
924     u16FrameID = GPOINTER_TO_UINT(pinfo->private_data);
925
926     /* frame id must be in valid range (acyclic Real-Time, DCP) */
927     if (u16FrameID < FRAME_ID_DCP_HELLO || u16FrameID > FRAME_ID_DCP_IDENT_RES) {
928         /* we are not interested in this packet */
929         return FALSE;
930     }
931
932     col_set_str(pinfo->cinfo, COL_PROTOCOL, "PN-DCP");
933     col_clear(pinfo->cinfo, COL_INFO);
934
935     /* subtree for DCP */
936     item = proto_tree_add_protocol_format(tree, proto_pn_dcp, tvb, 0, tvb_get_ntohs(tvb, 8) + 10,
937                 "PROFINET DCP, ");
938     dcp_tree = proto_item_add_subtree(item, ett_pn_dcp);
939
940     /* dissect this PDU */
941     dissect_PNDCP_PDU(tvb, pinfo, dcp_tree, item);
942
943     return TRUE;
944 }
945
946
947 void
948 proto_register_pn_dcp (void)
949 {
950     static hf_register_info hf[] = {
951     { &hf_pn_dcp,
952         { "PROFINET DCP", "pn_dcp", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
953     { &hf_pn_dcp_service_id,
954         { "ServiceID", "pn_dcp.service_id", FT_UINT8, BASE_DEC, VALS(pn_dcp_service_id), 0x0, NULL, HFILL }},
955     { &hf_pn_dcp_service_type,
956         { "ServiceType", "pn_dcp.service_type", FT_UINT8, BASE_DEC, VALS(pn_dcp_service_type), 0x0, NULL, HFILL }},
957     { &hf_pn_dcp_xid,
958         { "Xid", "pn_dcp.xid", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
959     { &hf_pn_dcp_reserved8,
960         { "Reserved", "pn_dcp.reserved8", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
961     { &hf_pn_dcp_reserved16,
962         { "Reserved", "pn_dcp.reserved16", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
963     { &hf_pn_dcp_response_delay,
964         { "ResponseDelay", "pn_dcp.response_delay", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
965     { &hf_pn_dcp_data_length,
966         { "DCPDataLength", "pn_dcp.data_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
967     { &hf_pn_dcp_block_length,
968         { "DCPBlockLength", "pn_dcp.block_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
969     { &hf_pn_dcp_option,
970         { "Option", "pn_dcp.option", FT_UINT8, BASE_DEC, VALS(pn_dcp_option), 0x0, NULL, HFILL }},
971     { &hf_pn_dcp_suboption,
972         { "Suboption", "pn_dcp.suboption", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
973     { &hf_pn_dcp_block_error,
974         { "BlockError", "pn_dcp.block_error", FT_UINT8, BASE_DEC, VALS(pn_dcp_block_error), 0x0, NULL, HFILL }},
975     { &hf_pn_dcp_block,
976         { "Block", "pn_dcp.block", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
977     { &hf_pn_dcp_block_info,
978         { "BlockInfo", "pn_dcp.block_info", FT_UINT16, BASE_DEC, VALS(pn_dcp_block_info), 0x0, NULL, HFILL }},
979     { &hf_pn_dcp_block_qualifier,
980         { "BlockQualifier", "pn_dcp.block_qualifier", FT_UINT16, BASE_DEC, VALS(pn_dcp_block_qualifier), 0x0, NULL, HFILL }},
981     { &hf_pn_dcp_suboption_ip,
982         { "Suboption", "pn_dcp.suboption_ip", FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_ip), 0x0, NULL, HFILL }},
983     { &hf_pn_dcp_suboption_ip_block_info,
984         { "BlockInfo", "pn_dcp.suboption_ip_block_info", FT_UINT16, BASE_DEC, VALS(pn_dcp_suboption_ip_block_info), 0x0, NULL, HFILL }},
985     { &hf_pn_dcp_suboption_ip_ip,
986         { "IPaddress", "pn_dcp.subobtion_ip_ip", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
987     { &hf_pn_dcp_suboption_ip_subnetmask,
988         { "Subnetmask", "pn_dcp.subobtion_ip_subnetmask", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
989     { &hf_pn_dcp_suboption_ip_standard_gateway,
990         { "StandardGateway", "pn_dcp.suboption_ip_standard_gateway", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
991
992     { &hf_pn_dcp_suboption_device,
993         { "Suboption", "pn_dcp.suboption_device", FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_device), 0x0, NULL, HFILL }},
994     { &hf_pn_dcp_suboption_device_typeofstation,
995         { "TypeOfStation", "pn_dcp.suboption_device_typeofstation", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
996     { &hf_pn_dcp_suboption_device_nameofstation,
997         { "NameOfStation", "pn_dcp.suboption_device_nameofstation", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
998     { &hf_pn_dcp_suboption_vendor_id,
999         { "VendorID", "pn_dcp.suboption_vendor_id", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1000     { &hf_pn_dcp_suboption_device_id,
1001         { "DeviceID", "pn_dcp.suboption_device_id", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1002     { &hf_pn_dcp_suboption_device_role,
1003         { "DeviceRoleDetails", "pn_dcp.suboption_device_role", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1004     { &hf_pn_dcp_suboption_device_aliasname,
1005         { "AliasName", "pn_dcp.suboption_device_aliasname", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1006
1007     { &hf_pn_dcp_suboption_dhcp,
1008         { "Suboption", "pn_dcp.suboption_dhcp", FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_dhcp), 0x0, NULL, HFILL }},
1009     { &hf_pn_dcp_suboption_dhcp_device_id,
1010         { "Device ID", "pn_dcp.suboption_dhcp_device_id", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1011
1012     { &hf_pn_dcp_suboption_control,
1013         { "Suboption", "pn_dcp.suboption_control", FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_control), 0x0, NULL, HFILL }},
1014     { &hf_pn_dcp_suboption_control_response,
1015         { "Response", "pn_dcp.suboption_control_response", FT_UINT8, BASE_DEC, VALS(pn_dcp_option), 0x0, NULL, HFILL }},
1016
1017     { &hf_pn_dcp_suboption_deviceinitiative,
1018         { "Suboption", "pn_dcp.suboption_deviceinitiative", FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_deviceinitiative), 0x0, NULL, HFILL }},
1019     { &hf_pn_dcp_deviceinitiative_value,
1020         { "DeviceInitiativeValue", "pn_dcp.deviceinitiative_value", FT_UINT16, BASE_DEC, VALS(pn_dcp_deviceinitiative_value), 0x0, NULL, HFILL }},
1021
1022     { &hf_pn_dcp_suboption_all,
1023         { "Suboption", "pn_dcp.suboption_all", FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_all), 0x0, NULL, HFILL }},
1024
1025     { &hf_pn_dcp_suboption_manuf,
1026         { "Suboption", "pn_dcp.suboption_manuf", FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_manuf), 0x0, NULL, HFILL }},
1027     };
1028
1029     static gint *ett[] = {
1030         &ett_pn_dcp,
1031         &ett_pn_dcp_block
1032     };
1033     proto_pn_dcp = proto_register_protocol ("PROFINET DCP", "PN-DCP", "pn_dcp");
1034     proto_register_field_array (proto_pn_dcp, hf, array_length (hf));
1035     proto_register_subtree_array (ett, array_length (ett));
1036 }
1037
1038 void
1039 proto_reg_handoff_pn_dcp (void)
1040 {
1041     /* register ourself as an heuristic pn-rt payload dissector */
1042     heur_dissector_add("pn_rt", dissect_PNDCP_Data_heur, proto_pn_dcp);
1043 }