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
9 * Erik Ivarsson <eriki@student.chalmers.se>
10 * Hans-Jorgen Gunnarsson <hag@hms.se>
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
21 #include <epan/packet.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;
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. */
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");
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")
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 },
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
[] = {
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" },
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" },
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" },
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" },
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" },
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" },
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" },
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" },
260 static const value_string devicenet_io_attribute_vals
[] = {
262 {0x02, "Device Type"},
263 {0x03, "Product Code"},
266 {0x06, "Serial Number"},
267 {0x07, "Product Name"},
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
;
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
);
286 proto_tree_add_item(devicenet_tree
, hf_devicenet_instance8
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
287 instance
= tvb_get_uint8(tvb
, offset
);
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
);
304 length
= offset
-start_offset
;
305 proto_tree_add_item(devicenet_tree
, hf_devicenet_data
, tvb
, offset
, length
, ENC_NA
);
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
;
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
);
324 proto_tree_add_item(devicenet_tree
, hf_devicenet_instance16
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
325 instance
= tvb_get_letohs(tvb
, offset
);
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
);
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
;
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
);
355 proto_tree_add_item(devicenet_tree
, hf_devicenet_instance8
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
356 instance
= tvb_get_uint8(tvb
, offset
);
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
);
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
;
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
);
387 proto_tree_add_item(devicenet_tree
, hf_devicenet_instance16
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
388 instance
= tvb_get_letohs(tvb
, offset
);
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
);
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
;
414 uint32_t data_length
= tvb_reported_length(tvb
);
416 struct can_info can_info
;
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. */
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
);
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
);
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");
488 proto_tree_add_item(content_tree
, hf_devicenet_data
, tvb
, offset
, data_length
, ENC_NA
);
492 proto_tree_add_item(content_tree
, hf_devicenet_data
, tvb
, offset
, data_length
, ENC_NA
);
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
);
500 proto_tree_add_item(content_tree
, hf_devicenet_dup_mac_id_vendor
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
503 proto_tree_add_item(content_tree
, hf_devicenet_dup_mac_id_serial_number
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
510 else if (can_info
.id
<= MESSAGE_GROUP_3_ID
)
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
);
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"));
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
);
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");
576 col_append_str(pinfo
->cinfo
, COL_INFO
, " - Request");
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? */
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
);
597 switch(service_rr
& CIP_SC_MASK
)
599 case SC_OPEN_EXPLICIT_MESSAGE
:
600 case SC_CLOSE_EXPLICIT_MESSAGE
:
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
);
609 expert_add_info_format(pinfo
, msg_id_item
, &ei_devicenet_invalid_msg_id
,
610 "Invalid Group 3 Message ID (%d)", message_id
);
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
);
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
);
626 proto_tree_add_item(content_tree
, hf_devicenet_connection_id
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
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
);
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
);
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
);
645 if(service_rr
& CIP_SC_MASK
)
647 proto_tree_add_item(devicenet_tree
, hf_devicenet_data
, tvb
, offset
, data_length
- 2, ENC_NA
);
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
)
660 body_type_8_over_8_dissection(data_length
, content_tree
, tvb
, pinfo
, offset
);
663 body_type_8_over_16_dissection(data_length
, content_tree
, tvb
, pinfo
, offset
);
666 body_type_16_over_8_dissection(data_length
, content_tree
, tvb
, pinfo
, offset
);
669 body_type_16_over_16_dissection(data_length
, content_tree
, tvb
, pinfo
, offset
);
672 proto_tree_add_item(content_tree
, hf_devicenet_data
, tvb
, offset
, data_length
, ENC_NA
);
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
);
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"));
699 case GRP4_COMM_FAULT_RESPONSE
:
700 case GRP4_COMM_FAULT_REQUEST
:
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
);
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");
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
);
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");
734 col_append_str(pinfo
->cinfo
, COL_INFO
, " - Request");
738 proto_tree_add_item(devicenet_tree
, hf_devicenet_vendor
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
740 proto_tree_add_item(devicenet_tree
, hf_devicenet_serial_number
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
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
);
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");
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
);
762 proto_tree_add_item(devicenet_tree
, hf_devicenet_vendor
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
764 proto_tree_add_item(devicenet_tree
, hf_devicenet_serial_number
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
768 /*Invalid CAN message*/
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)
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
,
808 { &hf_devicenet_src_mac_id
,
809 { "Source MAC ID", "devicenet.src_mac_id",
810 FT_UINT8
, BASE_DEC
, NULL
, 0,
813 { &hf_devicenet_connection_id
,
814 { "Connection ID", "devicenet.connection_id",
815 FT_UINT16
, BASE_DEC
, NULL
, 0,
818 { &hf_devicenet_data
,
819 { "Data", "devicenet.data",
820 FT_BYTES
, BASE_NONE
, NULL
, 0,
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
,
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
,
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
,
838 { &hf_devicenet_grp_msg3_dest_mac_id
,
839 { "Destination MAC ID", "devicenet.dest_mac_id",
840 FT_UINT8
, BASE_DEC
, NULL
, 0x3F,
843 { &hf_devicenet_grp_msg3_frag
,
844 { "Frag", "devicenet.grp_msg3.frag",
845 FT_BOOLEAN
, 8, NULL
, MESSAGE_GROUP_3_FRAG_MASK
,
848 { &hf_devicenet_grp_msg3_xid
,
849 { "XID", "devicenet.grp_msg3.xid",
850 FT_BOOLEAN
, 8, NULL
, MESSAGE_GROUP_3_XID_MASK
,
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
,
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
,
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,
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,
878 { &hf_devicenet_open_exp_msg_reserved
,
879 { "Reserved", "devicenet.open_message.reserved",
880 FT_UINT8
, BASE_DEC
, NULL
, 0xF0,
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,
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,
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,
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,
913 { &hf_devicenet_dup_mac_id_serial_number
,
914 { "Serial Number", "devicenet.dup_mac_id.serial_number",
915 FT_UINT32
, BASE_HEX
, NULL
, 0x00,
918 { &hf_devicenet_vendor
,
919 { "Vendor ID", "devicenet.vendor",
920 FT_UINT16
, BASE_HEX
|BASE_EXT_STRING
, &cip_vendor_vals_ext
, 0,
923 { &hf_devicenet_serial_number
,
924 { "Serial Number", "devicenet.serial_number",
925 FT_UINT32
, BASE_HEX
, NULL
, 0x00,
928 { &hf_devicenet_instance8
,
929 { "Instance", "devicenet.instance",
930 FT_UINT8
, BASE_HEX
, NULL
, 0x00,
933 { &hf_devicenet_instance16
,
934 { "Instance", "devicenet.instance",
935 FT_UINT16
, BASE_HEX
, NULL
, 0x00,
938 { &hf_devicenet_attribute
,
939 { "Attribute", "devicenet.attribute",
940 FT_UINT8
, BASE_HEX
, NULL
, 0x00,
943 { &hf_devicenet_fragment_type
,
944 { "Fragment Type", "devicenet.fragment_type",
945 FT_UINT8
, BASE_HEX
, VALS(devicenet_fragmented_message_type_vals
), 0xC0,
948 { &hf_devicenet_fragment_count
,
949 { "Fragment Count", "devicenet.fragment_count",
950 FT_UINT8
, BASE_HEX_DEC
, NULL
, 0x3F,
953 { &hf_devicenet_class8
,
954 { "Class", "devicenet.class",
955 FT_UINT8
, BASE_HEX
|BASE_EXT_STRING
, &cip_class_names_vals_ext
, 0,
958 { &hf_devicenet_class16
,
959 { "Class", "devicenet.class",
960 FT_UINT16
, BASE_HEX
|BASE_EXT_STRING
, &cip_class_names_vals_ext
, 0,
963 { &hf_devicenet_comm_fault_rsv
,
964 { "Reserved", "devicenet.comm_fault.reserved",
965 FT_UINT8
, BASE_HEX
, NULL
, 0x80,
968 { &hf_devicenet_comm_fault_match
,
969 { "Match", "devicenet.comm_fault.match",
970 FT_UINT8
, BASE_HEX
, NULL
, 0x40,
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
[] = {
998 &ett_devicenet_contents
,
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"),
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 */
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
,
1050 devicenet_handle
= register_dissector("devicenet", dissect_devicenet
, proto_devicenet
);
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
1065 * indent-tabs-mode: nil
1068 * vi: set shiftwidth=4 tabstop=8 expandtab:
1069 * :indentSize=4:tabSize=8:noTabs=true: