2 * Routines for Controller Area Network over Ethernet dissection
3 * Copyright 2018, Lazar Sumar <bugzilla@lazar.co.nz>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
13 * The CAN-ETH protocol is used for transmitting the Controller Area Network
14 * (CAN) protocol over UDP.
16 * The protocol definition can be found at http://www.proconx.com/assets/files/products/caneth/canframe.pdf
21 #include <epan/packet.h>
22 #include "packet-udp.h"
23 #include "packet-socketcan.h"
25 #define CAN_FRAME_LEN 15
27 #define CAN_ID_OFFSET 0
28 #define CAN_DLC_OFFSET 4
29 #define CAN_DATA_OFFSET 5
30 #define CAN_EXT_FLAG_OFFSET 13
31 #define CAN_RTR_FLAG_OFFSET 14
33 static const char magic
[] = "ISO11898";
35 void proto_reg_handoff_caneth(void);
36 void proto_register_caneth(void);
38 static dissector_handle_t caneth_handle
;
40 static int proto_caneth
;
41 static int hf_caneth_magic
;
42 static int hf_caneth_version
;
43 static int hf_caneth_frames
;
44 static int hf_caneth_options
;
46 static int hf_caneth_can_ident_ext
;
47 static int hf_caneth_can_ident_std
;
48 static int hf_caneth_can_extflag
;
49 static int hf_caneth_can_rtrflag
;
50 static int hf_caneth_can_len
;
51 static int hf_caneth_can_padding
;
53 #define CANETH_UDP_PORT 11898
55 static int ett_caneth
;
56 static int ett_caneth_frames
;
57 static int ett_caneth_can
;
59 static int proto_can
; // use CAN protocol for consistent filtering
61 /* A sample #define of the minimum length (in bytes) of the protocol data.
62 * If data is received with fewer than this many bytes it is rejected by
63 * the current dissector. */
64 #define CANETH_MIN_LENGTH 10
67 test_caneth(packet_info
*pinfo _U_
, tvbuff_t
*tvb
, int offset
, void *data _U_
)
69 /* Check that we have enough length for the Magic, Version, and Length */
70 if (tvb_reported_length(tvb
) < CANETH_MIN_LENGTH
)
72 /* Check that the magic id matches */
73 if (tvb_strneql(tvb
, offset
, magic
, 8) != 0)
75 /* Check that the version is 1 as that is the only supported version */
76 if (tvb_get_uint8(tvb
, offset
+8) != 1)
78 /* Check that the version 1 limit of 16 can frames is respected */
79 if (tvb_get_uint8(tvb
, offset
+9) > 16)
85 get_caneth_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
, int offset
, void *data _U_
)
87 return (unsigned) tvb_get_ntohs(tvb
, offset
+3);
91 dissect_caneth_can(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
99 struct can_info can_info
;
101 ti
= proto_tree_add_item(tree
, proto_can
, tvb
, 0, -1, ENC_NA
);
102 can_tree
= proto_item_add_subtree(ti
, ett_caneth_can
);
104 ext_flag
= tvb_get_uint8(tvb
, CAN_EXT_FLAG_OFFSET
);
105 rtr_flag
= tvb_get_uint8(tvb
, CAN_RTR_FLAG_OFFSET
);
109 proto_tree_add_item_ret_uint(can_tree
, hf_caneth_can_ident_ext
, tvb
, CAN_ID_OFFSET
, 4, ENC_LITTLE_ENDIAN
, &raw_can_id
);
110 can_info
.id
= raw_can_id
& CAN_EFF_MASK
;
114 proto_tree_add_item_ret_uint(can_tree
, hf_caneth_can_ident_std
, tvb
, CAN_ID_OFFSET
, 4, ENC_LITTLE_ENDIAN
, &raw_can_id
);
115 can_info
.id
= raw_can_id
& CAN_SFF_MASK
;
118 can_info
.id
|= (ext_flag
? CAN_EFF_FLAG
: 0) | (rtr_flag
? CAN_RTR_FLAG
: 0);
119 can_info
.fd
= CAN_TYPE_CAN_CLASSIC
;
120 can_info
.bus_id
= 0; /* see get_bus_id in packet-socketcan.c? */
122 proto_tree_add_item_ret_uint(can_tree
, hf_caneth_can_len
, tvb
, CAN_DLC_OFFSET
, 1, ENC_NA
, &can_info
.len
);
123 proto_tree_add_item(can_tree
, hf_caneth_can_extflag
, tvb
, CAN_EXT_FLAG_OFFSET
, 1, ENC_NA
);
124 proto_tree_add_item(can_tree
, hf_caneth_can_rtrflag
, tvb
, CAN_RTR_FLAG_OFFSET
, 1, ENC_NA
);
126 next_tvb
= tvb_new_subset_length(tvb
, CAN_DATA_OFFSET
, can_info
.len
);
128 if (!socketcan_call_subdissectors(next_tvb
, pinfo
, tree
, &can_info
, false)) {
129 call_data_dissector(next_tvb
, pinfo
, tree
);
132 if (tvb_captured_length_remaining(tvb
, CAN_DATA_OFFSET
+ can_info
.len
) > 0)
134 proto_tree_add_item(can_tree
, hf_caneth_can_padding
, tvb
, CAN_DATA_OFFSET
+ can_info
.len
, -1, ENC_NA
);
136 return tvb_captured_length(tvb
);
140 dissect_caneth(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
142 proto_tree
*caneth_tree
;
144 uint32_t frame_count
, offset
;
147 if (!test_caneth(pinfo
, tvb
, 0, data
))
150 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "CAN-ETH");
151 col_clear(pinfo
->cinfo
, COL_INFO
);
153 ti
= proto_tree_add_item(tree
, proto_caneth
, tvb
, 0, -1, ENC_NA
);
154 caneth_tree
= proto_item_add_subtree(ti
, ett_caneth
);
156 proto_tree_add_item(caneth_tree
, hf_caneth_magic
, tvb
, 0, 8, ENC_ASCII
);
157 proto_tree_add_item(caneth_tree
, hf_caneth_version
, tvb
, 8, 1, ENC_NA
);
158 proto_tree_add_item_ret_uint(caneth_tree
, hf_caneth_frames
, tvb
, 9, 1, ENC_NA
, &frame_count
);
160 for (offset
= 10; frame_count
-- > 0; offset
+= CAN_FRAME_LEN
)
162 next_tvb
= tvb_new_subset_length(tvb
, offset
, CAN_FRAME_LEN
);
163 dissect_caneth_can(next_tvb
, pinfo
, tree
, data
);
166 if (tvb_captured_length_remaining(tvb
, offset
) > 0)
168 proto_tree_add_item(caneth_tree
, hf_caneth_options
, tvb
, offset
, -1, ENC_NA
);
171 return tvb_captured_length(tvb
);
175 dissect_caneth_heur_udp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
177 return (udp_dissect_pdus(tvb
, pinfo
, tree
, CANETH_MIN_LENGTH
, test_caneth
,
178 get_caneth_len
, dissect_caneth
, data
) != 0);
182 proto_register_caneth(void)
184 static hf_register_info hf
[] = {
188 "Magic", "caneth.magic",
189 FT_STRING
, BASE_NONE
,
191 "The magic identifier used to denote the start of a CAN-ETH packet", HFILL
197 "Version", "caneth.version",
206 "CAN Frames", "caneth.frames",
209 "Number of enclosed CAN frames", HFILL
215 "Options (Reserved)", "caneth.options",
218 "Options field, reserved for future use, should be empty", HFILL
222 &hf_caneth_can_ident_ext
,
224 "Identifier", "can.id",
231 &hf_caneth_can_ident_std
,
233 "Identifier", "can.id",
240 &hf_caneth_can_extflag
,
242 "Extended Flag", "can.flags.xtd",
243 FT_BOOLEAN
, BASE_NONE
,
249 &hf_caneth_can_rtrflag
,
251 "Remote Transmission Request Flag", "can.flags.rtr",
252 FT_BOOLEAN
, BASE_NONE
,
260 "Frame-Length", "can.len",
267 &hf_caneth_can_padding
,
269 "Padding", "caneth.can.padding",
277 static int *ett
[] = {
283 proto_caneth
= proto_register_protocol("Controller Area Network over Ethernet", "CAN-ETH", "caneth");
285 proto_register_field_array(proto_caneth
, hf
, array_length(hf
));
286 proto_register_subtree_array(ett
, array_length(ett
));
288 caneth_handle
= register_dissector("caneth", dissect_caneth
, proto_caneth
);
292 proto_reg_handoff_caneth(void)
294 dissector_add_uint_with_preference("udp.port", CANETH_UDP_PORT
, caneth_handle
);
296 heur_dissector_add("udp", dissect_caneth_heur_udp
, "CAN-ETH over UDP", "caneth_udp", proto_caneth
, HEURISTIC_ENABLE
);
298 proto_can
= proto_get_id_by_filter_name("can");
302 * Editor modelines - https://www.wireshark.org/tools/modelines.html
307 * indent-tabs-mode: nil
310 * vi: set shiftwidth=4 tabstop=8 expandtab:
311 * :indentSize=4:tabSize=8:noTabs=true: