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