Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-devicenet.c
blob5e0cf1d940a69b02f7593a020783ee82534d821c
1 /* packet-devicenet.c
2 * Routines for dissection of DeviceNet
3 * DeviceNet Home: www.odva.org
5 * This dissector includes items from:
6 * CIP Volume 3: DeviceNet Adaptation of CIP, Edition 1.14
8 * Michael Mann
9 * Erik Ivarsson <eriki@student.chalmers.se>
10 * Hans-Jorgen Gunnarsson <hag@hms.se>
11 * Copyright 2012
13 * Wireshark - Network traffic analyzer
14 * By Gerald Combs <gerald@wireshark.org>
15 * Copyright 1998 Gerald Combs
17 * SPDX-License-Identifier: GPL-2.0-or-later
19 #include "config.h"
21 #include <epan/packet.h>
22 #include <epan/uat.h>
23 #include <epan/prefs.h>
24 #include <epan/expert.h>
25 #include <epan/address_types.h>
26 #include <epan/to_str.h>
28 #include "packet-cip.h"
29 #include "packet-socketcan.h"
31 void proto_register_devicenet(void);
32 void proto_reg_handoff_devicenet(void);
34 static dissector_handle_t devicenet_handle;
36 #define DEVICENET_CANID_MASK CAN_SFF_MASK
37 #define MESSAGE_GROUP_1_ID 0x03FF
38 #define MESSAGE_GROUP_1_MSG_MASK 0x03C0
39 #define MESSAGE_GROUP_1_MAC_ID_MASK 0x003F
41 #define MESSAGE_GROUP_2_ID 0x05FF
42 #define MESSAGE_GROUP_2_MSG_MASK 0x0007
43 #define MESSAGE_GROUP_2_MAC_ID_MASK 0x01F8
45 #define MESSAGE_GROUP_3_ID 0x07BF
46 #define MESSAGE_GROUP_3_MSG_MASK 0x01C0
47 #define MESSAGE_GROUP_3_MAC_ID_MASK 0x3F
48 #define MESSAGE_GROUP_3_FRAG_MASK 0x80
49 #define MESSAGE_GROUP_3_XID_MASK 0x40
51 #define MESSAGE_GROUP_4_ID 0x07EF
52 #define MESSAGE_GROUP_4_MSG_MASK 0x3F
54 static int proto_devicenet;
56 static int hf_devicenet_can_id;
57 static int hf_devicenet_src_mac_id;
58 static int hf_devicenet_data;
59 static int hf_devicenet_grp_msg1_id;
60 static int hf_devicenet_grp_msg2_id;
61 static int hf_devicenet_grp_msg3_id;
62 static int hf_devicenet_grp_msg3_frag;
63 static int hf_devicenet_grp_msg3_xid;
64 static int hf_devicenet_grp_msg3_dest_mac_id;
65 static int hf_devicenet_grp_msg4_id;
66 static int hf_devicenet_rr_bit;
67 static int hf_devicenet_service_code;
68 static int hf_devicenet_connection_id;
69 static int hf_devicenet_open_exp_src_message_id;
70 static int hf_devicenet_open_exp_dest_message_id;
71 static int hf_devicenet_open_exp_msg_req_body_format;
72 static int hf_devicenet_open_exp_msg_actual_body_format;
73 static int hf_devicenet_open_exp_group_select;
74 static int hf_devicenet_open_exp_msg_reserved;
75 static int hf_devicenet_dup_mac_id_rr_bit;
76 static int hf_devicenet_dup_mac_id_physical_port_number;
77 static int hf_devicenet_dup_mac_id_serial_number;
78 static int hf_devicenet_dup_mac_id_vendor;
79 static int hf_devicenet_comm_fault_rsv;
80 static int hf_devicenet_comm_fault_match;
81 static int hf_devicenet_comm_fault_value;
82 static int hf_devicenet_offline_ownership_reserved;
83 static int hf_devicenet_offline_ownership_client_mac_id;
84 static int hf_devicenet_offline_ownership_allocate;
85 static int hf_devicenet_vendor;
86 static int hf_devicenet_serial_number;
87 static int hf_devicenet_class8;
88 static int hf_devicenet_class16;
89 static int hf_devicenet_instance8;
90 static int hf_devicenet_instance16;
91 static int hf_devicenet_attribute;
92 static int hf_devicenet_fragment_type;
93 static int hf_devicenet_fragment_count;
95 static int ett_devicenet;
96 static int ett_devicenet_can;
97 static int ett_devicenet_contents;
98 static int ett_devicenet_8_8;
99 static int ett_devicenet_8_16;
100 static int ett_devicenet_16_8;
101 static int ett_devicenet_16_16;
103 static expert_field ei_devicenet_invalid_service;
104 static expert_field ei_devicenet_invalid_can_id;
105 static expert_field ei_devicenet_invalid_msg_id;
106 static expert_field ei_devicenet_frag_not_supported;
108 static int devicenet_address_type = -1;
110 enum node_behavior {
111 NODE_BEHAVIOR_8_8 = 0,
112 NODE_BEHAVIOR_8_16 = 1,
113 NODE_BEHAVIOR_16_8 = 2,
114 NODE_BEHAVIOR_16_16 = 3
117 /* UAT entry structure. */
118 typedef struct {
119 unsigned mac_id;
120 enum node_behavior behavior;
122 } uat_devicenet_record_t;
124 static uat_devicenet_record_t *uat_devicenet_records;
125 static uat_t *devicenet_uat;
126 static unsigned num_devicenet_records_uat;
128 static bool uat_devicenet_record_update_cb(void* r, char** err) {
129 uat_devicenet_record_t* rec = (uat_devicenet_record_t *)r;
131 if (rec->mac_id > 63) {
132 *err = g_strdup("MAC ID must be between 0-63");
133 return false;
135 return true;
138 UAT_DEC_CB_DEF(uat_devicenet_records, mac_id, uat_devicenet_record_t)
139 UAT_VS_DEF(uat_devicenet_records, behavior, uat_devicenet_record_t, enum node_behavior, NODE_BEHAVIOR_8_8, "string")
141 #if 0
142 static const enum_val_t bodytype_devicenet_protocol_options[] = {
143 { "eightovereight", "8/8", 0 },
144 { "eightoversixteen", "8/16", 1 },
145 { "sixteenovereight", "16/8", 2 },
146 { "sixteenoversixteen", "16/16", 3 },
147 { NULL, NULL, 0 }
149 #endif
151 #define SC_OPEN_EXPLICIT_MESSAGE 0x4B
152 #define SC_CLOSE_EXPLICIT_MESSAGE 0x4C
153 #define SC_DEVICE_HEARTBEAT_MESSAGE 0x4D
154 #define SC_DEVICE_SHUTOWN_MESSAGE 0x4E
156 static const value_string devicenet_service_code_vals[] = {
157 GENERIC_SC_LIST
159 { SC_OPEN_EXPLICIT_MESSAGE, "Open Explicit Message Connection Request" },
160 { SC_CLOSE_EXPLICIT_MESSAGE, "Close Connection Request" },
161 { SC_DEVICE_HEARTBEAT_MESSAGE, "Device Heartbeat Message" },
162 { SC_DEVICE_SHUTOWN_MESSAGE, "Device Shutdown Message" },
163 { 0, NULL }
166 static const value_string devicenet_grp_msg1_vals[] = {
167 { 0x0300, "Slave's I/O Multicast Poll Response" },
168 { 0x0340, "Slave's I/O Change of State or Cyclic Message" },
169 { 0x0380, "Slave's I/O Bit-Strobe Response Message" },
170 { 0x03C0, "Slave's I/O Poll Response or COS/Cyclic Ack Message" },
171 { 0, NULL }
174 static const value_string devicenet_grp_msg2_vals[] = {
175 { 0x00, "Master's I/O Bit-Strobe Command Message" },
176 { 0x01, "Master's I/O Multicast Poll Group ID" },
177 { 0x02, "Master's Change of State or Cyclic Acknowledge Message" },
178 { 0x03, "Slave's Explicit/Unconnected Response Messages" },
179 { 0x04, "Master's Explicit Request Messages" },
180 { 0x05, "Master's I/O Poll Command/COS/Cyclic Messages" },
181 { 0x06, "Group 2 Only Unconnected Explicit Request Messages" },
182 { 0x07, "Duplicate MAC ID Check Messages" },
183 { 0, NULL }
186 static const value_string devicenet_grp_msg3_vals[] = {
187 { 0x000, "Group 3 Message" },
188 { 0x040, "Group 3 Message" },
189 { 0x080, "Group 3 Message" },
190 { 0x0C0, "Group 3 Message" },
191 { 0x100, "Group 3 Message" },
192 { 0x140, "Unconnected Explicit Response Message" },
193 { 0x180, "Unconnected Explicit Request Message" },
194 { 0x1C0, "Invalid Group 3 Message" },
195 { 0, NULL }
198 #define GRP4_COMM_FAULT_RESPONSE 0x2C
199 #define GRP4_COMM_FAULT_REQUEST 0x2D
200 #define GRP4_OFFLINE_OWNER_RESPONSE 0x2E
201 #define GRP4_OFFLINE_OWNER_REQUEST 0x2F
203 static const value_string devicenet_grp_msg4_vals[] = {
204 { GRP4_COMM_FAULT_RESPONSE, "Communication Faulted Response Message" },
205 { GRP4_COMM_FAULT_REQUEST, "Communication Faulted Request Message" },
206 { GRP4_OFFLINE_OWNER_RESPONSE, "Offline Ownership Response Message" },
207 { GRP4_OFFLINE_OWNER_REQUEST, "Offline Ownership Request Message" },
208 { 0, NULL }
211 static const value_string devicenet_message_body_format_vals[] = {
212 { 0x00, "DeviceNet 8/8. Class ID = 8 bit integer, Instance ID = 8 bit integer" },
213 { 0x01, "DeviceNet 8/16. Class ID = 8 bit integer, Instance ID = 16 bit integer" },
214 { 0x02, "DeviceNet 16/16. Class ID = 16 bit integer. Instance ID = 16 bit integer" },
215 { 0x03, "DeviceNet 16/8. Class ID = 16 bit integer. Instance ID = 8 bit integer" },
216 { 0x04, "CIP Path. The addressing size is variable and is provided as a Packed EPATH on each request" },
217 { 0x05, "Reserved by DeviceNet" },
218 { 0x06, "Reserved by DeviceNet" },
219 { 0x07, "Reserved by DeviceNet" },
220 { 0x08, "Reserved by DeviceNet" },
221 { 0x09, "Reserved by DeviceNet" },
222 { 0x0A, "Reserved by DeviceNet" },
223 { 0x0B, "Reserved by DeviceNet" },
224 { 0x0C, "Reserved by DeviceNet" },
225 { 0x0D, "Reserved by DeviceNet" },
226 { 0x0E, "Reserved by DeviceNet" },
227 { 0x0F, "Reserved by DeviceNet" },
228 { 0, NULL }
231 static const value_string devicenet_group_select_vals[] = {
232 { 0x00, "Message Group 1" },
233 { 0x01, "Message Group 2" },
234 { 0x02, "Reserved" },
235 { 0x03, "Message Group 3" },
236 { 0x04, "Reserved by DeviceNet" },
237 { 0x05, "Reserved by DeviceNet" },
238 { 0x06, "Reserved by DeviceNet" },
239 { 0x07, "Reserved by DeviceNet" },
240 { 0x08, "Reserved by DeviceNet" },
241 { 0x09, "Reserved by DeviceNet" },
242 { 0x0A, "Reserved by DeviceNet" },
243 { 0x0B, "Reserved by DeviceNet" },
244 { 0x0C, "Reserved by DeviceNet" },
245 { 0x0D, "Reserved by DeviceNet" },
246 { 0x0E, "Reserved by DeviceNet" },
247 { 0x0F, "Reserved by Node Ping" },
248 { 0, NULL }
251 static const value_string devicenet_fragmented_message_type_vals[] = {
252 { 0, "First Fragment" },
253 { 1, "Middle fragment" },
254 { 2, "Last fragment" },
255 { 3, "Fragment Acknowledge" },
256 { 0, NULL }
259 #if 0
260 static const value_string devicenet_io_attribute_vals[] = {
261 {0x01, "Vendor ID"},
262 {0x02, "Device Type"},
263 {0x03, "Product Code"},
264 {0x04, "Revision"},
265 {0x05, "Status"},
266 {0x06, "Serial Number"},
267 {0x07, "Product Name"},
268 { 0, NULL }
270 #endif
272 static int body_type_8_over_8_dissection(uint8_t data_length, proto_tree *devicenet_tree,
273 tvbuff_t *tvb, packet_info *pinfo _U_, int offset)
275 uint16_t class_id, instance, attribute;
276 const attribute_info_t* att_info;
277 int start_offset = offset, length;
278 proto_item* ti;
280 devicenet_tree = proto_tree_add_subtree(devicenet_tree, tvb, offset, -1, ett_devicenet_8_8, NULL, "DeviceNet 8/8");
282 proto_tree_add_item(devicenet_tree, hf_devicenet_class8, tvb, offset, 1, ENC_LITTLE_ENDIAN);
283 class_id = tvb_get_uint8(tvb, offset);
284 offset++;
286 proto_tree_add_item(devicenet_tree, hf_devicenet_instance8, tvb, offset, 1, ENC_LITTLE_ENDIAN);
287 instance = tvb_get_uint8(tvb, offset);
289 offset++;
290 if (data_length > 3)
292 attribute = tvb_get_uint8(tvb, offset);
293 ti = proto_tree_add_item(devicenet_tree, hf_devicenet_attribute, tvb, offset, 1, ENC_LITTLE_ENDIAN);
294 att_info = cip_get_attribute(class_id, instance, attribute);
296 if (att_info != NULL)
297 proto_item_append_text(ti, " (%s)", att_info->text);
299 offset++;
302 if (data_length > 4)
304 length = offset-start_offset;
305 proto_tree_add_item(devicenet_tree, hf_devicenet_data, tvb, offset, length, ENC_NA);
306 offset += length;
308 return offset;
311 static int body_type_8_over_16_dissection(uint8_t data_length, proto_tree *devicenet_tree,
312 tvbuff_t *tvb, packet_info *pinfo _U_, int offset)
314 uint16_t class_id, instance, attribute;
315 const attribute_info_t* att_info;
316 proto_item* ti;
318 devicenet_tree = proto_tree_add_subtree(devicenet_tree, tvb, offset, -1, ett_devicenet_8_16, NULL, "DeviceNet 8/16");
320 proto_tree_add_item(devicenet_tree, hf_devicenet_class8, tvb, offset, 1, ENC_LITTLE_ENDIAN);
321 class_id = tvb_get_uint8(tvb, offset);
322 offset++;
324 proto_tree_add_item(devicenet_tree, hf_devicenet_instance16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
325 instance = tvb_get_letohs(tvb, offset);
327 if (data_length > 4)
329 attribute = tvb_get_uint8(tvb, offset);
330 ti = proto_tree_add_item(devicenet_tree, hf_devicenet_attribute, tvb, offset, 1, ENC_LITTLE_ENDIAN);
331 att_info = cip_get_attribute(class_id, instance, attribute);
333 if (att_info != NULL)
334 proto_item_append_text(ti, " (%s)", att_info->text);
336 offset++;
339 return offset;
342 static int body_type_16_over_8_dissection(uint8_t data_length, proto_tree *devicenet_tree, tvbuff_t *tvb,
343 packet_info *pinfo _U_, int offset)
345 uint16_t class_id, instance, attribute;
346 const attribute_info_t* att_info;
347 proto_item* ti;
349 devicenet_tree = proto_tree_add_subtree(devicenet_tree, tvb, offset, -1, ett_devicenet_16_8, NULL, "DeviceNet 16/8");
351 proto_tree_add_item(devicenet_tree, hf_devicenet_class16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
352 class_id = tvb_get_letohs(tvb, offset);
353 offset += 2;
355 proto_tree_add_item(devicenet_tree, hf_devicenet_instance8, tvb, offset, 1, ENC_LITTLE_ENDIAN);
356 instance = tvb_get_uint8(tvb, offset);
357 offset++;
359 if (data_length > 4)
361 attribute = tvb_get_uint8(tvb, offset);
362 ti = proto_tree_add_item(devicenet_tree, hf_devicenet_attribute, tvb, offset, 1, ENC_LITTLE_ENDIAN);
363 att_info = cip_get_attribute(class_id, instance, attribute);
365 if (att_info != NULL)
366 proto_item_append_text(ti, " (%s)", att_info->text);
368 offset++;
371 return offset;
374 static int body_type_16_over_16_dissection(uint8_t data_length, proto_tree *devicenet_tree, tvbuff_t *tvb,
375 packet_info *pinfo _U_, int offset)
377 uint16_t class_id, instance, attribute;
378 const attribute_info_t* att_info;
379 proto_item* ti;
381 devicenet_tree = proto_tree_add_subtree(devicenet_tree, tvb, offset, 4, ett_devicenet_16_16, NULL, "DeviceNet 16/16");
383 proto_tree_add_item(devicenet_tree, hf_devicenet_class16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
384 class_id = tvb_get_letohs(tvb, offset);
385 offset += 2;
387 proto_tree_add_item(devicenet_tree, hf_devicenet_instance16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
388 instance = tvb_get_letohs(tvb, offset);
389 offset+=2;
391 if (data_length > 5)
393 attribute = tvb_get_uint8(tvb, offset);
394 ti = proto_tree_add_item(devicenet_tree, hf_devicenet_attribute, tvb, offset, 1, ENC_LITTLE_ENDIAN);
395 att_info = cip_get_attribute(class_id, instance, attribute);
397 if (att_info != NULL)
398 proto_item_append_text(ti, " (%s)", att_info->text);
400 offset++;
403 return offset;
406 static int dissect_devicenet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
408 proto_item *ti, *can_id_item,
409 *msg_id_item, *service_item;
410 proto_tree *devicenet_tree, *can_tree, *content_tree;
412 int offset = 0;
413 uint16_t message_id;
414 uint32_t data_length = tvb_reported_length(tvb);
415 uint8_t source_mac;
416 struct can_info can_info;
417 uint8_t service_rr;
418 uint8_t *src_address, *dest_address;
420 DISSECTOR_ASSERT(data);
421 can_info = *((struct can_info*)data);
423 if (can_info.id & (CAN_ERR_FLAG | CAN_RTR_FLAG | CAN_EFF_FLAG))
425 /* Error, RTR and frames with extended ids are not for us. */
426 return 0;
429 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DeviceNet");
431 ti = proto_tree_add_item(tree, proto_devicenet, tvb, offset, -1, ENC_NA);
432 devicenet_tree = proto_item_add_subtree(ti, ett_devicenet);
434 can_tree = proto_tree_add_subtree_format(devicenet_tree, tvb, 0, 0, ett_devicenet_can, NULL, "CAN Identifier: 0x%04x", can_info.id);
435 can_id_item = proto_tree_add_uint(can_tree, hf_devicenet_can_id, tvb, 0, 0, can_info.id);
436 proto_item_set_generated(can_id_item);
439 * Message group 1
441 if ( can_info.id <= MESSAGE_GROUP_1_ID )
443 ti = proto_tree_add_uint(can_tree, hf_devicenet_grp_msg1_id, tvb, 0, 0, can_info.id);
444 proto_item_set_generated(ti);
445 ti = proto_tree_add_uint(can_tree, hf_devicenet_src_mac_id, tvb, 0, 0, can_info.id & MESSAGE_GROUP_1_MAC_ID_MASK);
446 proto_item_set_generated(ti);
448 /* Set source address */
449 src_address = (uint8_t*)wmem_alloc(pinfo->pool, 1);
450 *src_address = (uint8_t)(can_info.id & MESSAGE_GROUP_1_MAC_ID_MASK);
451 set_address(&pinfo->src, devicenet_address_type, 1, (const void*)src_address);
453 message_id = can_info.id & MESSAGE_GROUP_1_MSG_MASK;
454 col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(message_id, devicenet_grp_msg1_vals, "Other Group 1 Message"));
456 proto_tree_add_item(devicenet_tree, hf_devicenet_data, tvb, offset, data_length, ENC_NA);
459 * Message group 2
461 else if (can_info.id <= MESSAGE_GROUP_2_ID )
463 ti = proto_tree_add_uint(can_tree, hf_devicenet_grp_msg2_id, tvb, 0, 0, can_info.id);
464 proto_item_set_generated(ti);
466 /* create display subtree for the protocol */
467 message_id = can_info.id & MESSAGE_GROUP_2_MSG_MASK;
468 col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(message_id, devicenet_grp_msg2_vals, "Unknown"));
470 ti = proto_tree_add_uint(can_tree, hf_devicenet_src_mac_id, tvb, 0, 0, (can_info.id & MESSAGE_GROUP_2_MAC_ID_MASK) >> 3);
471 proto_item_set_generated(ti);
473 /* Set source address */
474 src_address = (uint8_t*)wmem_alloc(pinfo->pool, 1);
475 *src_address = (uint8_t)((can_info.id & MESSAGE_GROUP_2_MAC_ID_MASK) >> 3);
476 set_address(&pinfo->src, devicenet_address_type, 1, (const void*)src_address);
478 content_tree = proto_tree_add_subtree(devicenet_tree, tvb, offset, -1, ett_devicenet_contents, NULL, "Contents");
480 switch (message_id)
482 case 0x0:
483 case 0x1:
484 case 0x2:
485 case 0x3:
486 case 0x4:
487 case 0x5:
488 proto_tree_add_item(content_tree, hf_devicenet_data, tvb, offset, data_length, ENC_NA);
489 break;
491 case 0x6:
492 proto_tree_add_item(content_tree, hf_devicenet_data, tvb, offset, data_length, ENC_NA);
493 break;
495 case 0x7:
496 proto_tree_add_item(content_tree, hf_devicenet_dup_mac_id_rr_bit, tvb, offset, 1, ENC_LITTLE_ENDIAN);
497 proto_tree_add_item(content_tree, hf_devicenet_dup_mac_id_physical_port_number, tvb, offset, 1, ENC_LITTLE_ENDIAN);
498 offset ++;
500 proto_tree_add_item(content_tree, hf_devicenet_dup_mac_id_vendor, tvb, offset, 2, ENC_LITTLE_ENDIAN);
501 offset+=2;
503 proto_tree_add_item(content_tree, hf_devicenet_dup_mac_id_serial_number, tvb, offset, 4, ENC_LITTLE_ENDIAN);
504 break;
508 * Message group 3
510 else if (can_info.id <= MESSAGE_GROUP_3_ID )
512 uint8_t byte1;
514 msg_id_item = proto_tree_add_uint(can_tree, hf_devicenet_grp_msg3_id, tvb, 0, 0, can_info.id);
515 proto_item_set_generated(msg_id_item);
516 ti = proto_tree_add_uint(can_tree, hf_devicenet_src_mac_id, tvb, 0, 0, can_info.id & MESSAGE_GROUP_3_MAC_ID_MASK);
517 proto_item_set_generated(ti);
519 /* Set source address */
520 src_address = (uint8_t*)wmem_alloc(pinfo->pool, 1);
521 *src_address = (uint8_t)(can_info.id & MESSAGE_GROUP_3_MAC_ID_MASK);
522 set_address(&pinfo->src, devicenet_address_type, 1, (const void*)src_address);
524 message_id = can_info.id & MESSAGE_GROUP_3_MSG_MASK;
525 col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(message_id, devicenet_grp_msg3_vals, "Unknown"));
527 proto_tree_add_item(devicenet_tree, hf_devicenet_grp_msg3_frag, tvb, offset, 1, ENC_NA);
528 proto_tree_add_item(devicenet_tree, hf_devicenet_grp_msg3_xid, tvb, offset, 1, ENC_NA);
529 proto_tree_add_item(devicenet_tree, hf_devicenet_grp_msg3_dest_mac_id, tvb, offset, 1, ENC_LITTLE_ENDIAN);
530 byte1 = tvb_get_uint8(tvb, offset);
531 source_mac = byte1 & MESSAGE_GROUP_3_MAC_ID_MASK;
533 /* Set destination address */
534 /* XXX - This may be source address depending on message type. Need to adjust accordingly) */
535 dest_address = (uint8_t*)wmem_alloc(pinfo->pool, 1);
536 *dest_address = (uint8_t)source_mac;
537 set_address(&pinfo->dst, devicenet_address_type, 1, (const void*)dest_address);
538 offset++;
540 if (byte1 & MESSAGE_GROUP_3_FRAG_MASK)
542 col_set_str(pinfo->cinfo, COL_INFO, "Group 3 Message Fragment");
544 content_tree = proto_tree_add_subtree(devicenet_tree, tvb, offset, -1, ett_devicenet_contents, NULL, "Fragmentation");
546 proto_tree_add_item(content_tree, hf_devicenet_fragment_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
547 proto_tree_add_item(content_tree, hf_devicenet_fragment_count, tvb, offset, 1, ENC_LITTLE_ENDIAN);
549 /* TODO: Handle fragmentation */
550 proto_tree_add_expert(content_tree, pinfo, &ei_devicenet_frag_not_supported, tvb, offset, -1);
552 col_set_str(pinfo->cinfo, COL_INFO,
553 val_to_str_const((tvb_get_uint8(tvb, offset) & 0xC0) >> 6,
554 devicenet_fragmented_message_type_vals,
555 "Unknown fragmented message type"));
557 else
559 service_rr = tvb_get_uint8(tvb, offset);
561 content_tree = proto_tree_add_subtree_format(devicenet_tree, tvb, offset, -1, ett_devicenet_contents, NULL,
562 "Service: %s (%s)", val_to_str_const(service_rr & CIP_SC_MASK, devicenet_service_code_vals, "Unknown"),
563 service_rr & CIP_SC_RESPONSE_MASK ? "Response" : "Request");
565 proto_tree_add_item(content_tree, hf_devicenet_rr_bit, tvb, offset, 1, ENC_LITTLE_ENDIAN);
566 service_item = proto_tree_add_item(content_tree, hf_devicenet_service_code, tvb, offset, 1, ENC_LITTLE_ENDIAN);
567 offset++;
569 col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(service_rr & CIP_SC_MASK, devicenet_service_code_vals, "Unknown Service Code"));
570 if (service_rr & CIP_SC_RESPONSE_MASK)
572 col_append_str(pinfo->cinfo, COL_INFO, " - Response");
574 else
576 col_append_str(pinfo->cinfo, COL_INFO, " - Request");
579 switch(message_id)
581 case 0x140:
582 switch(service_rr & CIP_SC_MASK)
584 case SC_OPEN_EXPLICIT_MESSAGE:
585 case SC_CLOSE_EXPLICIT_MESSAGE:
586 case SC_DEVICE_HEARTBEAT_MESSAGE:
587 case SC_DEVICE_SHUTOWN_MESSAGE:
588 /* XXX - ERROR RESPONSE? */
589 break;
590 default:
591 expert_add_info_format(pinfo, service_item, &ei_devicenet_invalid_service,
592 "Invalid service code (0x%x) for Group 3 Message ID 5", service_rr & CIP_SC_MASK);
593 break;
595 break;
596 case 0x180:
597 switch(service_rr & CIP_SC_MASK)
599 case SC_OPEN_EXPLICIT_MESSAGE:
600 case SC_CLOSE_EXPLICIT_MESSAGE:
601 break;
602 default:
603 expert_add_info_format(pinfo, service_item, &ei_devicenet_invalid_service,
604 "Invalid service code (0x%x) for Group 3 Message ID 6", service_rr & CIP_SC_MASK);
605 break;
607 break;
608 case 0x1C0:
609 expert_add_info_format(pinfo, msg_id_item, &ei_devicenet_invalid_msg_id,
610 "Invalid Group 3 Message ID (%d)", message_id);
611 break;
614 switch(service_rr & CIP_SC_MASK)
616 case SC_OPEN_EXPLICIT_MESSAGE:
617 /* XXX - Create conversation to track connections */
618 if (service_rr & CIP_SC_RESPONSE_MASK)
620 proto_tree_add_item(content_tree, hf_devicenet_open_exp_msg_reserved, tvb, offset, 1, ENC_LITTLE_ENDIAN);
621 proto_tree_add_item(content_tree, hf_devicenet_open_exp_msg_actual_body_format, tvb, offset, 1, ENC_LITTLE_ENDIAN);
622 offset++;
623 proto_tree_add_item(content_tree, hf_devicenet_open_exp_dest_message_id, tvb, offset, 1, ENC_LITTLE_ENDIAN);
624 proto_tree_add_item(content_tree, hf_devicenet_open_exp_src_message_id, tvb, offset, 1, ENC_LITTLE_ENDIAN);
625 offset++;
626 proto_tree_add_item(content_tree, hf_devicenet_connection_id, tvb, offset, 2, ENC_LITTLE_ENDIAN);
628 else
630 proto_tree_add_item(content_tree, hf_devicenet_open_exp_msg_reserved, tvb, offset, 1, ENC_LITTLE_ENDIAN);
631 proto_tree_add_item(content_tree, hf_devicenet_open_exp_msg_req_body_format, tvb, offset, 1, ENC_LITTLE_ENDIAN);
632 offset++;
633 proto_tree_add_item(content_tree, hf_devicenet_open_exp_group_select, tvb, offset, 1, ENC_LITTLE_ENDIAN);
634 proto_tree_add_item(content_tree, hf_devicenet_open_exp_src_message_id, tvb, offset, 1, ENC_LITTLE_ENDIAN);
636 break;
637 case SC_CLOSE_EXPLICIT_MESSAGE:
638 /* XXX - Use conversation to track connections */
639 if ((service_rr & CIP_SC_RESPONSE_MASK) == 0)
641 proto_tree_add_item(content_tree, hf_devicenet_connection_id, tvb, offset, 2, ENC_LITTLE_ENDIAN);
643 break;
644 default:
645 if(service_rr & CIP_SC_MASK)
647 proto_tree_add_item(devicenet_tree, hf_devicenet_data, tvb, offset, data_length - 2, ENC_NA);
649 else
651 unsigned channel;
653 for (channel = 0; channel < num_devicenet_records_uat; channel++)
655 if (uat_devicenet_records[channel].mac_id == source_mac)
657 switch(uat_devicenet_records[channel].behavior)
659 case 0:
660 body_type_8_over_8_dissection(data_length, content_tree, tvb, pinfo, offset);
661 break;
662 case 1:
663 body_type_8_over_16_dissection(data_length, content_tree, tvb, pinfo, offset);
664 break;
665 case 2:
666 body_type_16_over_8_dissection(data_length, content_tree, tvb, pinfo, offset);
667 break;
668 case 3:
669 body_type_16_over_16_dissection(data_length, content_tree, tvb, pinfo, offset);
670 break;
671 default:
672 proto_tree_add_item(content_tree, hf_devicenet_data, tvb, offset, data_length, ENC_NA);
673 break;
678 /* Don't have a behavior defined for this address, default to 8 over 8 */
679 if (channel >= num_devicenet_records_uat)
681 body_type_8_over_8_dissection(data_length, content_tree, tvb, pinfo, offset);
684 break;
688 /*Message group 4*/
689 else if (can_info.id <= MESSAGE_GROUP_4_ID )
691 ti = proto_tree_add_uint(can_tree, hf_devicenet_grp_msg4_id, tvb, 0, 0, can_info.id);
692 proto_item_set_generated(ti);
694 message_id = can_info.id & MESSAGE_GROUP_4_MSG_MASK;
695 col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(message_id, devicenet_grp_msg4_vals, "Reserved Group 4 Message"));
697 switch(message_id)
699 case GRP4_COMM_FAULT_RESPONSE:
700 case GRP4_COMM_FAULT_REQUEST:
701 if(data_length == 2)
703 proto_tree_add_item(devicenet_tree, hf_devicenet_comm_fault_rsv, tvb, offset, 1, ENC_LITTLE_ENDIAN);
704 proto_tree_add_item(devicenet_tree, hf_devicenet_comm_fault_match, tvb, offset, 1, ENC_LITTLE_ENDIAN);
705 proto_tree_add_item(devicenet_tree, hf_devicenet_comm_fault_value, tvb, offset, 1, ENC_LITTLE_ENDIAN);
706 offset++;
708 proto_tree_add_item(devicenet_tree, hf_devicenet_rr_bit, tvb, offset, 1, ENC_LITTLE_ENDIAN);
709 proto_tree_add_item(devicenet_tree, hf_devicenet_service_code, tvb, offset, 1, ENC_LITTLE_ENDIAN);
711 if( tvb_get_uint8(tvb, offset) & CIP_SC_RESPONSE_MASK)
713 col_append_str(pinfo->cinfo, COL_INFO, " - Response");
715 else
717 col_append_str(pinfo->cinfo, COL_INFO, " - Request");
720 else if(data_length == 8)
722 proto_tree_add_item(devicenet_tree, hf_devicenet_comm_fault_rsv, tvb, offset, 1, ENC_LITTLE_ENDIAN);
723 offset++;
725 proto_tree_add_item(devicenet_tree, hf_devicenet_rr_bit, tvb, offset, 1, ENC_LITTLE_ENDIAN);
726 proto_tree_add_item(devicenet_tree, hf_devicenet_service_code, tvb, offset, 1, ENC_LITTLE_ENDIAN);
728 if( tvb_get_uint8(tvb, offset) & CIP_SC_RESPONSE_MASK)
730 col_append_str(pinfo->cinfo, COL_INFO, " - Response");
732 else
734 col_append_str(pinfo->cinfo, COL_INFO, " - Request");
736 offset++;
738 proto_tree_add_item(devicenet_tree, hf_devicenet_vendor, tvb, offset, 2, ENC_LITTLE_ENDIAN);
739 offset +=2;
740 proto_tree_add_item(devicenet_tree, hf_devicenet_serial_number, tvb, offset, 4, ENC_LITTLE_ENDIAN);
742 break;
743 case GRP4_OFFLINE_OWNER_REQUEST:
744 case GRP4_OFFLINE_OWNER_RESPONSE:
745 proto_tree_add_item(devicenet_tree, hf_devicenet_offline_ownership_reserved, tvb, offset, 1, ENC_LITTLE_ENDIAN);
746 proto_tree_add_item(devicenet_tree, hf_devicenet_offline_ownership_client_mac_id, tvb, offset, 1, ENC_LITTLE_ENDIAN);
747 offset++;
749 proto_tree_add_item(devicenet_tree, hf_devicenet_rr_bit, tvb, offset, 1, ENC_LITTLE_ENDIAN);
751 if( tvb_get_uint8(tvb, offset) & CIP_SC_RESPONSE_MASK)
753 col_append_str(pinfo->cinfo, COL_INFO, " - Response");
755 else
757 col_append_str(pinfo->cinfo, COL_INFO, " - Request");
760 proto_tree_add_item(devicenet_tree, hf_devicenet_offline_ownership_allocate, tvb, offset, 1, ENC_LITTLE_ENDIAN);
761 offset++;
762 proto_tree_add_item(devicenet_tree, hf_devicenet_vendor, tvb, offset, 2, ENC_LITTLE_ENDIAN);
763 offset +=2;
764 proto_tree_add_item(devicenet_tree, hf_devicenet_serial_number, tvb, offset, 4, ENC_LITTLE_ENDIAN);
765 break;
768 /*Invalid CAN message*/
769 else
771 col_add_fstr(pinfo->cinfo, COL_INFO, "Invalid CAN Message 0x%06X", can_info.id);
772 expert_add_info_format(pinfo, can_id_item, &ei_devicenet_invalid_can_id,
773 "Invalid CAN Message 0x%04X", can_info.id);
776 return tvb_captured_length(tvb);
779 static int devicenet_addr_to_str(const address* addr, char *buf, int buf_len)
781 const uint8_t *addrdata = (const uint8_t *)addr->data;
783 uint32_to_str_buf(*addrdata, buf, buf_len);
784 return (int)strlen(buf);
787 static int devicenet_addr_str_len(const address* addr _U_)
789 return 11; /* Leaves required space (10 bytes) for uint_to_str_back() */
792 static int devicenet_addr_len(void)
794 return 1;
797 void proto_register_devicenet(void)
799 module_t *devicenet_module;
800 expert_module_t*expert_devicenet;
802 static hf_register_info hf[] = {
803 { &hf_devicenet_can_id,
804 {"CAN Identifier", "devicenet.can_id",
805 FT_UINT16, BASE_HEX, NULL, DEVICENET_CANID_MASK,
806 NULL, HFILL }
808 { &hf_devicenet_src_mac_id,
809 { "Source MAC ID", "devicenet.src_mac_id",
810 FT_UINT8, BASE_DEC, NULL, 0,
811 NULL, HFILL }
813 { &hf_devicenet_connection_id,
814 { "Connection ID", "devicenet.connection_id",
815 FT_UINT16, BASE_DEC, NULL, 0,
816 NULL, HFILL }
818 { &hf_devicenet_data,
819 { "Data", "devicenet.data",
820 FT_BYTES, BASE_NONE, NULL, 0,
821 NULL, HFILL }
823 { &hf_devicenet_grp_msg1_id,
824 { "Group 1 message ID", "devicenet.grp_msg1.id",
825 FT_UINT16, BASE_DEC, NULL, MESSAGE_GROUP_1_MSG_MASK,
826 NULL, HFILL }
828 { &hf_devicenet_grp_msg2_id,
829 { "Group 2 message ID", "devicenet.grp_msg2.id",
830 FT_UINT16, BASE_DEC, NULL, MESSAGE_GROUP_2_MSG_MASK,
831 NULL, HFILL }
833 { &hf_devicenet_grp_msg3_id,
834 { "Group 3 message ID", "devicenet.grp_msg3.id",
835 FT_UINT16, BASE_DEC, NULL, MESSAGE_GROUP_3_MSG_MASK,
836 NULL, HFILL }
838 { &hf_devicenet_grp_msg3_dest_mac_id,
839 { "Destination MAC ID", "devicenet.dest_mac_id",
840 FT_UINT8, BASE_DEC, NULL, 0x3F,
841 NULL, HFILL }
843 { &hf_devicenet_grp_msg3_frag,
844 { "Frag", "devicenet.grp_msg3.frag",
845 FT_BOOLEAN, 8, NULL, MESSAGE_GROUP_3_FRAG_MASK,
846 NULL, HFILL }
848 { &hf_devicenet_grp_msg3_xid,
849 { "XID", "devicenet.grp_msg3.xid",
850 FT_BOOLEAN, 8, NULL, MESSAGE_GROUP_3_XID_MASK,
851 NULL, HFILL }
853 { &hf_devicenet_grp_msg4_id,
854 { "Group 4 message ID", "devicenet.grp_msg4.id",
855 FT_UINT16, BASE_DEC, NULL, MESSAGE_GROUP_4_MSG_MASK,
856 NULL, HFILL }
858 { &hf_devicenet_rr_bit,
859 { "Request/Response", "devicenet.rr",
860 FT_UINT8, BASE_DEC, VALS(cip_sc_rr), CIP_SC_RESPONSE_MASK,
861 "Request or Response message", HFILL }
863 { &hf_devicenet_service_code,
864 { "Service Code", "devicenet.service",
865 FT_UINT8, BASE_DEC, VALS(devicenet_service_code_vals), CIP_SC_MASK,
866 NULL, HFILL }
868 { &hf_devicenet_open_exp_src_message_id,
869 { "Source Message ID", "devicenet.open_message.src_message_id",
870 FT_UINT8, BASE_DEC, NULL, 0x0F,
871 NULL, HFILL }
873 { &hf_devicenet_open_exp_dest_message_id,
874 { "Destination Message ID", "devicenet.open_message.dest_message_id",
875 FT_UINT8, BASE_DEC, NULL, 0xF0,
876 NULL, HFILL }
878 { &hf_devicenet_open_exp_msg_reserved,
879 { "Reserved", "devicenet.open_message.reserved",
880 FT_UINT8, BASE_DEC, NULL, 0xF0,
881 NULL, HFILL }
883 { &hf_devicenet_open_exp_msg_req_body_format,
884 { "Requested Message Body Format", "devicenet.open_message.req_body_format",
885 FT_UINT8, BASE_DEC, VALS(devicenet_message_body_format_vals), 0x0F,
886 NULL, HFILL }
888 { &hf_devicenet_open_exp_msg_actual_body_format,
889 { "Actual Message Body Format", "devicenet.open_message.actual_body_format",
890 FT_UINT8, BASE_DEC, VALS(devicenet_message_body_format_vals), 0x0F,
891 NULL, HFILL }
893 { &hf_devicenet_open_exp_group_select,
894 { "Group Select", "devicenet.open_message.group_select",
895 FT_UINT8, BASE_DEC, VALS(devicenet_group_select_vals), 0xF0,
896 NULL, HFILL }
898 { &hf_devicenet_dup_mac_id_rr_bit,
899 { "Request/Response", "devicenet.dup_mac_id.rr",
900 FT_UINT8, BASE_DEC, VALS(cip_sc_rr), CIP_SC_RESPONSE_MASK,
901 "Duplicate MAC ID Request or Response message", HFILL }
903 { &hf_devicenet_dup_mac_id_physical_port_number,
904 { "Physical port number", "devicenet.dup_mac_id.physical_port_number",
905 FT_UINT8, BASE_DEC, NULL, 0x7F,
906 "Duplicate MAC ID check message physical port number", HFILL }
908 { &hf_devicenet_dup_mac_id_vendor,
909 { "Vendor ID", "devicenet.dup_mac_id.vendor",
910 FT_UINT16, BASE_HEX|BASE_EXT_STRING, &cip_vendor_vals_ext, 0,
911 NULL, HFILL }
913 { &hf_devicenet_dup_mac_id_serial_number,
914 { "Serial Number", "devicenet.dup_mac_id.serial_number",
915 FT_UINT32, BASE_HEX, NULL, 0x00,
916 NULL, HFILL }
918 { &hf_devicenet_vendor,
919 { "Vendor ID", "devicenet.vendor",
920 FT_UINT16, BASE_HEX|BASE_EXT_STRING, &cip_vendor_vals_ext, 0,
921 NULL, HFILL }
923 { &hf_devicenet_serial_number,
924 { "Serial Number", "devicenet.serial_number",
925 FT_UINT32, BASE_HEX, NULL, 0x00,
926 NULL, HFILL }
928 { &hf_devicenet_instance8,
929 { "Instance", "devicenet.instance",
930 FT_UINT8, BASE_HEX, NULL, 0x00,
931 NULL, HFILL }
933 { &hf_devicenet_instance16,
934 { "Instance", "devicenet.instance",
935 FT_UINT16, BASE_HEX, NULL, 0x00,
936 NULL, HFILL }
938 { &hf_devicenet_attribute,
939 { "Attribute", "devicenet.attribute",
940 FT_UINT8, BASE_HEX, NULL, 0x00,
941 NULL, HFILL }
943 { &hf_devicenet_fragment_type,
944 { "Fragment Type", "devicenet.fragment_type",
945 FT_UINT8, BASE_HEX, VALS(devicenet_fragmented_message_type_vals), 0xC0,
946 NULL, HFILL }
948 { &hf_devicenet_fragment_count,
949 { "Fragment Count", "devicenet.fragment_count",
950 FT_UINT8, BASE_HEX_DEC, NULL, 0x3F,
951 NULL, HFILL }
953 { &hf_devicenet_class8,
954 { "Class", "devicenet.class",
955 FT_UINT8, BASE_HEX|BASE_EXT_STRING, &cip_class_names_vals_ext, 0,
956 NULL, HFILL }
958 { &hf_devicenet_class16,
959 { "Class", "devicenet.class",
960 FT_UINT16, BASE_HEX|BASE_EXT_STRING, &cip_class_names_vals_ext, 0,
961 NULL, HFILL }
963 { &hf_devicenet_comm_fault_rsv,
964 { "Reserved", "devicenet.comm_fault.reserved",
965 FT_UINT8, BASE_HEX, NULL, 0x80,
966 NULL, HFILL }
968 { &hf_devicenet_comm_fault_match,
969 { "Match", "devicenet.comm_fault.match",
970 FT_UINT8, BASE_HEX, NULL, 0x40,
971 NULL, HFILL }
973 {&hf_devicenet_comm_fault_value,
974 { "Value", "devicenet.comm_fault.value",
975 FT_UINT8, BASE_HEX, NULL, 0x3F,
976 "Comm Fault Value", HFILL }
978 {&hf_devicenet_offline_ownership_reserved,
979 { "Reserved", "devicenet.offline_ownership.reserved",
980 FT_UINT8, BASE_HEX, NULL, 0xC0,
981 "Offline ownership Response Message Reserved", HFILL }
983 {&hf_devicenet_offline_ownership_client_mac_id,
984 { "Client MAC ID", "devicenet.offline_ownership.client_mac_id",
985 FT_UINT8, BASE_HEX, NULL, MESSAGE_GROUP_4_MSG_MASK,
986 "Offline ownership message client MAC ID", HFILL }
988 {&hf_devicenet_offline_ownership_allocate,
989 { "Allocate", "devicenet.offline_ownership.allocate",
990 FT_UINT8, BASE_HEX, NULL, CIP_SC_MASK,
991 "Offline ownership response message allocate", HFILL }
995 static int *ett[] = {
996 &ett_devicenet,
997 &ett_devicenet_can,
998 &ett_devicenet_contents,
999 &ett_devicenet_8_8,
1000 &ett_devicenet_8_16,
1001 &ett_devicenet_16_8,
1002 &ett_devicenet_16_16
1005 static ei_register_info ei[] = {
1006 { &ei_devicenet_invalid_service, { "devicenet.invalid_service", PI_PROTOCOL, PI_WARN, "Invalid service", EXPFILL }},
1007 { &ei_devicenet_invalid_can_id, { "devicenet.invalid_can_id", PI_PROTOCOL, PI_WARN, "Invalid CAN ID", EXPFILL }},
1008 { &ei_devicenet_invalid_msg_id, { "devicenet.invalid_msg_id", PI_PROTOCOL, PI_WARN, "Invalid Message ID", EXPFILL }},
1009 { &ei_devicenet_frag_not_supported, { "devicenet.frag_not_supported", PI_UNDECODED, PI_WARN, "Fragmentation not currently supported", EXPFILL }},
1012 static uat_field_t devicenet_uat_flds[] = {
1013 UAT_FLD_DEC(uat_devicenet_records, mac_id, "Option number", "Custom Option Number"),
1014 UAT_FLD_VS(uat_devicenet_records, behavior, "Option type", devicenet_message_body_format_vals, "Option datatype"),
1015 UAT_END_FIELDS
1018 proto_devicenet = proto_register_protocol("DeviceNet Protocol", "DeviceNet", "devicenet");
1020 proto_register_field_array(proto_devicenet, hf, array_length(hf));
1021 proto_register_subtree_array(ett, array_length(ett));
1022 expert_devicenet = expert_register_protocol(proto_devicenet);
1023 expert_register_field_array(expert_devicenet, ei, array_length(ei));
1025 devicenet_address_type = address_type_dissector_register("AT_DEVICENET", "DeviceNet Address", devicenet_addr_to_str, devicenet_addr_str_len, NULL, NULL, devicenet_addr_len, NULL, NULL);
1027 devicenet_module = prefs_register_protocol(proto_devicenet, NULL);
1029 devicenet_uat = uat_new("Node bodytypes",
1030 sizeof(uat_devicenet_record_t), /* record size */
1031 "devicenet_bodytypes", /* filename */
1032 true, /* from_profile */
1033 &uat_devicenet_records, /* data_ptr */
1034 &num_devicenet_records_uat, /* numitems_ptr */
1035 UAT_AFFECTS_DISSECTION, /* affects dissection of packets, but not set of named fields */
1036 NULL, /* help */
1037 NULL, /* copy callback */
1038 uat_devicenet_record_update_cb, /* update callback */
1039 NULL, /* free callback */
1040 NULL, /* post update callback */
1041 NULL, /* reset callback */
1042 devicenet_uat_flds); /* UAT field definitions */
1044 prefs_register_uat_preference(devicenet_module,
1045 "bodytype_table",
1046 "Node bodytypes",
1047 "Node bodytypes",
1048 devicenet_uat);
1050 devicenet_handle = register_dissector("devicenet", dissect_devicenet, proto_devicenet );
1053 void
1054 proto_reg_handoff_devicenet(void)
1056 dissector_add_for_decode_as("can.subdissector", devicenet_handle );
1060 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1062 * Local variables:
1063 * c-basic-offset: 4
1064 * tab-width: 8
1065 * indent-tabs-mode: nil
1066 * End:
1068 * vi: set shiftwidth=4 tabstop=8 expandtab:
1069 * :indentSize=4:tabSize=8:noTabs=true: