1 /* packet-pn-dcp.c
2  * Routines for PN-DCP (PROFINET Discovery and basic Configuration Protocol)
3  * packet dissection.
4  *
5  * IEC 61158-6-10 section 4.3
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1999 Gerald Combs
10  *
11  * SPDX-License-Identifier: GPL-2.0-or-later
12  */
13 
14 /*
15  * Cyclic PNIO RTC1 Data Dissection:
16  *
17  * Added new functions to packet-pn-dcp.c. The profinet plug-in will now save
18  * the information (Stationname, -type, -id)  of "Ident OK" frames. Those
19  * informations will later be used for detailled dissection of cyclic PNIO RTC1
20  * dataframes.
21  *
22  * The declaration of the new added structures are within packet-pn.h to
23  * use the information within packet-pn-rtc-one.c
24  *
25  * Overview for cyclic PNIO RTC1 data dissection functions:
26  *   -> dissect_PNDCP_Suboption_Device (Save Stationname, -type, -id)
27  */
28 
29 
30 #include "config.h"
31 
32 #include <string.h>
33 
34 #include <glib.h>
35 
36 #include <epan/packet.h>
37 #include <epan/exceptions.h>
38 #include <epan/to_str.h>
39 #include <epan/wmem_scopes.h>
40 #include <epan/expert.h>
41 #include <epan/conversation.h>
42 
43 #include "packet-pn.h"
44 
45 
46 void proto_register_pn_dcp(void);
47 void proto_reg_handoff_pn_dcp(void);
48 
49 int proto_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_block_info = -1;
66 static int hf_pn_dcp_block_qualifier = -1;
67 static int hf_pn_dcp_blockqualifier = -1;
68 static int hf_pn_dcp_blockqualifier_r2f = -1;
69 
70 static int hf_pn_dcp_suboption_ip = -1;
71 static int hf_pn_dcp_suboption_ip_block_info = -1;
72 static int hf_pn_dcp_suboption_ip_ip = -1;
73 static int hf_pn_dcp_suboption_ip_subnetmask = -1;
74 static int hf_pn_dcp_suboption_ip_standard_gateway = -1;
75 static int hf_pn_dcp_suboption_ip_mac_address = -1;
76 
77 static int hf_pn_dcp_suboption_device = -1;
78 static int hf_pn_dcp_suboption_device_typeofstation = -1;
79 static int hf_pn_dcp_suboption_device_nameofstation = -1;
80 static int hf_pn_dcp_suboption_vendor_id = -1;
81 static int hf_pn_dcp_suboption_device_id = -1;
82 static int hf_pn_dcp_suboption_device_role = -1;
83 static int hf_pn_dcp_suboption_device_aliasname = -1;
84 static int hf_pn_dcp_suboption_device_instance_high = -1;
85 static int hf_pn_dcp_suboption_device_instance_low = -1;
86 static int hf_pn_dcp_suboption_device_oem_ven_id = -1;
87 static int hf_pn_dcp_suboption_device_oem_dev_id = -1;
88 
89 static int hf_pn_dcp_rsi_properties_value = -1;
90 static int hf_pn_dcp_rsi_properties_value_bit0 = -1;
91 static int hf_pn_dcp_rsi_properties_value_bit1 = -1;
92 static int hf_pn_dcp_rsi_properties_value_bit2 = -1;
93 static int hf_pn_dcp_rsi_properties_value_bit3 = -1;
94 static int hf_pn_dcp_rsi_properties_value_bit4 = -1;
95 static int hf_pn_dcp_rsi_properties_value_bit5 = -1;
96 static int hf_pn_dcp_rsi_properties_value_otherbits = -1;
97 
98 static int hf_pn_dcp_suboption_dhcp = -1;
99 static int hf_pn_dcp_suboption_dhcp_option_code = -1;
100 static int hf_pn_dcp_suboption_dhcp_parameter_length = -1;
101 static int hf_pn_dcp_suboption_dhcp_parameter_data = -1;
102 static int hf_pn_dcp_suboption_dhcp_arbitrary_client_id = -1;
103 static int hf_pn_dcp_suboption_dhcp_control_parameter_data = -1;
104 
105 static int hf_pn_dcp_suboption_control = -1;
106 static int hf_pn_dcp_suboption_control_option = -1;
107 static int hf_pn_dcp_suboption_control_signal_value = -1;
108 
109 static int hf_pn_dcp_suboption_deviceinitiative = -1;
110 static int hf_pn_dcp_deviceinitiative_value = -1;
111 
112 static int hf_pn_dcp_suboption_all = -1;
113 
114 static int hf_pn_dcp_suboption_manuf = -1;
115 
116 static gint ett_pn_dcp = -1;
117 static gint ett_pn_dcp_block = -1;
118 
119 static gint ett_pn_dcp_rsi_properties_value = -1;
120 
121 static expert_field ei_pn_dcp_block_parse_error = EI_INIT;
122 static expert_field ei_pn_dcp_block_error_unknown = EI_INIT;
123 static expert_field ei_pn_dcp_ip_conflict = EI_INIT;
124 
125 #define PNDCP_SERVICE_ID_GET        0x03
126 #define PNDCP_SERVICE_ID_SET        0x04
127 #define PNDCP_SERVICE_ID_IDENTIFY   0x05
128 #define PNDCP_SERVICE_ID_HELLO      0x06
129 
130 static const value_string pn_dcp_service_id[] = {
131     { 0x00,                     "reserved" },
132     { 0x01,                     "Manufacturer specific" },
133     { 0x02,                     "Manufacturer specific" },
134     { PNDCP_SERVICE_ID_GET,     "Get" },
135     { PNDCP_SERVICE_ID_SET,     "Set" },
136     { PNDCP_SERVICE_ID_IDENTIFY,"Identify" },
137     { PNDCP_SERVICE_ID_HELLO,   "Hello" },
138     /* 0x07 - 0xff reserved */
139     { 0, NULL }
140 };
141 
142 #define PNDCP_SERVICE_TYPE_REQUEST              0
143 #define PNDCP_SERVICE_TYPE_RESPONSE_SUCCESS     1
144 #define PNDCP_SERVICE_TYPE_RESPONSE_UNSUPPORTED 5
145 
146 static const value_string pn_dcp_service_type[] = {
147     { PNDCP_SERVICE_TYPE_REQUEST,               "Request" },
148     { PNDCP_SERVICE_TYPE_RESPONSE_SUCCESS,      "Response Success" },
149     { PNDCP_SERVICE_TYPE_RESPONSE_UNSUPPORTED,  "Response - Request not supported" },
150     /* all others reserved */
151     { 0, NULL }
152 };
153 
154 static const value_string pn_dcp_block_error[] = {
155     { 0x00, "Ok" },
156     { 0x01, "Option unsupp." },
157     { 0x02, "Suboption unsupp. or no DataSet avail." },
158     { 0x03, "Suboption not set" },
159     { 0x04, "Resource Error" },
160     { 0x05, "SET not possible by local reasons" },
161     { 0x06, "In operation, SET not possible" },
162     /* all others reserved */
163     { 0, NULL }
164 };
165 
166 static const range_string pn_dcp_block_info[] = {
167     { 0x0000, 0xFFFF, "Reserved" },
168     { 0, 0, NULL }
169 };
170 
171 static const value_string pn_dcp_block_qualifier[] = {
172     { 0x0000, "Use the value temporary" },
173     { 0x0001, "Save the value permanent" },
174     /*0x0002 - 0xffff reserved */
175     { 0, NULL }
176 };
177 
178 static const value_string pn_dcp_BlockQualifier[] = {
179     { 0x0002, "Reset application data" },
180     { 0x0003, "Reset application data" },
181     { 0x0004, "Reset communication parameter" },
182     { 0x0005, "Reset communication parameter" },
183     { 0x0006, "Reset engineering parameter" },
184     { 0x0007, "Reset engineering parameter" },
185     { 0x0008, "Resets all stored data" },
186     { 0x0009, "Resets all stored data" },
187     { 0x000A, "Reset engineering parameter" },
188     { 0x000B, "Reset engineering parameter" },
189     { 0x000C, "Reserved" },
190     { 0x000D, "Reserved" },
191     { 0x000E, "Reserved" },
192     { 0x0010, "Resets all stored data in the IOD or IOC to its factory values" },
193     { 0x0011, "Resets all stored data in the IOD or IOC to its factory values" },
194     { 0x0012, "Reset and restore data" },
195     { 0x0013, "Reset and restore data" },
196     { 0x0014, "Reserved" },
197     { 0x0015, "Reserved" },
198     { 0x0016, "Reserved" },
199     { 0, NULL }
200 };
201 
202 #define PNDCP_OPTION_IP                 0x01
203 #define PNDCP_OPTION_DEVICE             0x02
204 #define PNDCP_OPTION_DHCP               0x03
205 #define PNDCP_OPTION_RESERVED           0x04
206 #define PNDCP_OPTION_CONTROL            0x05
207 #define PNDCP_OPTION_DEVICEINITIATIVE   0x06
208 #define PNDCP_OPTION_MANUF_X80          0x80
209 #define PNDCP_OPTION_MANUF_XFE          0xFE
210 #define PNDCP_OPTION_ALLSELECTOR        0xFF
211 
212 static const range_string pn_dcp_option[] = {
213     { 0x00, 0x00, "Reserved" },
214     { PNDCP_OPTION_IP              , PNDCP_OPTION_IP              , "IP" },
215     { PNDCP_OPTION_DEVICE          , PNDCP_OPTION_DEVICE          , "Device properties" },
216     { PNDCP_OPTION_DHCP            , PNDCP_OPTION_DHCP            , "DHCP" },
217     { PNDCP_OPTION_RESERVED        , PNDCP_OPTION_RESERVED        , "Reserved" },
218     { PNDCP_OPTION_CONTROL         , PNDCP_OPTION_CONTROL         , "Control" },
219     { PNDCP_OPTION_DEVICEINITIATIVE, PNDCP_OPTION_DEVICEINITIATIVE, "Device Initiative" },
220     /*0x07 - 0x7F reserved */
221     /*0x80 - 0xFE manufacturer specific */
222     { PNDCP_OPTION_MANUF_X80  , PNDCP_OPTION_MANUF_XFE  , "Manufacturer specific" },
223     { PNDCP_OPTION_ALLSELECTOR, PNDCP_OPTION_ALLSELECTOR, "All Selector" },
224     { 0, 0, NULL }
225 };
226 
227 #define PNDCP_SUBOPTION_IP_MAC  0x01
228 #define PNDCP_SUBOPTION_IP_IP   0x02
229 #define PNDCP_SUBOPTION_IP_FULL_IP_SUITE   0x03
230 
231 static const value_string pn_dcp_suboption_ip[] = {
232     { 0x00, "Reserved" },
233     { PNDCP_SUBOPTION_IP_MAC,   "MAC address" },
234     { PNDCP_SUBOPTION_IP_IP,    "IP parameter" },
235     { PNDCP_SUBOPTION_IP_FULL_IP_SUITE,    "Full IP suite" },
236     /*0x03 - 0xff reserved */
237     { 0, NULL }
238 };
239 
240 static const value_string pn_dcp_suboption_ip_block_info[] = {
241     { 0x0000, "IP not set" },
242     { 0x0001, "IP set" },
243     { 0x0002, "IP set by DHCP" },
244     { 0x0080, "IP not set (address conflict detected)" },
245     { 0x0081, "IP set (address conflict detected)" },
246     { 0x0082, "IP set by DHCP (address conflict detected)" },
247     /*0x0003 - 0xffff reserved */
248     { 0, NULL }
249 };
250 
251 static const value_string pn_dcp_suboption_control_signal_value[] = {
252     {0x0100, "Flash Once"},
253     {0, NULL}
254 };
255 
256 #define PNDCP_SUBOPTION_DEVICE_MANUF            0x01
257 #define PNDCP_SUBOPTION_DEVICE_NAMEOFSTATION    0x02
258 #define PNDCP_SUBOPTION_DEVICE_DEV_ID           0x03
259 #define PNDCP_SUBOPTION_DEVICE_DEV_ROLE         0x04
260 #define PNDCP_SUBOPTION_DEVICE_DEV_OPTIONS      0x05
261 #define PNDCP_SUBOPTION_DEVICE_ALIAS_NAME       0x06
262 #define PNDCP_SUBOPTION_DEVICE_DEV_INSTANCE     0x07
263 #define PNDCP_SUBOPTION_DEVICE_OEM_DEV_ID       0x08
264 #define PNDCP_SUBOPTION_DEVICE_RSI_PROPERTIES   0x0A
265 
266 static const value_string pn_dcp_suboption_device[] = {
267     { 0x00, "Reserved" },
268     { PNDCP_SUBOPTION_DEVICE_MANUF,         "Manufacturer specific (Type of Station)" },
269     { PNDCP_SUBOPTION_DEVICE_NAMEOFSTATION, "Name of Station" },
270     { PNDCP_SUBOPTION_DEVICE_DEV_ID,        "Device ID" },
271     { PNDCP_SUBOPTION_DEVICE_DEV_ROLE,      "Device Role" },
272     { PNDCP_SUBOPTION_DEVICE_DEV_OPTIONS,   "Device Options" },
273     { PNDCP_SUBOPTION_DEVICE_ALIAS_NAME,    "Alias Name" },
274     { PNDCP_SUBOPTION_DEVICE_DEV_INSTANCE,  "Device Instance" },
275     { PNDCP_SUBOPTION_DEVICE_OEM_DEV_ID,    "OEM Device ID"},
276     { PNDCP_SUBOPTION_DEVICE_RSI_PROPERTIES,"RSI Properties" },
277     /*0x09 - 0xff reserved */
278     { 0, NULL }
279 };
280 
281 static const true_false_string pn_dcp_rsi_properties_value_bit =
282     { "Available", "Not available" };
283 
284 #define PNDCP_SUBOPTION_DHCP_CLIENT_ID  61
285 #define PNDCP_SUBOPTION_DHCP_CONTROL_FOR_ADDRESS_RES  255
286 
287 static const value_string pn_dcp_suboption_dhcp[] = {
288     { 12, "Host name" },
289     { 43, "Vendor specific" },
290     { 54, "Server identifier" },
291     { 55, "Parameter request list" },
292     { 60, "Class identifier" },
293     { PNDCP_SUBOPTION_DHCP_CLIENT_ID, "DHCP client identifier" },
294     { 81, "FQDN, Fully Qualified Domain Name" },
295     { 97, "UUID/GUID-based Client" },
296     { PNDCP_SUBOPTION_DHCP_CONTROL_FOR_ADDRESS_RES, "Control DHCP for address resolution" },
297     /*all others reserved */
298     { 0, NULL }
299 };
300 
301 static const value_string pn_dcp_suboption_dhcp_control_parameter_data[] = {
302     { 0x00, "Don't use DHCP (Default)" },
303     { 0x01, "Don't use DHCP, all DHCPOptions set to Reset to Factory value" },
304     { 0x02, "Use DHCP with the given set of DHCPOptions" },
305     { 0, NULL }
306 };
307 
308 #define PNDCP_SUBOPTION_CONTROL_START_TRANS 0x01
309 #define PNDCP_SUBOPTION_CONTROL_END_TRANS   0x02
310 #define PNDCP_SUBOPTION_CONTROL_SIGNAL      0x03
311 #define PNDCP_SUBOPTION_CONTROL_RESPONSE    0x04
312 #define PNDCP_SUBOPTION_CONTROL_FACT_RESET  0x05
313 #define PNDCP_SUBOPTION_CONTROL_RESET_TO_FACT  0x06
314 
315 static const value_string pn_dcp_suboption_control[] = {
316     { 0x00, "Reserved" },
317     { PNDCP_SUBOPTION_CONTROL_START_TRANS, "Start Transaction" },
318     { PNDCP_SUBOPTION_CONTROL_END_TRANS,   "End Transaction" },
319     { PNDCP_SUBOPTION_CONTROL_SIGNAL,      "Signal" },
320     { PNDCP_SUBOPTION_CONTROL_RESPONSE,    "Response" },
321     { PNDCP_SUBOPTION_CONTROL_FACT_RESET,  "Reset Factory Settings" },
322     { PNDCP_SUBOPTION_CONTROL_RESET_TO_FACT,"Reset to Factory" },
323     /*0x07 - 0xff reserved */
324     { 0, NULL }
325 };
326 
327 #define PNDCP_SUBOPTION_DEVICEINITIATIVE 0x01
328 
329 static const value_string pn_dcp_suboption_deviceinitiative[] = {
330     { 0x00, "Reserved" },
331     { PNDCP_SUBOPTION_DEVICEINITIATIVE, "Device Initiative" },
332     /*0x00 - 0xff reserved */
333     { 0, NULL }
334 };
335 
336 static const value_string pn_dcp_deviceinitiative_value[] = {
337     { 0x00, "Device does not issue a DCP-Hello-ReqPDU after power on" },
338     { 0x01, "Device does issue a DCP-Hello-ReqPDU after power on" },
339     /*0x02 - 0xff reserved */
340     { 0, NULL }
341 };
342 
343 static const value_string pn_dcp_suboption_all[] = {
344     { 0xff, "ALL Selector" },
345     /* all other reserved */
346     { 0, NULL }
347 };
348 
349 static const value_string pn_dcp_suboption_other[] = {
350     { 0x00, "Default" },
351     /* all other reserved */
352     { 0, NULL }
353 };
354 
355 static const value_string pn_dcp_suboption_manuf[] = {
356     /* none known */
357     { 0, NULL }
358 };
359 
360 
361 
362 
363 
364 /* dissect the option field */
365 static int
dissect_PNDCP_Option(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree,proto_item * block_item,int hfindex,gboolean append_col)366 dissect_PNDCP_Option(tvbuff_t *tvb, int offset, packet_info *pinfo,
367                              proto_tree *tree, proto_item *block_item, int hfindex, gboolean append_col)
368 {
369     guint8 option;
370     guint8 suboption;
371     const value_string *val_str;
372 
373     offset = dissect_pn_uint8 (tvb, offset, pinfo, tree, hfindex, &option);
374     switch (option) {
375     case PNDCP_OPTION_IP:
376         offset  = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip, &suboption);
377         val_str = pn_dcp_suboption_ip;
378         break;
379     case PNDCP_OPTION_DEVICE:
380         offset  = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device, &suboption);
381         val_str = pn_dcp_suboption_device;
382         break;
383     case PNDCP_OPTION_DHCP:
384         offset  = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_dhcp, &suboption);
385         val_str = pn_dcp_suboption_dhcp;
386         break;
387     case PNDCP_OPTION_CONTROL:
388         offset  = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_control, &suboption);
389         val_str = pn_dcp_suboption_control;
390         break;
391     case PNDCP_OPTION_DEVICEINITIATIVE:
392         offset  = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_deviceinitiative, &suboption);
393         val_str = pn_dcp_suboption_deviceinitiative;
394         break;
395     case PNDCP_OPTION_ALLSELECTOR:
396         offset  = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_all, &suboption);
397         val_str = pn_dcp_suboption_all;
398         break;
399     default:
400         offset  = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_manuf, &suboption);
401         val_str = pn_dcp_suboption_manuf;
402     }
403 
404     proto_item_append_text(block_item, ", Status from %s - %s",
405         rval_to_str(option, pn_dcp_option, "Unknown"), val_to_str(suboption, val_str, "Unknown"));
406 
407     if (append_col) {
408         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", val_to_str(suboption, val_str, "Unknown"));
409     }
410 
411     return offset;
412 }
413 
414 
415 /* dissect the "IP" suboption */
416 static int
dissect_PNDCP_Suboption_IP(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree,proto_item * block_item,proto_item * dcp_item,guint8 service_id,gboolean is_response)417 dissect_PNDCP_Suboption_IP(tvbuff_t *tvb, int offset, packet_info *pinfo,
418                             proto_tree *tree, proto_item *block_item, proto_item *dcp_item,
419                             guint8 service_id, gboolean is_response)
420 {
421     guint8      suboption;
422     guint16     block_length;
423     guint16     block_info;
424     guint16     block_qualifier;
425     gboolean    have_block_info = FALSE;
426     gboolean    have_block_qualifier = FALSE;
427     guint8      mac[6];
428     guint32     ip;
429     proto_item *item = NULL;
430     address     addr;
431 
432 
433     /* SuboptionIPParameter */
434     offset = dissect_pn_uint8 (tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip, &suboption);
435     /* DCPBlockLength */
436     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);
437 
438     switch (suboption) {
439     case PNDCP_SUBOPTION_IP_MAC:
440         /* MACAddressValue? */
441         pn_append_info(pinfo, dcp_item, ", MAC");
442         proto_item_append_text(block_item, "IP/MAC");
443 
444         /* BlockInfo? */
445         if (((service_id == PNDCP_SERVICE_ID_IDENTIFY) && is_response) ||
446             ((service_id == PNDCP_SERVICE_ID_HELLO) && !is_response) ||
447             ((service_id == PNDCP_SERVICE_ID_GET) && is_response)) {
448             offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_info, &block_info);
449             have_block_info = TRUE;
450             block_length -= 2;
451         }
452 
453         /* BlockQualifier? */
454         if ((service_id == PNDCP_SERVICE_ID_SET) && !is_response) {
455             offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_qualifier, &block_qualifier);
456             have_block_qualifier = TRUE;
457             block_length -= 2;
458         }
459 
460         if (have_block_qualifier) {
461             proto_item_append_text(block_item, ", BlockQualifier: %s",
462                 val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
463         }
464         if (have_block_info) {
465             proto_item_append_text(block_item, ", BlockInfo: %s",
466                 rval_to_str(block_info, pn_dcp_block_info, "Unknown"));
467         }
468 
469         offset = dissect_pn_mac(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_mac_address, mac);
470         set_address(&addr, AT_ETHER, 6, mac);
471         proto_item_append_text(block_item, ", MACAddress: %s", address_to_str(pinfo->pool, &addr));
472         break;
473     case PNDCP_SUBOPTION_IP_IP:
474         pn_append_info(pinfo, dcp_item, ", IP");
475         proto_item_append_text(block_item, "IP/IP");
476 
477         /* BlockInfo? */
478         if (((service_id == PNDCP_SERVICE_ID_IDENTIFY) && is_response) ||
479             ((service_id == PNDCP_SERVICE_ID_HELLO) && !is_response) ||
480             ((service_id == PNDCP_SERVICE_ID_GET) && is_response)) {
481             block_info = tvb_get_ntohs(tvb, offset);
482             if (tree) {
483                 item = proto_tree_add_uint(tree, hf_pn_dcp_suboption_ip_block_info, tvb, offset, 2, block_info);
484             }
485             offset += 2;
486             proto_item_append_text(block_item, ", BlockInfo: %s",
487                 val_to_str(block_info, pn_dcp_suboption_ip_block_info, "Undecoded"));
488             block_length -= 2;
489             if (block_info & 0x80) {
490                 expert_add_info(pinfo, item, &ei_pn_dcp_ip_conflict);
491             }
492         }
493 
494         /* BlockQualifier? */
495         if ( (service_id == PNDCP_SERVICE_ID_SET) && !is_response) {
496             offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_qualifier, &block_qualifier);
497             proto_item_append_text(block_item, ", BlockQualifier: %s",
498                                    val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
499             block_length -= 2;
500         }
501 
502         /* IPParameterValue ... */
503 
504         /* IPAddress */
505         offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_ip, &ip);
506         set_address(&addr, AT_IPv4, 4, &ip);
507         proto_item_append_text(block_item, ", IP: %s", address_to_str(pinfo->pool, &addr));
508 
509         /* Subnetmask */
510         offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_subnetmask, &ip);
511         set_address(&addr, AT_IPv4, 4, &ip);
512         proto_item_append_text(block_item, ", Subnet: %s", address_to_str(pinfo->pool, &addr));
513 
514         /* StandardGateway */
515         offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_standard_gateway, &ip);
516         set_address(&addr, AT_IPv4, 4, &ip);
517         proto_item_append_text(block_item, ", Gateway: %s", address_to_str(pinfo->pool, &addr));
518         break;
519     case PNDCP_SUBOPTION_IP_FULL_IP_SUITE:
520         pn_append_info(pinfo, dcp_item, ", MAC");
521         proto_item_append_text(block_item, "IP/MAC");
522 
523         /* BlockInfo? */
524         if (((service_id == PNDCP_SERVICE_ID_IDENTIFY) && is_response) ||
525             ((service_id == PNDCP_SERVICE_ID_HELLO) && !is_response) ||
526             ((service_id == PNDCP_SERVICE_ID_GET) && is_response)) {
527             offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_info, &block_info);
528             have_block_info = TRUE;
529             block_length -= 2;
530         }
531 
532         /* BlockQualifier? */
533         if ((service_id == PNDCP_SERVICE_ID_SET) && !is_response) {
534             offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_qualifier, &block_qualifier);
535             have_block_qualifier = TRUE;
536             block_length -= 2;
537         }
538 
539         if (have_block_qualifier) {
540             proto_item_append_text(block_item, ", BlockQualifier: %s",
541                val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
542         }
543         if (have_block_info) {
544             proto_item_append_text(block_item, ", BlockInfo: %s",
545                 rval_to_str(block_info, pn_dcp_block_info, "Unknown"));
546         }
547 
548         /* IPAddress */
549         offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_ip, &ip);
550         set_address(&addr, AT_IPv4, 4, &ip);
551         proto_item_append_text(block_item, ", IP: %s", address_to_str(pinfo->pool, &addr));
552 
553         /* Subnetmask */
554         offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_subnetmask, &ip);
555         set_address(&addr, AT_IPv4, 4, &ip);
556         proto_item_append_text(block_item, ", Subnet: %s", address_to_str(pinfo->pool, &addr));
557 
558         /* StandardGateway */
559         offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_standard_gateway, &ip);
560         set_address(&addr, AT_IPv4, 4, &ip);
561         proto_item_append_text(block_item, ", Gateway: %s", address_to_str(pinfo->pool, &addr));
562 
563         /* IPAddress_1 */
564         offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_ip, &ip);
565         set_address(&addr, AT_IPv4, 4, &ip);
566         proto_item_append_text(block_item, ", DNSServerIP1: %s", address_to_str(pinfo->pool, &addr));
567 
568         /* IPAddress_2 */
569         offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_subnetmask, &ip);
570         set_address(&addr, AT_IPv4, 4, &ip);
571         proto_item_append_text(block_item, ", DNSServerIP2: %s", address_to_str(pinfo->pool, &addr));
572 
573         /* IPAddress_3 */
574         offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_standard_gateway, &ip);
575         set_address(&addr, AT_IPv4, 4, &ip);
576         proto_item_append_text(block_item, ", DNSServerIP3: %s", address_to_str(pinfo->pool, &addr));
577 
578         /* IPAddress_4 */
579         offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_standard_gateway, &ip);
580         set_address(&addr, AT_IPv4, 4, &ip);
581         proto_item_append_text(block_item, ", DNSServerIP4: %s", address_to_str(pinfo->pool, &addr));
582 
583         break;
584     default:
585         offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, block_length);
586     }
587 
588     return offset;
589 }
590 
591 
592 /* dissect the "device" suboption */
593 static int
dissect_PNDCP_Suboption_Device(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree,proto_item * block_item,proto_item * dcp_item,guint8 service_id,gboolean is_response)594 dissect_PNDCP_Suboption_Device(tvbuff_t *tvb, int offset, packet_info *pinfo,
595                                proto_tree *tree, proto_item *block_item, proto_item *dcp_item,
596                                guint8 service_id, gboolean is_response)
597 {
598     guint8    suboption;
599     guint16   block_length;
600     gchar    *info_str;
601     guint8    device_role;
602     guint16   vendor_id;
603     guint16   device_id;
604     char     *typeofstation;
605     char     *nameofstation;
606     char     *aliasname;
607     guint16   block_info = 0;
608     guint16   block_qualifier = 0;
609     gboolean  have_block_info      = FALSE;
610     gboolean  have_block_qualifier = FALSE;
611     guint8    device_instance_high;
612     guint8    device_instance_low;
613     guint16   oem_vendor_id;
614     guint16   oem_device_id;
615     proto_item *sub_item;
616     proto_tree *sub_tree;
617     conversation_t    *conversation;
618     stationInfo       *station_info;
619 
620     /* SuboptionDevice... */
621     offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device, &suboption);
622     /* DCPBlockLength */
623     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);
624 
625     /* BlockInfo? */
626     if ( ((service_id == PNDCP_SERVICE_ID_IDENTIFY) &&  is_response) ||
627          ((service_id == PNDCP_SERVICE_ID_HELLO)    && !is_response) ||
628          ((service_id == PNDCP_SERVICE_ID_GET)      &&  is_response)) {
629         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_info, &block_info);
630         have_block_info = TRUE;
631         block_length -= 2;
632     }
633 
634     /* BlockQualifier? */
635     if ( (service_id == PNDCP_SERVICE_ID_SET) && !is_response) {
636         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_qualifier, &block_qualifier);
637         have_block_qualifier = TRUE;
638         block_length -= 2;
639     }
640 
641     switch (suboption) {
642     case PNDCP_SUBOPTION_DEVICE_MANUF:
643         /*
644          * XXX - IEC 61158-6-10 Edition 4.0, section 4.3, says this field
645          * "shall be coded as data type VisibleString", and that VisibleString
646          * is "ISO/IEC 646 - International Reference Version without the "del"
647          * (coding 0x7F) character", i.e. ASCII.
648          *
649          * However, at least one capture has a packet where 0xAE is used in
650          * a place where a registered trademark symbol would be appropriate,
651          * so the host sending it apparently extended ASCII to ISO 8859-n
652          * for some value of n.  That may have just been an error on their
653          * part, not realizing that they should have done "(R)" or something
654          * such as that.
655          */
656         proto_tree_add_item_ret_display_string (tree, hf_pn_dcp_suboption_device_typeofstation, tvb, offset, block_length, ENC_ASCII|ENC_NA, pinfo->pool, &typeofstation);
657         pn_append_info(pinfo, dcp_item, ", DeviceVendorValue");
658         proto_item_append_text(block_item, "Device/Manufacturer specific");
659         if (have_block_qualifier) {
660             proto_item_append_text(block_item, ", BlockQualifier: %s",
661                                    val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
662         }
663         if (have_block_info){
664             proto_item_append_text(block_item, ", BlockInfo: %s",
665                                    rval_to_str(block_info, pn_dcp_block_info, "Unknown"));
666         }
667         proto_item_append_text(block_item, ", DeviceVendorValue: \"%s\"", typeofstation);
668 
669 
670         if (PINFO_FD_VISITED(pinfo) == FALSE) {
671             /* Create a conversation between the MAC addresses */
672             conversation = find_conversation(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0);
673             if (conversation == NULL) {
674                 /* Create new conversation, need to switch dl_src & dl_dst if not a response
675                  * All conversations are based on Device MAC as addr1 */
676                 if (is_response) {
677                    conversation = conversation_new(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0);
678                 }
679                 else {
680                    conversation = conversation_new(pinfo->num, &pinfo->dl_dst, &pinfo->dl_src, ENDPOINT_NONE, 0, 0, 0);
681                 }
682             }
683 
684             station_info = (stationInfo*)conversation_get_proto_data(conversation, proto_pn_dcp);
685             if (station_info == NULL) {
686                 station_info = wmem_new0(wmem_file_scope(), stationInfo);
687                 init_pnio_rtc1_station(station_info);
688                 conversation_add_proto_data(conversation, proto_pn_dcp, station_info);
689             }
690 
691             station_info->typeofstation = wmem_strdup(wmem_file_scope(), typeofstation);
692         }
693 
694         offset += block_length;
695         break;
696 
697     case PNDCP_SUBOPTION_DEVICE_NAMEOFSTATION:
698         /*
699          * XXX - IEC 61158-6-10 Edition 4.0 says, in section 4.3.1.4.15
700          * "Coding of the field NameOfStationValue", that "This field shall
701          * be coded as data type OctetString with 1 to 240 octets.  The
702          * definition of IETF RFC 5890 and the following syntax applies: ..."
703          *
704          * RFC 5890 means Punycode; should we translate the domain name to
705          * UTF-8 and show both the untranslated and translated domain name?
706          *
707          * They don't mention anything about the RFC 1035 encoding of
708          * domain names as mentioned in section 3.1 "Name space definitions",
709          * with the labels being counted strings; does that mean that this
710          * is just an ASCII string to be interpreted as a Punycode Unicode
711          * domain name?
712          */
713         proto_tree_add_item_ret_display_string (tree, hf_pn_dcp_suboption_device_nameofstation, tvb, offset, block_length, ENC_ASCII|ENC_NA, pinfo->pool, &nameofstation);
714         pn_append_info(pinfo, dcp_item, wmem_strdup_printf(pinfo->pool, ", NameOfStation:\"%s\"", nameofstation));
715         proto_item_append_text(block_item, "Device/NameOfStation");
716         if (have_block_qualifier) {
717             proto_item_append_text(block_item, ", BlockQualifier: %s",
718                                    val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
719         }
720         if (have_block_info) {
721             proto_item_append_text(block_item, ", BlockInfo: %s",
722                                    rval_to_str(block_info, pn_dcp_block_info, "Unknown"));
723         }
724         proto_item_append_text(block_item, ", \"%s\"", nameofstation);
725 
726 
727         if (PINFO_FD_VISITED(pinfo) == FALSE) {
728             /* Create a conversation between the MAC addresses */
729             conversation = find_conversation(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0);
730             if (conversation == NULL) {
731                 /* Create new conversation, need to switch dl_src & dl_dst if not a response
732                  * All conversations are based on Device MAC as addr1 */
733                 if (is_response) {
734                    conversation = conversation_new(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0);
735                 }
736                 else {
737                    conversation = conversation_new(pinfo->num, &pinfo->dl_dst, &pinfo->dl_src, ENDPOINT_NONE, 0, 0, 0);
738                 }
739             }
740 
741             station_info = (stationInfo*)conversation_get_proto_data(conversation, proto_pn_dcp);
742             if (station_info == NULL) {
743                 station_info = wmem_new0(wmem_file_scope(), stationInfo);
744                 init_pnio_rtc1_station(station_info);
745                 conversation_add_proto_data(conversation, proto_pn_dcp, station_info);
746             }
747 
748             station_info->nameofstation = wmem_strdup(wmem_file_scope(), nameofstation);
749         }
750 
751         offset += block_length;
752         break;
753 
754     case PNDCP_SUBOPTION_DEVICE_DEV_ID:
755         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_vendor_id, &vendor_id);
756         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device_id, &device_id);
757 
758         if (PINFO_FD_VISITED(pinfo) == FALSE) {
759             /* Create a conversation between the MAC addresses */
760             conversation = find_conversation(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0);
761             if (conversation == NULL) {
762                 /* Create new conversation, need to switch dl_src & dl_dst if not a response
763                  * All conversations are based on Device MAC as addr1 */
764                 if (is_response) {
765                    conversation = conversation_new(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0);
766                 }
767                 else {
768                    conversation = conversation_new(pinfo->num, &pinfo->dl_dst, &pinfo->dl_src, ENDPOINT_NONE, 0, 0, 0);
769                 }
770             }
771 
772             station_info = (stationInfo*)conversation_get_proto_data(conversation, proto_pn_dcp);
773             if (station_info == NULL) {
774                 station_info = wmem_new0(wmem_file_scope(), stationInfo);
775                 init_pnio_rtc1_station(station_info);
776                 conversation_add_proto_data(conversation, proto_pn_dcp, station_info);
777             }
778 
779             station_info->u16Vendor_id = vendor_id;
780             station_info->u16Device_id = device_id;
781         }
782 
783 
784         pn_append_info(pinfo, dcp_item, ", Dev-ID");
785         proto_item_append_text(block_item, "Device/Device ID");
786         if (have_block_qualifier) {
787             proto_item_append_text(block_item, ", BlockQualifier: %s",
788                                    val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
789         }
790         if (have_block_info) {
791             proto_item_append_text(block_item, ", BlockInfo: %s",
792                                    rval_to_str(block_info, pn_dcp_block_info, "Unknown"));
793         }
794         proto_item_append_text(block_item, ", VendorID: 0x%04x / DeviceID: 0x%04x", vendor_id, device_id);
795         break;
796     case PNDCP_SUBOPTION_DEVICE_DEV_ROLE:
797         offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device_role, &device_role);
798         offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_reserved8, NULL);
799         pn_append_info(pinfo, dcp_item, ", Dev-Role");
800         proto_item_append_text(block_item, "Device/Device Role");
801         if (have_block_qualifier) {
802             proto_item_append_text(block_item, ", BlockQualifier: %s",
803                                    val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
804         }
805         if (have_block_info)
806             proto_item_append_text(block_item, ", BlockInfo: %s", rval_to_str(block_info, pn_dcp_block_info, "Unknown"));
807         if (device_role & 0x01)
808             proto_item_append_text(block_item, ", IO-Device");
809         if (device_role & 0x02)
810             proto_item_append_text(block_item, ", IO-Controller");
811         if (device_role & 0x04)
812             proto_item_append_text(block_item, ", IO-Multidevice");
813         if (device_role & 0x08)
814             proto_item_append_text(block_item, ", PN-Supervisor");
815         break;
816     case PNDCP_SUBOPTION_DEVICE_DEV_OPTIONS:
817         info_str = wmem_strdup_printf(pinfo->pool, ", Dev-Options(%u)", block_length/2);
818         pn_append_info(pinfo, dcp_item, info_str);
819         proto_item_append_text(block_item, "Device/Device Options");
820         if (have_block_qualifier) {
821             proto_item_append_text(block_item, ", BlockQualifier: %s",
822                                    val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
823         }
824         if (have_block_info) {
825             proto_item_append_text(block_item, ", BlockInfo: %s",
826                                    rval_to_str(block_info, pn_dcp_block_info, "Unknown"));
827         }
828         proto_item_append_text(block_item, ", %u options", block_length/2);
829         for( ; block_length != 0; block_length -= 2) {
830             offset = dissect_PNDCP_Option(tvb, offset, pinfo, tree, NULL /*block_item*/, hf_pn_dcp_option,
831                 FALSE /* append_col */);
832         }
833         break;
834     case PNDCP_SUBOPTION_DEVICE_ALIAS_NAME:
835         /*
836          * XXX - IEC 61158-6-10 Edition 4.0, section 4.3.1.4.17 "Coding of
837          * the field AliasNameValue", says this field "shall be coded as
838          * OctetString. The content shall be the concatenation of the content
839          * of the fields NameOfPort and NameOfStation.
840          *
841          *    AliasNameValue = NameOfPort + "." + NameOfStation
842          *
843          * " and:
844          *
845          *   It says in section 4.3.1.4.16 "Coding of the field NameOfPort"
846          *   that "This field shall be coded as OctetString[8] or
847          *   OctetString[14] as "port-xyz" or "port-xyz-rstuv" where x, y,
848          *   z is in the range "0"-"9" from 001 up to 255 and r, s, t, u, v
849          *   is in the range "0"-"9" from 00000 up to 65535. ...
850          *   Furthermore, the definition of IETF RFC 5890 shall be applied."
851          *
852          *   That suggests that the Octets are probably just ASCII characters;
853          *   IETF RFC 5890 means Punycode, but there isn't anything in those
854          *   string formats that requires non-ASCII characters - they're
855          *   just literally "port-" followed by numbers and hyphens.
856          *
857          *   It says in section 4.3.1.4.15 "Coding of the field
858          *   NameOfStationValue" that it's a domain name, complete with
859          *   RFC 5890 Punycode.
860          */
861         proto_tree_add_item_ret_display_string (tree, hf_pn_dcp_suboption_device_aliasname, tvb, offset, block_length, ENC_ASCII|ENC_NA, pinfo->pool, &aliasname);
862         pn_append_info(pinfo, dcp_item, wmem_strdup_printf(pinfo->pool, ", AliasName:\"%s\"", aliasname));
863         proto_item_append_text(block_item, "Device/AliasName");
864         if (have_block_qualifier) {
865             proto_item_append_text(block_item, ", BlockQualifier: %s",
866                                    val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
867         }
868         if (have_block_info) {
869             proto_item_append_text(block_item, ", BlockInfo: %s",
870                                    rval_to_str(block_info, pn_dcp_block_info, "Unknown"));
871         }
872         proto_item_append_text(block_item, ", \"%s\"", aliasname);
873         offset += block_length;
874         break;
875     case PNDCP_SUBOPTION_DEVICE_DEV_INSTANCE:
876         offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device_instance_high, &device_instance_high);
877         offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device_instance_low, &device_instance_low);
878         pn_append_info(pinfo, dcp_item, ", Dev-Instance");
879         proto_item_append_text(block_item, "Device/Device Instance");
880         if (have_block_qualifier) {
881             proto_item_append_text(block_item, ", BlockQualifier: %s",
882                                    val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
883         }
884         if (have_block_info) {
885             proto_item_append_text(block_item, ", BlockInfo: %s",
886                                    rval_to_str(block_info, pn_dcp_block_info, "Unknown"));
887         }
888         proto_item_append_text(block_item, ", InstanceHigh: %d, Instance Low: %d",
889                                device_instance_high, device_instance_low);
890         break;
891     case PNDCP_SUBOPTION_DEVICE_OEM_DEV_ID:
892         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device_oem_ven_id, &oem_vendor_id);
893         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device_oem_dev_id, &oem_device_id);
894         pn_append_info(pinfo, dcp_item, ", OEM-Dev-ID");
895         proto_item_append_text(block_item, "Device/OEM Device ID");
896         if(have_block_qualifier) {
897             proto_item_append_text(block_item, ", BlockQualifier: %s",
898                                    val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
899         }
900         if(have_block_info) {
901             proto_item_append_text(block_item, ", BlockInfo: %s",
902                                    rval_to_str(block_info, pn_dcp_block_info, "Unknown"));
903         }
904         proto_item_append_text(block_item, ", OEMVendorID: 0x%04x / OEMDeviceID: 0x%04x", oem_vendor_id, oem_device_id);
905         break;
906     case PNDCP_SUBOPTION_DEVICE_RSI_PROPERTIES:
907         sub_item = proto_tree_add_item(tree, hf_pn_dcp_rsi_properties_value, tvb, offset, 2, ENC_BIG_ENDIAN);
908         sub_tree = proto_item_add_subtree(sub_item, ett_pn_dcp_rsi_properties_value);
909 
910         static int* const flags[] = {
911             &hf_pn_dcp_rsi_properties_value_bit0,
912             &hf_pn_dcp_rsi_properties_value_bit1,
913             &hf_pn_dcp_rsi_properties_value_bit2,
914             &hf_pn_dcp_rsi_properties_value_bit3,
915             &hf_pn_dcp_rsi_properties_value_bit4,
916             &hf_pn_dcp_rsi_properties_value_bit5,
917             &hf_pn_dcp_rsi_properties_value_otherbits,
918             NULL
919         };
920 
921         proto_tree_add_bitmask(sub_tree, tvb, offset, hf_pn_dcp_rsi_properties_value, ett_pn_dcp_rsi_properties_value, flags, ENC_BIG_ENDIAN);
922 
923         offset = offset + 2;
924 
925         if (pinfo->fd->visited == FALSE) {
926             /* Create a conversation between the MAC addresses */
927             conversation = find_conversation(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0);
928             if (conversation == NULL) {
929                 conversation = conversation_new(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0);
930             }
931 
932             station_info = (stationInfo*)conversation_get_proto_data(conversation, proto_pn_dcp);
933             if (station_info == NULL) {
934                 station_info = wmem_new0(wmem_file_scope(), stationInfo);
935                 init_pnio_rtc1_station(station_info);
936                 conversation_add_proto_data(conversation, proto_pn_dcp, station_info);
937             }
938         }
939 
940         pn_append_info(pinfo, dcp_item, ", RSI-Properties");
941         proto_item_append_text(block_item, "Device/RSI Properties");
942         if (have_block_qualifier) {
943             proto_item_append_text(block_item, ", BlockQualifier: %s",
944                 val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
945         }
946         if (have_block_info) {
947             proto_item_append_text(block_item, ", BlockInfo: %s",
948                 rval_to_str(block_info, pn_dcp_block_info, "Unknown"));
949         }
950         break;
951     default:
952         offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, block_length);
953     }
954 
955     return offset;
956 }
957 
958 
959 /* dissect the "DHCP" suboption */
960 static int
dissect_PNDCP_Suboption_DHCP(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree,proto_item * block_item,proto_item * dcp_item,guint8 service_id _U_,gboolean is_response _U_)961 dissect_PNDCP_Suboption_DHCP(tvbuff_t *tvb, int offset, packet_info *pinfo,
962                                 proto_tree *tree, proto_item *block_item, proto_item *dcp_item,
963                                 guint8 service_id _U_, gboolean is_response _U_)
964 {
965     guint8   suboption;
966     guint8   option_code = 0;
967     guint16  block_length;
968     guint16  block_info = 0;
969     guint16  block_qualifier = 0;
970     guint8   dhcpparameterlength = 0;
971     guint8   dhcpparameterdata = 0;
972     guint8   dhcpcontrolparameterdata = 0;
973     gboolean have_block_info      = FALSE;
974     gboolean have_block_qualifier = FALSE;
975     int      expected_offset;
976 
977 
978     offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_dhcp, &suboption);
979     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);
980 
981     expected_offset = offset + block_length;
982 
983     /* BlockInfo? */
984     if ( ((service_id == PNDCP_SERVICE_ID_IDENTIFY) &&  is_response) ||
985          ((service_id == PNDCP_SERVICE_ID_HELLO)    && !is_response) ||
986          ((service_id == PNDCP_SERVICE_ID_GET)      &&  is_response)) {
987         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_info, &block_info);
988         have_block_info=TRUE;
989         block_length -= 2;
990     }
991     /* BlockQualifier? */
992     if ( (service_id == PNDCP_SERVICE_ID_SET) && !is_response) {
993         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_qualifier, &block_qualifier);
994         have_block_qualifier=TRUE;
995         block_length -= 2;
996     }
997 
998     switch (suboption) {
999     case PNDCP_SUBOPTION_DHCP_CLIENT_ID:
1000         pn_append_info(pinfo, dcp_item, ", DHCP client identifier");
1001         proto_item_append_text(block_item, "DHCP/Client-ID");
1002         if (have_block_qualifier) {
1003             proto_item_append_text(block_item, ", BlockQualifier: %s",
1004                                    val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
1005         }
1006         if (have_block_info) {
1007             proto_item_append_text(block_item, ", BlockInfo: %s",
1008                                    rval_to_str(block_info, pn_dcp_block_info, "Unknown"));
1009         }
1010         offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_dhcp_option_code, &option_code);
1011         offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_dhcp_parameter_length, &dhcpparameterlength);
1012         if (dhcpparameterlength > 0) {
1013             offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_dhcp_parameter_data, &dhcpparameterdata);
1014             if (dhcpparameterlength == 1) {
1015                 if (dhcpparameterdata == 1) {
1016                     proto_item_append_text(block_item, ", Client-ID: MAC Address");
1017                 }
1018                 else {
1019                     proto_item_append_text(block_item, ", Client-ID: Name of Station");
1020                 }
1021             }
1022             else {
1023                 proto_item_append_text(block_item, ", Client-ID: Arbitrary");
1024                 /*
1025                  * XXX - IEC 61158-6-10 Edition 4.0, section 4.3.1.4.21.5
1026                  * "Use of arbitrary client identifier", that this is an
1027                  * OctetString to be used as a client identifier with DHCP.
1028                  *
1029                  * Does that mean it should be FT_BYTES, possibly with
1030                  * the BASE_SHOW_ASCII_PRINTABLE flag to show it as ASCII
1031                  * iff it's printable?  Or should packet-dhcp.c export
1032                  * dissect_dhcpopt_client_identifier(), so that we can
1033                  * use its heuristics?
1034                  */
1035                 proto_tree_add_item(tree, hf_pn_dcp_suboption_dhcp_arbitrary_client_id, tvb, offset, dhcpparameterlength - 1, ENC_ASCII|ENC_NA);
1036                 offset += (dhcpparameterlength-1);
1037             }
1038         }
1039         break;
1040     case PNDCP_SUBOPTION_DHCP_CONTROL_FOR_ADDRESS_RES:
1041         pn_append_info(pinfo, dcp_item, ", Control DHCP for address resolution");
1042         proto_item_append_text(block_item, "DHCP/Control DHCP for address resolution");
1043         if (have_block_qualifier) {
1044             proto_item_append_text(block_item, ", BlockQualifier: %s",
1045                 val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
1046         }
1047         if (have_block_info) {
1048             proto_item_append_text(block_item, ", BlockInfo: %s",
1049                 rval_to_str(block_info, pn_dcp_block_info, "Unknown"));
1050         }
1051         offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_dhcp_option_code, &option_code);
1052         offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_dhcp_parameter_length, &dhcpparameterlength);
1053         offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_dhcp_control_parameter_data, &dhcpcontrolparameterdata);
1054         break;
1055     default:
1056         offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, block_length);
1057     }
1058 
1059     if (expected_offset > offset) {
1060         offset = dissect_pn_user_data(tvb, offset, pinfo, tree, expected_offset - offset, "Undefined");
1061     }
1062 
1063     return offset;
1064 }
1065 
1066 
1067 /* dissect the "control" suboption */
1068 static int
dissect_PNDCP_Suboption_Control(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree,proto_item * block_item,proto_item * dcp_item,guint8 service_id _U_,gboolean is_response _U_)1069 dissect_PNDCP_Suboption_Control(tvbuff_t *tvb, int offset, packet_info *pinfo,
1070                                 proto_tree *tree, proto_item *block_item, proto_item *dcp_item,
1071                                 guint8 service_id _U_, gboolean is_response _U_)
1072 {
1073     guint8      suboption;
1074     guint16     block_length;
1075     guint16     block_qualifier;
1076     guint16     BlockQualifier;
1077     guint16     u16SignalValue;
1078     gchar      *info_str;
1079     guint8      block_error;
1080     proto_item *item = NULL;
1081 
1082 
1083     offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_control, &suboption);
1084     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);
1085 
1086     if (service_id == PNDCP_SERVICE_ID_SET && block_length == 0) {
1087         pn_append_info(pinfo, dcp_item, ", Erroneous DCPSet block");
1088         proto_item_append_text(block_item, "Control/Erroneous DCPSet block");
1089     }
1090     else {
1091         switch (suboption) {
1092         case PNDCP_SUBOPTION_CONTROL_START_TRANS:
1093             pn_append_info(pinfo, dcp_item, ", Start-Trans");
1094             proto_item_append_text(block_item, "Control/Start-Transaction");
1095             offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_qualifier, &block_qualifier);
1096             break;
1097         case PNDCP_SUBOPTION_CONTROL_END_TRANS:
1098             pn_append_info(pinfo, dcp_item, ", End-Trans");
1099             proto_item_append_text(block_item, "Control/End-Transaction");
1100             offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_qualifier, &block_qualifier);
1101             break;
1102         case PNDCP_SUBOPTION_CONTROL_SIGNAL:
1103             pn_append_info(pinfo, dcp_item, ", Signal");
1104             proto_item_append_text(block_item, "Control/Signal");
1105             offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_qualifier, &block_qualifier);
1106             block_length -= 2;
1107 
1108             offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_control_signal_value, &u16SignalValue);
1109             break;
1110         case PNDCP_SUBOPTION_CONTROL_RESPONSE:
1111             proto_item_append_text(block_item, "Control/Response");
1112             offset = dissect_PNDCP_Option(tvb, offset, pinfo, tree, block_item, hf_pn_dcp_suboption_control_option,
1113                 FALSE /* append_col */);
1114             block_error = tvb_get_guint8(tvb, offset);
1115             if (tree) {
1116                 item = proto_tree_add_uint(tree, hf_pn_dcp_block_error, tvb, offset, 1, block_error);
1117             }
1118             offset += 1;
1119             if (block_error != 0) {
1120                 expert_add_info_format(pinfo, item, &ei_pn_dcp_block_error_unknown, "%s",
1121                     val_to_str(block_error, pn_dcp_block_error, "Unknown"));
1122             }
1123             info_str = wmem_strdup_printf(pinfo->pool, ", Response(%s)",
1124                 val_to_str(block_error, pn_dcp_block_error, "Unknown"));
1125             pn_append_info(pinfo, dcp_item, info_str);
1126             proto_item_append_text(block_item, ", BlockError: %s",
1127                 val_to_str(block_error, pn_dcp_block_error, "Unknown"));
1128 
1129             break;
1130         case PNDCP_SUBOPTION_CONTROL_FACT_RESET:
1131             pn_append_info(pinfo, dcp_item, ", Reset FactorySettings");
1132             proto_item_append_text(block_item, "Control/Reset FactorySettings");
1133             block_length -= 2;
1134             offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_blockqualifier, &BlockQualifier);
1135             proto_item_append_text(block_item, ", BlockQualifier: %s",
1136                 val_to_str(BlockQualifier, pn_dcp_suboption_other, "reserved"));
1137             block_length -= 2;
1138             break;
1139 
1140         case PNDCP_SUBOPTION_CONTROL_RESET_TO_FACT:
1141             pn_append_info(pinfo, dcp_item, ", Reset to Factory");
1142             proto_item_append_text(block_item, "Reset to FactorySettings");
1143 
1144             offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_blockqualifier_r2f, &BlockQualifier);
1145             proto_item_append_text(block_item, ", BlockQualifier: %s",
1146                 val_to_str(BlockQualifier, pn_dcp_BlockQualifier, "reserved"));
1147             block_length -= 2;
1148 
1149             break;
1150         default:
1151             offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, block_length);
1152         }
1153     }
1154 
1155     return offset;
1156 }
1157 
1158 
1159 /* dissect the "deviceinitaitve" suboption */
1160 static int
dissect_PNDCP_Suboption_DeviceInitiative(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree,proto_item * block_item,proto_item * dcp_item,guint8 service_id,gboolean is_response)1161 dissect_PNDCP_Suboption_DeviceInitiative(tvbuff_t *tvb, int offset, packet_info *pinfo,
1162                             proto_tree *tree, proto_item *block_item, proto_item *dcp_item,
1163                             guint8 service_id, gboolean is_response)
1164 {
1165     guint8  suboption;
1166     guint16 block_length;
1167     guint16 block_info;
1168     guint16 block_qualifier;
1169     guint16 value;
1170 
1171 
1172     offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_deviceinitiative, &suboption);
1173     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);
1174 
1175     pn_append_info(pinfo, dcp_item, ", DeviceInitiative");
1176     proto_item_append_text(block_item, "DeviceInitiative/DeviceInitiative");
1177 
1178     /* BlockInfo? */
1179     if ( ((service_id == PNDCP_SERVICE_ID_IDENTIFY) &&  is_response) ||
1180         ((service_id == PNDCP_SERVICE_ID_HELLO)    && !is_response) ||
1181         ((service_id == PNDCP_SERVICE_ID_GET)      &&  is_response)) {
1182         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_info, &block_info);
1183         proto_item_append_text(block_item, ", BlockInfo: %s",
1184                                rval_to_str(block_info, pn_dcp_block_info, "Unknown"));
1185         block_length -= 2;
1186     }
1187 
1188     /* BlockQualifier? */
1189     if ( (service_id == PNDCP_SERVICE_ID_SET) && !is_response) {
1190         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_qualifier, &block_qualifier);
1191         proto_item_append_text(block_item, ", BlockQualifier: %s",
1192                                val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
1193         block_length -= 2;
1194     }
1195 
1196     /* DeviceInitiativeValue */
1197     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_deviceinitiative_value, &value);
1198 
1199     return offset;
1200 }
1201 
1202 
1203 /* dissect the "all" suboption */
1204 static int
dissect_PNDCP_Suboption_All(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree,proto_item * block_item,proto_item * dcp_item,guint8 service_id _U_,gboolean is_response _U_)1205 dissect_PNDCP_Suboption_All(tvbuff_t *tvb, int offset, packet_info *pinfo,
1206                             proto_tree *tree, proto_item *block_item, proto_item *dcp_item,
1207                             guint8 service_id _U_, gboolean is_response _U_)
1208 {
1209     guint8  suboption;
1210     guint16 block_length;
1211 
1212 
1213     offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_all, &suboption);
1214     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);
1215 
1216     switch (suboption) {
1217     case 255:    /* All */
1218         pn_append_info(pinfo, dcp_item, ", All");
1219         proto_item_append_text(block_item, "All/All");
1220         break;
1221     default:
1222         offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, block_length);
1223     }
1224 
1225     return offset;
1226 }
1227 
1228 
1229 /* dissect the "manufacturer" suboption */
1230 static int
dissect_PNDCP_Suboption_Manuf(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree,proto_item * block_item,proto_item * dcp_item,guint8 service_id _U_,gboolean is_response _U_)1231 dissect_PNDCP_Suboption_Manuf(tvbuff_t *tvb, int offset, packet_info *pinfo,
1232                             proto_tree *tree, proto_item *block_item, proto_item *dcp_item,
1233                             guint8 service_id _U_, gboolean is_response _U_)
1234 {
1235     guint16 block_length;
1236 
1237     offset = dissect_pn_uint8( tvb, offset, pinfo, tree, hf_pn_dcp_suboption_manuf, NULL);
1238 
1239     pn_append_info(pinfo, dcp_item, ", Manufacturer Specific");
1240     proto_item_append_text(block_item, "Manufacturer Specific");
1241 
1242     if (tvb_reported_length_remaining(tvb, offset)>0)
1243     {
1244         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);
1245         offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, block_length);
1246     }
1247     return offset;
1248 }
1249 
1250 
1251 /* dissect one DCP block */
1252 static int
dissect_PNDCP_Block(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree,proto_item * dcp_item,guint8 service_id,gboolean is_response)1253 dissect_PNDCP_Block(tvbuff_t *tvb, int offset, packet_info *pinfo,
1254                     proto_tree *tree, proto_item *dcp_item,
1255                     guint8 service_id, gboolean is_response)
1256 {
1257     guint8      option;
1258     proto_item *block_item;
1259     proto_tree *block_tree;
1260     int         ori_offset = offset;
1261 
1262     /* subtree for block */
1263     block_item = proto_tree_add_none_format(tree, hf_pn_dcp_block,
1264         tvb, offset, 0, "Block: ");
1265     block_tree = proto_item_add_subtree(block_item, ett_pn_dcp_block);
1266 
1267 
1268     offset = dissect_pn_uint8(tvb, offset, pinfo, block_tree, hf_pn_dcp_option, &option);
1269 
1270     if (option == PNDCP_OPTION_IP)
1271     {
1272         offset = dissect_PNDCP_Suboption_IP(tvb, offset, pinfo, block_tree, block_item, dcp_item, service_id, is_response);
1273     }
1274     else if (option == PNDCP_OPTION_DEVICE)
1275     {
1276         offset = dissect_PNDCP_Suboption_Device(tvb, offset, pinfo, block_tree, block_item, dcp_item, service_id, is_response);
1277     }
1278     else if (option == PNDCP_OPTION_DHCP)
1279     {
1280         offset = dissect_PNDCP_Suboption_DHCP(tvb, offset, pinfo, block_tree, block_item, dcp_item, service_id, is_response);
1281     }
1282     else if (option == PNDCP_OPTION_CONTROL)
1283     {
1284         offset = dissect_PNDCP_Suboption_Control(tvb, offset, pinfo, block_tree, block_item, dcp_item, service_id, is_response);
1285     }
1286     else if (option == PNDCP_OPTION_DEVICEINITIATIVE)
1287     {
1288         offset = dissect_PNDCP_Suboption_DeviceInitiative(tvb, offset, pinfo, block_tree, block_item, dcp_item, service_id, is_response);
1289     }
1290     else if (option == PNDCP_OPTION_ALLSELECTOR)
1291     {
1292         offset = dissect_PNDCP_Suboption_All(tvb, offset, pinfo, block_tree, block_item, dcp_item, service_id, is_response);
1293     }
1294     else if (PNDCP_OPTION_MANUF_X80 <= option && option <= PNDCP_OPTION_MANUF_XFE)
1295     {
1296         offset = dissect_PNDCP_Suboption_Manuf(tvb, offset, pinfo, block_tree, block_item, dcp_item, service_id, is_response);
1297     }
1298     else
1299     {
1300         pn_append_info(pinfo, dcp_item, ", Reserved");
1301         proto_item_append_text(block_item, "Reserved");
1302         /* there isn't a predefined suboption type for reserved option, rest of the block will be seen as padding */
1303     }
1304 
1305     proto_item_set_len(block_item, offset-ori_offset);
1306 
1307     if (((offset-ori_offset) & 1) && (tvb_reported_length_remaining(tvb, offset) > 0)) {
1308         /* we have an odd number of bytes in this block, add a padding byte */
1309         offset = dissect_pn_padding(tvb, offset, pinfo, tree, 1);
1310     }
1311 
1312     return offset;
1313 }
1314 
1315 
1316 /* dissect a whole DCP PDU */
1317 static void
dissect_PNDCP_PDU(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,proto_item * dcp_item)1318 dissect_PNDCP_PDU(tvbuff_t *tvb,
1319     packet_info *pinfo, proto_tree *tree, proto_item *dcp_item)
1320 {
1321     guint8    service_id;
1322     guint8    service_type;
1323     guint32   xid;
1324     guint16   response_delay;
1325     guint16   data_length;
1326     int       offset      = 0;
1327     gchar    *xid_str;
1328     gboolean  is_response = FALSE;
1329 
1330 
1331     offset = dissect_pn_uint8 (tvb, offset, pinfo, tree, hf_pn_dcp_service_id, &service_id);
1332     offset = dissect_pn_uint8 (tvb, offset, pinfo, tree, hf_pn_dcp_service_type, &service_type);
1333     proto_tree_add_item_ret_uint(tree, hf_pn_dcp_xid, tvb, offset, 4, ENC_BIG_ENDIAN, &xid);
1334     offset += 4;
1335     if (service_id == PNDCP_SERVICE_ID_IDENTIFY && service_type == PNDCP_SERVICE_TYPE_REQUEST) {
1336         /* multicast header */
1337         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_response_delay, &response_delay);
1338     } else {
1339         /* unicast header */
1340         offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_reserved16, NULL);
1341     }
1342     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_data_length, &data_length);
1343 
1344     switch (service_id) {
1345     case PNDCP_SERVICE_ID_GET:
1346         pn_append_info(pinfo, dcp_item, "Get");
1347         break;
1348     case PNDCP_SERVICE_ID_SET:
1349         pn_append_info(pinfo, dcp_item, "Set");
1350         break;
1351     case PNDCP_SERVICE_ID_IDENTIFY:
1352         pn_append_info(pinfo, dcp_item, "Ident");
1353         break;
1354     case PNDCP_SERVICE_ID_HELLO:
1355         pn_append_info(pinfo, dcp_item, "Hello");
1356         break;
1357     default:
1358         dissect_pn_undecoded(tvb, offset, pinfo, tree, tvb_captured_length_remaining(tvb, offset));
1359         return;
1360     }
1361 
1362     switch (service_type) {
1363     case PNDCP_SERVICE_TYPE_REQUEST:
1364         pn_append_info(pinfo, dcp_item, " Req");
1365         break;
1366     case PNDCP_SERVICE_TYPE_RESPONSE_SUCCESS:
1367         pn_append_info(pinfo, dcp_item, " Ok ");
1368         is_response = TRUE;
1369         break;
1370     case PNDCP_SERVICE_TYPE_RESPONSE_UNSUPPORTED:
1371         pn_append_info(pinfo, dcp_item, " unsupported");
1372         is_response = TRUE;
1373         break;
1374     default:
1375         dissect_pn_undecoded(tvb, offset, pinfo, tree, tvb_captured_length_remaining(tvb, offset));
1376         return;
1377     }
1378 
1379     xid_str = wmem_strdup_printf(pinfo->pool, ", Xid:0x%x", xid);
1380     pn_append_info(pinfo, dcp_item, xid_str);
1381 
1382     /* dissect a number of blocks (depending on the remaining length) */
1383     while(data_length) {
1384         int ori_offset = offset;
1385 
1386         if (service_id == PNDCP_SERVICE_ID_GET && service_type == PNDCP_SERVICE_TYPE_REQUEST) {
1387             /* Selectors */
1388             offset = dissect_PNDCP_Option(tvb, offset, pinfo,
1389                                  tree, dcp_item, hf_pn_dcp_option, TRUE /* append_col */);
1390         } else {
1391             offset = dissect_PNDCP_Block(tvb, offset, pinfo, tree, dcp_item, service_id, is_response);
1392         }
1393         /* prevent an infinite loop */
1394         if (offset <= ori_offset || data_length < (offset - ori_offset)) {
1395             proto_tree_add_expert(tree, pinfo, &ei_pn_dcp_block_parse_error,
1396                             tvb, ori_offset, tvb_captured_length_remaining(tvb, ori_offset));
1397             break;
1398         }
1399         data_length -= (offset - ori_offset);
1400     }
1401 }
1402 
1403 
1404 /* possibly dissect a PN-RT packet (frame ID must be in the appropriate range) */
1405 static gboolean
dissect_PNDCP_Data_heur(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)1406 dissect_PNDCP_Data_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1407     void *data)
1408 {
1409     /* the tvb will NOT contain the frame_id here, so get it from dissection data! */
1410     guint16     u16FrameID = GPOINTER_TO_UINT(data);
1411     proto_item *item;
1412     proto_tree *dcp_tree;
1413 
1414 
1415     /* frame id must be in valid range (acyclic Real-Time, DCP) */
1416     if (u16FrameID < FRAME_ID_DCP_HELLO || u16FrameID > FRAME_ID_DCP_IDENT_RES) {
1417         /* we are not interested in this packet */
1418         return FALSE;
1419     }
1420 
1421     col_set_str(pinfo->cinfo, COL_PROTOCOL, "PN-DCP");
1422     col_clear(pinfo->cinfo, COL_INFO);
1423 
1424     /* subtree for DCP */
1425     item = proto_tree_add_protocol_format(tree, proto_pn_dcp, tvb, 0, tvb_get_ntohs(tvb, 8) + 10,
1426                 "PROFINET DCP, ");
1427     dcp_tree = proto_item_add_subtree(item, ett_pn_dcp);
1428 
1429     /* dissect this PDU */
1430     dissect_PNDCP_PDU(tvb, pinfo, dcp_tree, item);
1431 
1432     return TRUE;
1433 }
1434 
1435 
1436 void
proto_register_pn_dcp(void)1437 proto_register_pn_dcp (void)
1438 {
1439     static hf_register_info hf[] = {
1440         { &hf_pn_dcp_service_id,
1441           { "ServiceID", "pn_dcp.service_id",
1442             FT_UINT8, BASE_DEC, VALS(pn_dcp_service_id), 0x0,
1443             NULL, HFILL }},
1444 
1445         { &hf_pn_dcp_service_type,
1446           { "ServiceType", "pn_dcp.service_type",
1447             FT_UINT8, BASE_DEC, VALS(pn_dcp_service_type), 0x0,
1448             NULL, HFILL }},
1449 
1450         { &hf_pn_dcp_xid,
1451           { "Xid", "pn_dcp.xid",
1452             FT_UINT32, BASE_HEX, NULL, 0x0,
1453             NULL, HFILL }},
1454 
1455         { &hf_pn_dcp_reserved8,
1456           { "Reserved", "pn_dcp.reserved8",
1457             FT_UINT8, BASE_DEC, NULL, 0x0,
1458             NULL, HFILL }},
1459 
1460         { &hf_pn_dcp_reserved16,
1461           { "Reserved", "pn_dcp.reserved16",
1462             FT_UINT16, BASE_DEC, NULL, 0x0,
1463             NULL, HFILL }},
1464 
1465         { &hf_pn_dcp_response_delay,
1466           { "ResponseDelay", "pn_dcp.response_delay",
1467             FT_UINT16, BASE_DEC, NULL, 0x0,
1468             NULL, HFILL }},
1469 
1470         { &hf_pn_dcp_data_length,
1471           { "DCPDataLength", "pn_dcp.data_length",
1472             FT_UINT16, BASE_DEC, NULL, 0x0,
1473             NULL, HFILL }},
1474 
1475         { &hf_pn_dcp_block_length,
1476           { "DCPBlockLength", "pn_dcp.block_length",
1477             FT_UINT16, BASE_DEC, NULL, 0x0,
1478             NULL, HFILL }},
1479 
1480         { &hf_pn_dcp_option,
1481           { "Option", "pn_dcp.option",
1482             FT_UINT8, BASE_DEC|BASE_RANGE_STRING, RVALS(pn_dcp_option), 0x0,
1483             NULL, HFILL }},
1484 
1485 #if 0
1486         { &hf_pn_dcp_suboption,
1487           { "Suboption", "pn_dcp.suboption",
1488             FT_UINT8, BASE_DEC, NULL, 0x0,
1489             NULL, HFILL }},
1490 #endif
1491 
1492         { &hf_pn_dcp_block_error,
1493           { "BlockError", "pn_dcp.block_error",
1494             FT_UINT8, BASE_DEC, VALS(pn_dcp_block_error), 0x0,
1495             NULL, HFILL }},
1496 
1497         { &hf_pn_dcp_block,
1498           { "Block", "pn_dcp.block",
1499             FT_NONE, BASE_NONE, NULL, 0x0,
1500             NULL, HFILL }},
1501 
1502         { &hf_pn_dcp_block_info,
1503           { "BlockInfo", "pn_dcp.block_info",
1504             FT_UINT16, BASE_DEC|BASE_RANGE_STRING, RVALS(pn_dcp_block_info), 0x0,
1505             NULL, HFILL }},
1506 
1507         { &hf_pn_dcp_block_qualifier,
1508           { "BlockQualifier", "pn_dcp.block_qualifier",
1509             FT_UINT16, BASE_DEC, VALS(pn_dcp_block_qualifier), 0x0,
1510             NULL, HFILL }},
1511 
1512         { &hf_pn_dcp_blockqualifier_r2f,
1513           { "BlockQualifier: ResettoFactory", "pn_dcp.block_qualifier_reset",
1514             FT_UINT16, BASE_DEC, VALS(pn_dcp_BlockQualifier), 0x0,
1515             NULL, HFILL }},
1516 
1517         { &hf_pn_dcp_blockqualifier,
1518           { "BlockQualifier: ResetFactorySettings", "pn_dcp.block_qualifier_reset",
1519             FT_UINT16, BASE_DEC, VALS(pn_dcp_suboption_other), 0x0,
1520             NULL, HFILL }},
1521 
1522         { &hf_pn_dcp_suboption_ip,
1523           { "Suboption", "pn_dcp.suboption_ip",
1524             FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_ip), 0x0,
1525             NULL, HFILL }},
1526 
1527         { &hf_pn_dcp_suboption_ip_block_info,
1528           { "BlockInfo", "pn_dcp.suboption_ip_block_info",
1529             FT_UINT16, BASE_DEC, VALS(pn_dcp_suboption_ip_block_info), 0x0,
1530             NULL, HFILL }},
1531 
1532         { &hf_pn_dcp_suboption_ip_mac_address,
1533           { "MAC Address", "pn_dcp.suboption_ip_mac_address",
1534              FT_ETHER, BASE_NONE, NULL, 0x0,
1535              NULL, HFILL }},
1536 
1537         { &hf_pn_dcp_suboption_ip_ip,
1538           { "IPaddress", "pn_dcp.suboption_ip_ip",
1539             FT_IPv4, BASE_NONE, NULL, 0x0,
1540             NULL, HFILL }},
1541 
1542         { &hf_pn_dcp_suboption_ip_subnetmask,
1543           { "Subnetmask", "pn_dcp.suboption_ip_subnetmask",
1544             FT_IPv4, BASE_NONE, NULL, 0x0,
1545             NULL, HFILL }},
1546 
1547         { &hf_pn_dcp_suboption_ip_standard_gateway,
1548           { "StandardGateway", "pn_dcp.suboption_ip_standard_gateway",
1549             FT_IPv4, BASE_NONE, NULL, 0x0,
1550             NULL, HFILL }},
1551 
1552         { &hf_pn_dcp_suboption_device,
1553           { "Suboption", "pn_dcp.suboption_device",
1554             FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_device), 0x0,
1555             NULL, HFILL }},
1556 
1557         { &hf_pn_dcp_suboption_device_typeofstation,
1558           { "DeviceVendorValue", "pn_dcp.suboption_device_devicevendorvalue",
1559             FT_STRING, BASE_NONE, NULL, 0x0,
1560             NULL, HFILL }},
1561 
1562         { &hf_pn_dcp_suboption_device_nameofstation,
1563           { "NameOfStation", "pn_dcp.suboption_device_nameofstation",
1564             FT_STRING, BASE_NONE, NULL, 0x0,
1565             NULL, HFILL }},
1566 
1567         { &hf_pn_dcp_suboption_vendor_id,
1568           { "VendorID", "pn_dcp.suboption_vendor_id",
1569             FT_UINT16, BASE_HEX, NULL, 0x0,
1570             NULL, HFILL }},
1571 
1572         { &hf_pn_dcp_suboption_device_id,
1573           { "DeviceID", "pn_dcp.suboption_device_id",
1574             FT_UINT16, BASE_HEX, NULL, 0x0,
1575             NULL, HFILL }},
1576 
1577         { &hf_pn_dcp_suboption_device_role,
1578           { "DeviceRoleDetails", "pn_dcp.suboption_device_role",
1579             FT_UINT8, BASE_HEX, NULL, 0x0,
1580             NULL, HFILL }},
1581 
1582         { &hf_pn_dcp_suboption_device_aliasname,
1583           { "AliasName", "pn_dcp.suboption_device_aliasname",
1584             FT_STRING, BASE_NONE, NULL, 0x0,
1585             NULL, HFILL }},
1586 
1587         { &hf_pn_dcp_suboption_device_instance_high,
1588           { "DeviceInstanceHigh", "pn_dcp.suboption_device_instance",
1589             FT_UINT8, BASE_HEX, NULL, 0x0,
1590             NULL, HFILL }},
1591 
1592         { &hf_pn_dcp_suboption_device_instance_low,
1593           { "DeviceInstanceLow", "pn_dcp.suboption_device_instance",
1594             FT_UINT8, BASE_HEX, NULL, 0x0,
1595             NULL, HFILL }},
1596 
1597         { &hf_pn_dcp_suboption_device_oem_ven_id,
1598           { "OEMVendorID", "pn_dcp.suboption_device_oem_ven_id",
1599             FT_UINT16, BASE_HEX, NULL, 0x0,
1600             NULL, HFILL }},
1601 
1602         { &hf_pn_dcp_suboption_device_oem_dev_id,
1603           { "OEMDeviceID", "pn_dcp.suboption_device_oem_dev_id",
1604             FT_UINT16, BASE_HEX, NULL, 0x0,
1605             NULL, HFILL }},
1606 
1607         { &hf_pn_dcp_rsi_properties_value,
1608           { "RsiPropertiesValue", "pn_dcp.suboption_device_rsi_properties_value",
1609             FT_UINT16, BASE_HEX, 0, 0x0,
1610             NULL, HFILL } },
1611 
1612         { &hf_pn_dcp_rsi_properties_value_bit0,
1613           { "IP Stack", "pn_dcp.suboption_device_rsi_properties_value.bit0",
1614             FT_BOOLEAN, 16, TFS(&pn_dcp_rsi_properties_value_bit), 0x0001,
1615             NULL, HFILL } },
1616 
1617         { &hf_pn_dcp_rsi_properties_value_bit1,
1618           { "CLRPC Interface", "pn_dcp.suboption_device_rsi_properties_value.bit1",
1619             FT_BOOLEAN, 16, TFS(&pn_dcp_rsi_properties_value_bit), 0x0002,
1620             NULL, HFILL } },
1621 
1622         { &hf_pn_dcp_rsi_properties_value_bit2,
1623           { "RSI AR Interface", "pn_dcp.suboption_device_rsi_properties_value.bit2",
1624             FT_BOOLEAN, 16, TFS(&pn_dcp_rsi_properties_value_bit), 0x0004,
1625             NULL, HFILL } },
1626 
1627         { &hf_pn_dcp_rsi_properties_value_bit3,
1628           { "RSI AR Read Implicit Interface", "pn_dcp.suboption_device_rsi_properties_value.bit3",
1629             FT_BOOLEAN, 16, TFS(&pn_dcp_rsi_properties_value_bit), 0x0008,
1630             NULL, HFILL } },
1631 
1632         { &hf_pn_dcp_rsi_properties_value_bit4,
1633           { "RSI CIM Interface", "pn_dcp.suboption_device_rsi_properties_value.bit4",
1634             FT_BOOLEAN, 16, TFS(&pn_dcp_rsi_properties_value_bit), 0x0010,
1635             NULL, HFILL } },
1636 
1637         { &hf_pn_dcp_rsi_properties_value_bit5,
1638           { "RSI CIM Read Implicit Interface", "pn_dcp.suboption_device_rsi_properties_value.bit5",
1639             FT_BOOLEAN, 16, TFS(&pn_dcp_rsi_properties_value_bit), 0x0020,
1640             NULL, HFILL } },
1641 
1642         { &hf_pn_dcp_rsi_properties_value_otherbits,
1643           { "RsiPropertiesValue.Bit6-15", "pn_dcp.suboption_device_rsi_properties_value.otherbits",
1644             FT_UINT16, BASE_HEX, NULL, 0xFFC0,
1645             NULL, HFILL } },
1646 
1647         { &hf_pn_dcp_suboption_dhcp,
1648           { "Suboption", "pn_dcp.suboption_dhcp",
1649             FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_dhcp), 0x0,
1650             NULL, HFILL }},
1651 
1652         { &hf_pn_dcp_suboption_dhcp_option_code,
1653           { "Option-Code", "pn_dcp.suboption_dhcp_option_code",
1654             FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_dhcp), 0x0,
1655             NULL, HFILL }},
1656 
1657         { &hf_pn_dcp_suboption_dhcp_arbitrary_client_id,
1658           { "Client ID", "pn_dcp.suboption_dhcp_client_id",
1659             FT_STRING, BASE_NONE, NULL, 0x0,
1660             NULL, HFILL }},
1661 
1662         { &hf_pn_dcp_suboption_dhcp_parameter_length,
1663           { "DHCP Parameter Length", "pn_dcp.suboption_dhcp_parameter_length",
1664             FT_UINT8, BASE_HEX, NULL, 0x0,
1665             NULL, HFILL } },
1666 
1667         { &hf_pn_dcp_suboption_dhcp_parameter_data,
1668           { "DHCP Parameter Data", "pn_dcp.suboption_dhcp_parameter_data",
1669             FT_UINT8, BASE_HEX, NULL, 0x0,
1670             NULL, HFILL } },
1671 
1672         { &hf_pn_dcp_suboption_dhcp_control_parameter_data,
1673           { "DHCP Parameter Data", "pn_dcp.suboption_dhcp_parameter_data",
1674             FT_UINT8, BASE_HEX, VALS(pn_dcp_suboption_dhcp_control_parameter_data), 0x0,
1675             NULL, HFILL } },
1676 
1677         { &hf_pn_dcp_suboption_control,
1678           { "Suboption", "pn_dcp.suboption_control",
1679             FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_control), 0x0,
1680             NULL, HFILL }},
1681 
1682         { &hf_pn_dcp_suboption_control_option,
1683           { "Option", "pn_dcp.suboption_control_option",
1684             FT_UINT8, BASE_DEC|BASE_RANGE_STRING, RVALS(pn_dcp_option), 0x0,
1685             NULL, HFILL }},
1686 
1687         { &hf_pn_dcp_suboption_control_signal_value,
1688           { "SignalValue", "pn_dcp.suboption_control_signal_value",
1689             FT_UINT16, BASE_HEX, VALS(pn_dcp_suboption_control_signal_value), 0x0,
1690             NULL, HFILL } },
1691 
1692         { &hf_pn_dcp_suboption_deviceinitiative,
1693           { "Suboption", "pn_dcp.suboption_deviceinitiative",
1694             FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_deviceinitiative), 0x0,
1695             NULL, HFILL }},
1696 
1697         { &hf_pn_dcp_deviceinitiative_value,
1698           { "DeviceInitiativeValue", "pn_dcp.deviceinitiative_value",
1699             FT_UINT16, BASE_DEC, VALS(pn_dcp_deviceinitiative_value), 0x0,
1700             NULL, HFILL }},
1701 
1702         { &hf_pn_dcp_suboption_all,
1703           { "Suboption", "pn_dcp.suboption_all",
1704             FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_all), 0x0,
1705             NULL, HFILL }},
1706 
1707         { &hf_pn_dcp_suboption_manuf,
1708           { "Suboption", "pn_dcp.suboption_manuf",
1709             FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_manuf), 0x0,
1710             NULL, HFILL }},
1711 
1712     };
1713 
1714     static gint *ett[] = {
1715         &ett_pn_dcp,
1716         &ett_pn_dcp_block,
1717         &ett_pn_dcp_rsi_properties_value
1718     };
1719 
1720     static ei_register_info ei[] = {
1721         { &ei_pn_dcp_block_parse_error, { "pn_dcp.block_error.parse", PI_PROTOCOL, PI_ERROR, "parse error", EXPFILL }},
1722         { &ei_pn_dcp_block_error_unknown, { "pn_dcp.block_error.unknown", PI_RESPONSE_CODE, PI_CHAT, "Unknown", EXPFILL }},
1723         { &ei_pn_dcp_ip_conflict, { "pn_dcp.ip_conflict", PI_RESPONSE_CODE, PI_NOTE, "IP address conflict detected!", EXPFILL }},
1724     };
1725 
1726     expert_module_t* expert_pn_dcp;
1727 
1728     proto_pn_dcp = proto_register_protocol ("PROFINET DCP", "PN-DCP", "pn_dcp");
1729     proto_register_field_array (proto_pn_dcp, hf, array_length (hf));
1730     proto_register_subtree_array (ett, array_length (ett));
1731     expert_pn_dcp = expert_register_protocol(proto_pn_dcp);
1732     expert_register_field_array(expert_pn_dcp, ei, array_length(ei));
1733 }
1734 
1735 void
proto_reg_handoff_pn_dcp(void)1736 proto_reg_handoff_pn_dcp (void)
1737 {
1738     /* register ourself as an heuristic pn-rt payload dissector */
1739     heur_dissector_add("pn_rt", dissect_PNDCP_Data_heur, "PROFINET DCP IO", "pn_dcp_pn_rt", proto_pn_dcp, HEURISTIC_ENABLE);
1740 }
1741 
1742 /*
1743  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1744  *
1745  * Local variables:
1746  * c-basic-offset: 4
1747  * tab-width: 8
1748  * indent-tabs-mode: nil
1749  * End:
1750  *
1751  * vi: set shiftwidth=4 tabstop=8 expandtab:
1752  * :indentSize=4:tabSize=8:noTabs=true:
1753  */
1754