/src/wireshark/epan/dissectors/packet-caneth.c
Line | Count | Source |
1 | | /* packet-caneth.c |
2 | | * Routines for Controller Area Network over Ethernet dissection |
3 | | * Copyright 2018, Lazar Sumar <bugzilla@lazar.co.nz> |
4 | | * |
5 | | * Wireshark - Network traffic analyzer |
6 | | * By Gerald Combs <gerald@wireshark.org> |
7 | | * Copyright 1998 Gerald Combs |
8 | | * |
9 | | * SPDX-License-Identifier: GPL-2.0-or-later |
10 | | */ |
11 | | |
12 | | /* |
13 | | * The CAN-ETH protocol is used for transmitting the Controller Area Network |
14 | | * (CAN) protocol over UDP. |
15 | | * |
16 | | * The protocol definition can be found at http://www.proconx.com/assets/files/products/caneth/canframe.pdf |
17 | | */ |
18 | | |
19 | | #include <config.h> |
20 | | |
21 | | #include <epan/packet.h> |
22 | | #include "packet-udp.h" |
23 | | #include "packet-socketcan.h" |
24 | | |
25 | 0 | #define CAN_FRAME_LEN 15 |
26 | | |
27 | 0 | #define CAN_ID_OFFSET 0 |
28 | 0 | #define CAN_DLC_OFFSET 4 |
29 | 0 | #define CAN_DATA_OFFSET 5 |
30 | 0 | #define CAN_EXT_FLAG_OFFSET 13 |
31 | 0 | #define CAN_RTR_FLAG_OFFSET 14 |
32 | | |
33 | | static const char magic[] = "ISO11898"; |
34 | | |
35 | | void proto_reg_handoff_caneth(void); |
36 | | void proto_register_caneth(void); |
37 | | |
38 | | static dissector_handle_t caneth_handle; |
39 | | |
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; |
45 | | |
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; |
52 | | |
53 | 14 | #define CANETH_UDP_PORT 11898 |
54 | | |
55 | | static int ett_caneth; |
56 | | static int ett_caneth_frames; |
57 | | static int ett_caneth_can; |
58 | | |
59 | | static int proto_can; // use CAN protocol for consistent filtering |
60 | | |
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 | 2 | #define CANETH_MIN_LENGTH 10 |
65 | | |
66 | | static bool |
67 | | test_caneth(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_) |
68 | 2 | { |
69 | | /* Check that we have enough length for the Magic, Version, and Length */ |
70 | 2 | if (tvb_reported_length(tvb) < CANETH_MIN_LENGTH) |
71 | 1 | return false; |
72 | | /* Check that the magic id matches */ |
73 | 1 | if (tvb_strneql(tvb, offset, magic, 8) != 0) |
74 | 1 | return false; |
75 | | /* Check that the version is 1 as that is the only supported version */ |
76 | 0 | if (tvb_get_uint8(tvb, offset+8) != 1) |
77 | 0 | return false; |
78 | | /* Check that the version 1 limit of 16 can frames is respected */ |
79 | 0 | if (tvb_get_uint8(tvb, offset+9) > 16) |
80 | 0 | return false; |
81 | 0 | return true; |
82 | 0 | } |
83 | | |
84 | | static unsigned |
85 | | get_caneth_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_) |
86 | 0 | { |
87 | 0 | return (unsigned) tvb_get_ntohs(tvb, offset+3); |
88 | 0 | } |
89 | | |
90 | | static int |
91 | | dissect_caneth_can(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
92 | 0 | { |
93 | 0 | proto_tree *can_tree; |
94 | 0 | proto_item *ti; |
95 | 0 | uint32_t raw_can_id; |
96 | 0 | int8_t ext_flag; |
97 | 0 | int8_t rtr_flag; |
98 | 0 | tvbuff_t* next_tvb; |
99 | 0 | struct can_info can_info; |
100 | |
|
101 | 0 | ti = proto_tree_add_item(tree, proto_can, tvb, 0, -1, ENC_NA); |
102 | 0 | can_tree = proto_item_add_subtree(ti, ett_caneth_can); |
103 | |
|
104 | 0 | ext_flag = tvb_get_uint8(tvb, CAN_EXT_FLAG_OFFSET); |
105 | 0 | rtr_flag = tvb_get_uint8(tvb, CAN_RTR_FLAG_OFFSET); |
106 | |
|
107 | 0 | if (ext_flag) |
108 | 0 | { |
109 | 0 | 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 | 0 | can_info.id = raw_can_id & CAN_EFF_MASK; |
111 | 0 | } |
112 | 0 | else |
113 | 0 | { |
114 | 0 | 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 | 0 | can_info.id = raw_can_id & CAN_SFF_MASK; |
116 | 0 | } |
117 | |
|
118 | 0 | can_info.id |= (ext_flag ? CAN_EFF_FLAG : 0) | (rtr_flag ? CAN_RTR_FLAG : 0); |
119 | 0 | can_info.fd = CAN_TYPE_CAN_CLASSIC; |
120 | 0 | can_info.bus_id = 0; /* see get_bus_id in packet-socketcan.c? */ |
121 | |
|
122 | 0 | proto_tree_add_item_ret_uint(can_tree, hf_caneth_can_len, tvb, CAN_DLC_OFFSET, 1, ENC_NA, &can_info.len); |
123 | 0 | proto_tree_add_item(can_tree, hf_caneth_can_extflag, tvb, CAN_EXT_FLAG_OFFSET, 1, ENC_NA); |
124 | 0 | proto_tree_add_item(can_tree, hf_caneth_can_rtrflag, tvb, CAN_RTR_FLAG_OFFSET, 1, ENC_NA); |
125 | |
|
126 | 0 | next_tvb = tvb_new_subset_length(tvb, CAN_DATA_OFFSET, can_info.len); |
127 | |
|
128 | 0 | if (!socketcan_call_subdissectors(next_tvb, pinfo, tree, &can_info, false)) { |
129 | 0 | call_data_dissector(next_tvb, pinfo, tree); |
130 | 0 | } |
131 | |
|
132 | 0 | if (tvb_captured_length_remaining(tvb, CAN_DATA_OFFSET + can_info.len) > 0) |
133 | 0 | { |
134 | 0 | proto_tree_add_item(can_tree, hf_caneth_can_padding, tvb, CAN_DATA_OFFSET + can_info.len, -1, ENC_NA); |
135 | 0 | } |
136 | 0 | return tvb_captured_length(tvb); |
137 | 0 | } |
138 | | |
139 | | static int |
140 | | dissect_caneth(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
141 | 2 | { |
142 | 2 | proto_tree *caneth_tree; |
143 | 2 | proto_item *ti; |
144 | 2 | uint32_t frame_count, offset; |
145 | 2 | tvbuff_t* next_tvb; |
146 | | |
147 | 2 | if (!test_caneth(pinfo, tvb, 0, data)) |
148 | 2 | return 0; |
149 | | |
150 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "CAN-ETH"); |
151 | 0 | col_clear(pinfo->cinfo, COL_INFO); |
152 | |
|
153 | 0 | ti = proto_tree_add_item(tree, proto_caneth, tvb, 0, -1, ENC_NA); |
154 | 0 | caneth_tree = proto_item_add_subtree(ti, ett_caneth); |
155 | |
|
156 | 0 | proto_tree_add_item(caneth_tree, hf_caneth_magic, tvb, 0, 8, ENC_ASCII); |
157 | 0 | proto_tree_add_item(caneth_tree, hf_caneth_version, tvb, 8, 1, ENC_NA); |
158 | 0 | proto_tree_add_item_ret_uint(caneth_tree, hf_caneth_frames, tvb, 9, 1, ENC_NA, &frame_count); |
159 | |
|
160 | 0 | for (offset = 10; frame_count-- > 0; offset += CAN_FRAME_LEN) |
161 | 0 | { |
162 | 0 | next_tvb = tvb_new_subset_length(tvb, offset, CAN_FRAME_LEN); |
163 | 0 | dissect_caneth_can(next_tvb, pinfo, tree, data); |
164 | 0 | } |
165 | |
|
166 | 0 | if (tvb_captured_length_remaining(tvb, offset) > 0) |
167 | 0 | { |
168 | 0 | proto_tree_add_item(caneth_tree, hf_caneth_options, tvb, offset, -1, ENC_NA); |
169 | 0 | } |
170 | |
|
171 | 0 | return tvb_captured_length(tvb); |
172 | 2 | } |
173 | | |
174 | | static bool |
175 | | dissect_caneth_heur_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
176 | 0 | { |
177 | 0 | return (udp_dissect_pdus(tvb, pinfo, tree, CANETH_MIN_LENGTH, test_caneth, |
178 | 0 | get_caneth_len, dissect_caneth, data) != 0); |
179 | 0 | } |
180 | | |
181 | | void |
182 | | proto_register_caneth(void) |
183 | 14 | { |
184 | 14 | static hf_register_info hf[] = { |
185 | 14 | { |
186 | 14 | &hf_caneth_magic, |
187 | 14 | { |
188 | 14 | "Magic", "caneth.magic", |
189 | 14 | FT_STRING, BASE_NONE, |
190 | 14 | NULL, 0x0, |
191 | 14 | "The magic identifier used to denote the start of a CAN-ETH packet", HFILL |
192 | 14 | } |
193 | 14 | }, |
194 | 14 | { |
195 | 14 | &hf_caneth_version, |
196 | 14 | { |
197 | 14 | "Version", "caneth.version", |
198 | 14 | FT_UINT8, BASE_DEC, |
199 | 14 | NULL, 0x0, |
200 | 14 | NULL, HFILL |
201 | 14 | } |
202 | 14 | }, |
203 | 14 | { |
204 | 14 | &hf_caneth_frames, |
205 | 14 | { |
206 | 14 | "CAN Frames", "caneth.frames", |
207 | 14 | FT_UINT8, BASE_DEC, |
208 | 14 | NULL, 0x0, |
209 | 14 | "Number of enclosed CAN frames", HFILL |
210 | 14 | } |
211 | 14 | }, |
212 | 14 | { |
213 | 14 | &hf_caneth_options, |
214 | 14 | { |
215 | 14 | "Options (Reserved)", "caneth.options", |
216 | 14 | FT_BYTES, BASE_NONE, |
217 | 14 | NULL, 0x0, |
218 | 14 | "Options field, reserved for future use, should be empty", HFILL |
219 | 14 | } |
220 | 14 | }, |
221 | 14 | { |
222 | 14 | &hf_caneth_can_ident_ext, |
223 | 14 | { |
224 | 14 | "Identifier", "can.id", |
225 | 14 | FT_UINT32, BASE_HEX, |
226 | 14 | NULL, CAN_EFF_MASK, |
227 | 14 | NULL, HFILL |
228 | 14 | } |
229 | 14 | }, |
230 | 14 | { |
231 | 14 | &hf_caneth_can_ident_std, |
232 | 14 | { |
233 | 14 | "Identifier", "can.id", |
234 | 14 | FT_UINT32, BASE_HEX, |
235 | 14 | NULL, CAN_SFF_MASK, |
236 | 14 | NULL, HFILL |
237 | 14 | } |
238 | 14 | }, |
239 | 14 | { |
240 | 14 | &hf_caneth_can_extflag, |
241 | 14 | { |
242 | 14 | "Extended Flag", "can.flags.xtd", |
243 | 14 | FT_BOOLEAN, BASE_NONE, |
244 | 14 | NULL, 0, |
245 | 14 | NULL, HFILL |
246 | 14 | } |
247 | 14 | }, |
248 | 14 | { |
249 | 14 | &hf_caneth_can_rtrflag, |
250 | 14 | { |
251 | 14 | "Remote Transmission Request Flag", "can.flags.rtr", |
252 | 14 | FT_BOOLEAN, BASE_NONE, |
253 | 14 | NULL, 0, |
254 | 14 | NULL, HFILL |
255 | 14 | } |
256 | 14 | }, |
257 | 14 | { |
258 | 14 | &hf_caneth_can_len, |
259 | 14 | { |
260 | 14 | "Frame-Length", "can.len", |
261 | 14 | FT_UINT8, BASE_DEC, |
262 | 14 | NULL, 0x0, |
263 | 14 | NULL, HFILL |
264 | 14 | } |
265 | 14 | }, |
266 | 14 | { |
267 | 14 | &hf_caneth_can_padding, |
268 | 14 | { |
269 | 14 | "Padding", "caneth.can.padding", |
270 | 14 | FT_BYTES, BASE_NONE, |
271 | 14 | NULL, 0x0, |
272 | 14 | NULL, HFILL |
273 | 14 | } |
274 | 14 | }, |
275 | 14 | }; |
276 | | |
277 | 14 | static int *ett[] = { |
278 | 14 | &ett_caneth, |
279 | 14 | &ett_caneth_frames, |
280 | 14 | &ett_caneth_can, |
281 | 14 | }; |
282 | | |
283 | 14 | proto_caneth = proto_register_protocol("Controller Area Network over Ethernet", "CAN-ETH", "caneth"); |
284 | | |
285 | 14 | proto_register_field_array(proto_caneth, hf, array_length(hf)); |
286 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
287 | | |
288 | 14 | caneth_handle = register_dissector("caneth", dissect_caneth, proto_caneth); |
289 | 14 | } |
290 | | |
291 | | void |
292 | | proto_reg_handoff_caneth(void) |
293 | 14 | { |
294 | 14 | dissector_add_uint_with_preference("udp.port", CANETH_UDP_PORT, caneth_handle); |
295 | | |
296 | 14 | heur_dissector_add("udp", dissect_caneth_heur_udp, "CAN-ETH over UDP", "caneth_udp", proto_caneth, HEURISTIC_DISABLE); |
297 | | |
298 | 14 | proto_can = proto_get_id_by_filter_name("can"); |
299 | 14 | } |
300 | | |
301 | | /* |
302 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
303 | | * |
304 | | * Local variables: |
305 | | * c-basic-offset: 4 |
306 | | * tab-width: 8 |
307 | | * indent-tabs-mode: nil |
308 | | * End: |
309 | | * |
310 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
311 | | * :indentSize=4:tabSize=8:noTabs=true: |
312 | | */ |