epan/dissectors/pidl/samr/samr.cnf cnf_dissect_lsa_BinaryString => lsarpc_dissect_str...
[wireshark-sm.git] / epan / dissectors / packet-uavcan-can.c
blob56d6fbfb9dc4466c7b75d846aae7c58c6c7f3477
1 /* packet-uavcan-can.c
2 * Routines for dissection of UAVCAN/CAN
4 * Copyright 2020-2021 NXP
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
12 #include "config.h"
14 #include <inttypes.h>
15 #include <epan/packet.h>
16 #include <epan/prefs.h>
17 #include <epan/address_types.h>
18 #include <epan/to_str.h>
19 #include <epan/expert.h>
20 #include <epan/reassemble.h>
21 #include <epan/proto_data.h>
22 #include <epan/crc16-tvb.h>
24 #include "packet-socketcan.h"
25 #include "packet-uavcan-dsdl.h"
27 #define ANONYMOUS_FLAG 0x8000
28 #define BROADCAST_FLAG 0x4000
29 #define ADDR_MASK 0XFF
31 #define START_OF_TRANSFER 0x80
32 #define END_OF_TRANSFER 0x40
33 #define TOGGLE 0x20
34 #define TRANSFER_ID 0x1F
36 #define UAVCAN_SUBJECT_ID(can_id) ((can_id & 0x001FFF00) >> 8)
37 #define UAVCAN_SERVICE_ID(can_id) ((can_id & 0x007FC000) >> 14)
38 #define UAVCAN_DESTINATION_ID(can_id) ((can_id & 0x00003F80) >> 7)
39 #define UAVCAN_SOURCE_ID(can_id) ((can_id & 0x0000007F))
40 #define UAVCAN_IS_SERVICE(can_id) ((can_id & 0x2000000) != 0)
41 #define UAVCAN_IS_MESSAGE(can_id) ((can_id & 0x2000000) == 0)
42 #define UAVCAN_IS_REQUEST(can_id) ((can_id & 0x01000000) != 0)
43 #define UAVCAN_IS_RESPONSE(can_id) ((can_id & 0x01000000) == 0)
44 #define UAVCAN_IS_ANONYMOUS(can_id) ((can_id & 0x01000000) != 0)
46 struct uavcan_proto_data
48 uint32_t seq_id;
49 bool toggle_error;
52 void proto_register_uavcan(void);
53 void proto_reg_handoff_uavcan(void);
55 static dissector_handle_t uavcan_handle;
57 static int proto_uavcan;
59 static int hf_uavcan_can_id;
60 static int hf_uavcan_priority;
61 static int hf_uavcan_anonymous;
62 static int hf_uavcan_req_not_rsp;
63 static int hf_uavcan_serv_not_msg;
64 static int hf_uavcan_subject_id;
65 static int hf_uavcan_service_id;
66 static int hf_uavcan_dst_addr;
67 static int hf_uavcan_src_addr;
68 static int hf_uavcan_data;
69 static int hf_uavcan_start_of_transfer;
70 static int hf_uavcan_end_of_transfer;
71 static int hf_uavcan_toggle;
72 static int hf_uavcan_transfer_id;
74 static int uavcan_address_type = -1;
76 static wmem_tree_t *fragment_info_table;
78 static reassembly_table uavcan_reassembly_table;
80 static int hf_uavcan_packet_crc;
82 static int ett_uavcan;
83 static int ett_uavcan_can;
84 static int ett_uavcan_message;
86 static expert_field ei_uavcan_toggle_bit_error;
87 static expert_field ei_uavcan_transfer_crc_error;
89 static int ett_uavcan_fragment;
90 static int ett_uavcan_fragments;
91 static int hf_uavcan_fragments;
92 static int hf_uavcan_fragment;
93 static int hf_uavcan_fragment_overlap;
94 static int hf_uavcan_fragment_overlap_conflicts;
95 static int hf_uavcan_fragment_multiple_tails;
96 static int hf_uavcan_fragment_too_long_fragment;
97 static int hf_uavcan_fragment_error;
98 static int hf_uavcan_fragment_count;
99 static int hf_uavcan_reassembled_in;
100 static int hf_uavcan_reassembled_length;
102 /* fragment struct to store packet assembly data */
103 typedef struct _fragment_info_t
105 int toggle;
106 int fragment_id;
107 uint32_t seq_id;
108 } fragment_info_t;
110 uint32_t uavcan_seq_id;
112 static const fragment_items uavcan_frag_items = {
113 /* Fragment subtrees */
114 &ett_uavcan_fragment,
115 &ett_uavcan_fragments,
117 /* Fragment fields */
118 &hf_uavcan_fragments,
119 &hf_uavcan_fragment,
120 &hf_uavcan_fragment_overlap,
121 &hf_uavcan_fragment_overlap_conflicts,
122 &hf_uavcan_fragment_multiple_tails,
123 &hf_uavcan_fragment_too_long_fragment,
124 &hf_uavcan_fragment_error,
126 &hf_uavcan_fragment_count,
128 /* Reassembled in field */
129 &hf_uavcan_reassembled_in,
131 /* Reassembled length field */
132 &hf_uavcan_reassembled_length,
134 /* Reassembled data field */
135 NULL,
137 /* Tag */
138 "Message fragments"
141 static dissector_handle_t dsdl_message_handle;
142 static dissector_handle_t dsdl_request_handle;
143 static dissector_handle_t dsdl_response_handle;
145 static const value_string uavcan_priority_vals[] = {
146 { 0, "Exceptional" },
147 { 1, "Immediate" },
148 { 2, "Fast" },
149 { 3, "High" },
150 { 4, "Nominal" },
151 { 5, "Low" },
152 { 6, "Slow" },
153 { 7, "Optional" },
154 { 0, NULL }
157 static int
158 dissect_uavcan(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
160 proto_item *ti, *toggle, *transfer_crc;
161 proto_tree *uavcan_tree, *can_id_tree, *can_data_tree, *dsdl_tree;
163 int offset = 0;
164 struct can_info can_info;
165 uint16_t *src_addr, *dest_addr;
166 uint8_t tail_byte;
167 fragment_info_t *fragment_info = NULL;
168 unsigned reported_length;
169 uint32_t lookup_id = 0;
171 /* Semi-unique lookup id for reassembly lookup table note transfer-ID rolls-over every 32 times */
173 reported_length = tvb_reported_length(tvb);
175 DISSECTOR_ASSERT(data);
176 can_info = *((struct can_info *) data);
178 tail_byte = tvb_get_uint8(tvb, reported_length - 1);
180 if ((can_info.id & CAN_ERR_FLAG) ||
181 !(can_info.id & CAN_EFF_FLAG)) {
182 /* Error frames and frames with standards ids are not for us */
183 return 0;
186 if ((tail_byte & (START_OF_TRANSFER | TOGGLE)) ==
187 (START_OF_TRANSFER)) {
188 /* UAVCAN v0 Frame */
189 return 0;
192 if ((tail_byte & (START_OF_TRANSFER | END_OF_TRANSFER)) !=
193 (START_OF_TRANSFER | END_OF_TRANSFER)) { /* Multi-frame */
194 if (UAVCAN_IS_MESSAGE(can_info.id)) { /* Message */
195 lookup_id = 0; // Bit 0 false indicates message
196 lookup_id |= UAVCAN_SUBJECT_ID(can_info.id) << 1;
197 lookup_id |= UAVCAN_SOURCE_ID(can_info.id) << 11;
198 lookup_id |= (tail_byte & TRANSFER_ID) << 18;
199 } else { /* Service */
200 lookup_id = 1; // Bit 0 true indicates service
201 lookup_id |= ((can_info.id & 0x01000000) >> 24) << 1;
202 lookup_id |= UAVCAN_SERVICE_ID(can_info.id) << 2;
203 lookup_id |= UAVCAN_DESTINATION_ID(can_info.id) << 11;
204 lookup_id |= UAVCAN_SOURCE_ID(can_info.id) << 18;
205 lookup_id |= (tail_byte & TRANSFER_ID) << 25;
208 fragment_info = (fragment_info_t *) wmem_tree_lookup32(fragment_info_table, lookup_id);
210 if (!(tail_byte & START_OF_TRANSFER) && fragment_info == NULL) {
211 /* Lookup id doesn't exist, but not a start of transfer discard potentially a UAVCANv0 frame */
212 return 0;
217 col_set_str(pinfo->cinfo, COL_PROTOCOL, "UAVCAN/CAN");
218 col_clear(pinfo->cinfo, COL_INFO);
220 ti = proto_tree_add_item(tree, proto_uavcan, tvb, offset, reported_length, ENC_NA);
221 uavcan_tree = proto_item_add_subtree(ti, ett_uavcan);
223 can_id_tree = proto_tree_add_subtree_format(uavcan_tree, tvb, 0, 0,
224 ett_uavcan_can, &ti, "CAN ID field: 0x%08x",
225 can_info.id);
226 proto_item_set_generated(ti);
228 ti = proto_tree_add_uint(can_id_tree, hf_uavcan_can_id, tvb, 0, 0, can_info.id);
229 proto_item_set_generated(ti);
231 /* Dissect UAVCAN/CAN Message frame */
232 if (UAVCAN_IS_MESSAGE(can_info.id)) {
233 ti = proto_tree_add_uint(can_id_tree, hf_uavcan_priority, tvb, 0, 0, can_info.id);
234 proto_item_set_generated(ti);
235 ti = proto_tree_add_uint(can_id_tree, hf_uavcan_serv_not_msg, tvb, 0, 0, can_info.id);
236 proto_item_set_generated(ti);
237 ti = proto_tree_add_uint(can_id_tree, hf_uavcan_anonymous, tvb, 0, 0, can_info.id);
238 proto_item_set_generated(ti);
239 ti = proto_tree_add_uint(can_id_tree, hf_uavcan_subject_id, tvb, 0, 0, can_info.id);
240 proto_item_set_generated(ti);
241 ti = proto_tree_add_uint(can_id_tree, hf_uavcan_src_addr, tvb, 0, 0, can_info.id);
242 proto_item_set_generated(ti);
244 /* Set source address */
245 src_addr = wmem_new(pinfo->pool, uint16_t);
246 *src_addr = (uint16_t) UAVCAN_SOURCE_ID(can_info.id);
248 if (UAVCAN_IS_ANONYMOUS(can_info.id)) {
249 *src_addr |= ANONYMOUS_FLAG;
252 set_address(&pinfo->src, uavcan_address_type, 2, (const void *) src_addr);
254 /* Fill in "destination" address even if its "broadcast" */
255 dest_addr = wmem_new(pinfo->pool, uint16_t);
256 *dest_addr = BROADCAST_FLAG;
257 set_address(&pinfo->dst, uavcan_address_type, 2, (const void *) dest_addr);
259 col_add_fstr(pinfo->cinfo, COL_INFO, "Message: %d (%s)", UAVCAN_SUBJECT_ID(can_info.id),
260 rval_to_str_const(UAVCAN_SUBJECT_ID(can_info.id), uavcan_subject_id_vals, "Reserved"));
261 } else { /* UAVCAN/CAN Service frame */
262 ti = proto_tree_add_uint(can_id_tree, hf_uavcan_priority, tvb, 0, 0, can_info.id);
263 proto_item_set_generated(ti);
264 ti = proto_tree_add_uint(can_id_tree, hf_uavcan_serv_not_msg, tvb, 0, 0, can_info.id);
265 proto_item_set_generated(ti);
266 ti = proto_tree_add_uint(can_id_tree, hf_uavcan_req_not_rsp, tvb, 0, 0, can_info.id);
267 proto_item_set_generated(ti);
268 ti = proto_tree_add_uint(can_id_tree, hf_uavcan_service_id, tvb, 0, 0, can_info.id);
269 proto_item_set_generated(ti);
270 ti = proto_tree_add_uint(can_id_tree, hf_uavcan_dst_addr, tvb, 0, 0, can_info.id);
271 proto_item_set_generated(ti);
272 ti = proto_tree_add_uint(can_id_tree, hf_uavcan_src_addr, tvb, 0, 0, can_info.id);
273 proto_item_set_generated(ti);
275 /* Set source address */
276 src_addr = wmem_new(pinfo->pool, uint16_t);
277 *src_addr = (uint16_t) UAVCAN_SOURCE_ID(can_info.id);
278 set_address(&pinfo->src, uavcan_address_type, 2, (const void *) src_addr);
280 dest_addr = wmem_new(pinfo->pool, uint16_t);
281 *dest_addr = (uint16_t) UAVCAN_DESTINATION_ID(can_info.id);
282 set_address(&pinfo->dst, uavcan_address_type, 2, (const void *) dest_addr);
283 if (UAVCAN_IS_RESPONSE(can_info.id)) {
284 col_add_fstr(pinfo->cinfo, COL_INFO, "Service response: %d (%s)", UAVCAN_SERVICE_ID(can_info.id),
285 rval_to_str_const(UAVCAN_SERVICE_ID(can_info.id), uavcan_service_id_vals, "Reserved"));
286 } else {
287 col_add_fstr(pinfo->cinfo, COL_INFO, "Service request: %d (%s)", UAVCAN_SERVICE_ID(can_info.id),
288 rval_to_str_const(UAVCAN_SERVICE_ID(can_info.id), uavcan_service_id_vals, "Reserved"));
292 can_data_tree = proto_tree_add_subtree(uavcan_tree, tvb, 0, -1, ett_uavcan_message, NULL, "CAN data field");
294 proto_tree_add_item(can_data_tree, hf_uavcan_start_of_transfer, tvb,
295 reported_length - 1, 1, ENC_NA);
296 proto_tree_add_item(can_data_tree, hf_uavcan_end_of_transfer, tvb,
297 reported_length - 1, 1, ENC_NA);
298 toggle = proto_tree_add_item(can_data_tree, hf_uavcan_toggle, tvb,
299 reported_length - 1, 1, ENC_NA);
300 proto_tree_add_item(can_data_tree, hf_uavcan_transfer_id, tvb,
301 reported_length - 1, 1, ENC_NA);
302 proto_tree_add_item(can_data_tree, hf_uavcan_data, tvb, 0, reported_length - 1,
303 ENC_NA);
305 if ((tail_byte & (START_OF_TRANSFER | END_OF_TRANSFER)) ==
306 (START_OF_TRANSFER | END_OF_TRANSFER)) { /* Single frame */
307 dsdl_tree = proto_tree_add_subtree(uavcan_tree, tvb, 0, tvb_reported_length(
308 tvb) - 1, ett_uavcan_message, NULL, "");
309 tvb_set_reported_length(tvb, reported_length - 1); /* Don't pass Tail byte to DSDL */
311 if (UAVCAN_IS_MESSAGE(can_info.id)) {
312 uint32_t id;
313 id = UAVCAN_SUBJECT_ID(can_info.id);
314 proto_item_append_text(dsdl_tree, "Message");
315 call_dissector_with_data(dsdl_message_handle, tvb, pinfo, dsdl_tree,
316 GUINT_TO_POINTER((unsigned) id));
317 } else if (UAVCAN_IS_SERVICE(can_info.id)) {
318 uint32_t id;
319 id = UAVCAN_SERVICE_ID(can_info.id);
321 if (UAVCAN_IS_REQUEST(can_info.id)) {
322 proto_item_append_text(dsdl_tree, "Service request");
323 call_dissector_with_data(dsdl_request_handle, tvb, pinfo, dsdl_tree, GUINT_TO_POINTER(
324 (unsigned) id));
325 } else {
326 proto_item_append_text(dsdl_tree, "Service response");
327 call_dissector_with_data(dsdl_response_handle, tvb, pinfo, dsdl_tree, GUINT_TO_POINTER(
328 (unsigned) id));
333 /* Re-assembly attempt */
335 if ((tail_byte & (START_OF_TRANSFER | END_OF_TRANSFER)) !=
336 (START_OF_TRANSFER | END_OF_TRANSFER)) { /* Multi-frame */
337 struct uavcan_proto_data *uavcan_frame_data;
339 if (!PINFO_FD_VISITED(pinfo)) { /* Not visited */
340 if (fragment_info == NULL) { /* Doesn't exist, allocate lookup_id */
341 fragment_info = (fragment_info_t *) wmem_new(wmem_file_scope(), fragment_info_t);
342 fragment_info->fragment_id = 0;
343 fragment_info->toggle = tail_byte & TOGGLE;
345 wmem_tree_insert32(fragment_info_table, lookup_id, fragment_info);
348 /* Store sequence number and status in pinfo so we can revisit later */
349 uavcan_frame_data =
350 wmem_new0(wmem_file_scope(), struct uavcan_proto_data);
351 p_add_proto_data(wmem_file_scope(), pinfo, proto_uavcan, 0, uavcan_frame_data);
353 if ((tail_byte & START_OF_TRANSFER) != 0) { /* Start of transfer */
354 uavcan_frame_data->toggle_error = 0;
355 fragment_info->fragment_id = 0;
356 fragment_info->seq_id = uavcan_seq_id;
357 uavcan_seq_id += 1;
358 } else { /* Update transfer */
359 fragment_info->fragment_id += 1;
360 uavcan_frame_data->toggle_error =
361 ((tail_byte & TOGGLE) == fragment_info->toggle) ? true : false;
364 uavcan_frame_data->seq_id = fragment_info->seq_id;
366 fragment_info->toggle = tail_byte & TOGGLE;
368 pinfo->fragmented = true;
369 fragment_add_seq_check(&uavcan_reassembly_table,
370 tvb, offset, pinfo, fragment_info->seq_id, NULL, /* ID for fragments belonging together */
371 fragment_info->fragment_id, /* fragment sequence number */
372 tvb_captured_length_remaining(tvb, offset) - 1, /* fragment length - minus tail byte */
373 ((tail_byte & END_OF_TRANSFER) == 0) ? true : false); /* More fragments? */
374 } else { /* Visited reassembled data */
375 fragment_head *reassembled = NULL;
376 tvbuff_t *reassembled_tvb;
377 proto_tree *multi_tree;
379 uavcan_frame_data = (struct uavcan_proto_data *) p_get_proto_data(
380 wmem_file_scope(), pinfo, proto_uavcan, 0);
382 reassembled = fragment_get_reassembled_id(&uavcan_reassembly_table, pinfo,
383 uavcan_frame_data->seq_id);
385 if (reassembled) {
386 if (uavcan_frame_data->toggle_error == 1) {
387 expert_add_info_format(pinfo, toggle, &ei_uavcan_toggle_bit_error,
388 "Expected Toggle %u got %u.",
389 !((tail_byte & TOGGLE) != 0),
390 ((tail_byte & TOGGLE) != 0));
393 col_append_str(pinfo->cinfo, COL_INFO,
394 " (Multi-frame)");
396 reassembled_tvb = tvb_new_chain(tvb, reassembled->tvb_data); /* Reassembled tvb chain */
398 multi_tree = proto_tree_add_subtree(uavcan_tree, reassembled_tvb, 0,
399 -1, ett_uavcan_message, NULL,
400 "Multi-frame");
402 process_reassembled_data(tvb, offset, pinfo,
403 "Reassembled Message", reassembled, &uavcan_frag_items,
404 NULL, multi_tree);
406 /* Parsing reassembled data */
407 if ((tail_byte & END_OF_TRANSFER) != 0) {
408 transfer_crc = proto_tree_add_item(multi_tree, hf_uavcan_packet_crc,
409 reassembled_tvb,
410 tvb_reported_length(reassembled_tvb) - 2,
411 2, ENC_BIG_ENDIAN);
413 uint16_t packet_crc = tvb_get_uint16(reassembled_tvb,
414 tvb_reported_length(reassembled_tvb) - 2,
415 ENC_BIG_ENDIAN);
416 uint16_t calc_crc = crc16_x25_ccitt_tvb(reassembled_tvb,
417 tvb_reported_length(reassembled_tvb) - 2);
419 if (packet_crc != calc_crc) {
420 expert_add_info_format(pinfo, transfer_crc, &ei_uavcan_transfer_crc_error,
421 "Expected CRC16 %X got %X.",
422 calc_crc, packet_crc);
425 tvb_set_reported_length(reassembled_tvb, tvb_reported_length(reassembled_tvb) - 2); /* Don't pass CRC16 to DSDL */
427 dsdl_tree = proto_tree_add_subtree(uavcan_tree, reassembled_tvb, 0,
428 -1, ett_uavcan_message, NULL, "");
430 /* Pass payload to DSDL dissector */
431 if (UAVCAN_IS_MESSAGE(can_info.id)) {
432 uint32_t id = UAVCAN_SUBJECT_ID(can_info.id);
433 proto_item_append_text(dsdl_tree, "Message");
435 call_dissector_with_data(dsdl_message_handle, reassembled_tvb, pinfo,
436 dsdl_tree,
437 GUINT_TO_POINTER((unsigned) id));
438 } else if (UAVCAN_IS_SERVICE(can_info.id)) {
439 uint32_t id = UAVCAN_SERVICE_ID(can_info.id);
441 if (UAVCAN_IS_REQUEST(can_info.id)) {
442 proto_item_append_text(dsdl_tree, "Service request");
443 call_dissector_with_data(dsdl_request_handle, reassembled_tvb, pinfo,
444 dsdl_tree, GUINT_TO_POINTER((unsigned) id));
445 } else {
446 proto_item_append_text(dsdl_tree, "Service response");
447 call_dissector_with_data(dsdl_response_handle, reassembled_tvb, pinfo,
448 dsdl_tree, GUINT_TO_POINTER((unsigned) id));
456 return tvb_captured_length(tvb);
459 static int
460 UAVCAN_addr_to_str(const address *addr, char *buf, int buf_len)
462 const uint16_t *addrdata = (const uint16_t *) addr->data;
464 if ((*addrdata & ANONYMOUS_FLAG) != 0) {
465 return (int) snprintf(buf, buf_len, "Anonymous");
466 } else if ((*addrdata & BROADCAST_FLAG) != 0) {
467 return (int) snprintf(buf, buf_len, "Broadcast");
468 } else {
469 uint8_t real_addr = (uint8_t) (*addrdata & ADDR_MASK);
470 uint32_to_str_buf(real_addr, buf, buf_len);
471 return (int) strlen(buf);
475 static int
476 UAVCAN_addr_str_len(const address *addr _U_)
478 return 12; /* Leaves required space (10 bytes) for uint_to_str_back() */
481 static const char *
482 UAVCAN_col_filter_str(const address *addr _U_, bool is_src)
484 if (is_src)
485 return "uavcan_can.src_addr";
487 return "uavcan_can.dst_addr";
490 static int
491 UAVCAN_addr_len(void)
493 return 2;
496 void
497 proto_register_uavcan(void)
499 static hf_register_info hf[] = {
500 {&hf_uavcan_can_id,
501 {"CAN Identifier", "uavcan_can.can_id",
502 FT_UINT32, BASE_HEX, NULL, CAN_EFF_MASK, NULL, HFILL}},
503 {&hf_uavcan_priority,
504 {"Priority", "uavcan_can.priority",
505 FT_UINT32, BASE_DEC, VALS(uavcan_priority_vals), 0x1C000000, NULL, HFILL}},
506 {&hf_uavcan_serv_not_msg,
507 {"Service, not message", "uavcan_can.serv_not_msg",
508 FT_UINT32, BASE_DEC, NULL, 0x02000000, NULL, HFILL}},
509 {&hf_uavcan_anonymous,
510 {"Anonymous", "uavcan_can.anonymous",
511 FT_UINT32, BASE_DEC, NULL, 0x01000000, NULL, HFILL}},
512 {&hf_uavcan_req_not_rsp,
513 {"Request, not response", "uavcan_can.req_not_rsp",
514 FT_UINT32, BASE_DEC, NULL, 0x01000000, NULL, HFILL}},
515 {&hf_uavcan_subject_id,
516 {"Subject ID", "uavcan_can.subject_id",
517 FT_UINT32, BASE_DEC|BASE_RANGE_STRING, RVALS(uavcan_subject_id_vals), 0x001FFF00, NULL, HFILL}},
518 {&hf_uavcan_service_id,
519 {"Service ID", "uavcan_can.service_id",
520 FT_UINT32, BASE_DEC|BASE_RANGE_STRING, RVALS(uavcan_service_id_vals), 0x007FC000, NULL, HFILL}},
521 {&hf_uavcan_dst_addr,
522 {"Destination node-ID", "uavcan_can.dst_addr",
523 FT_UINT32, BASE_DEC, NULL, 0x00003F80, NULL, HFILL}},
524 {&hf_uavcan_src_addr,
525 {"Source node-ID", "uavcan_can.src_addr",
526 FT_UINT32, BASE_DEC, NULL, 0x0000007F, NULL, HFILL}},
527 {&hf_uavcan_data,
528 {"Payload", "uavcan_can.payload",
529 FT_BYTES, BASE_NONE | BASE_ALLOW_ZERO, NULL, 0x0, NULL, HFILL}},
530 {&hf_uavcan_start_of_transfer,
531 {"Start of transfer", "uavcan_can.start_of_transfer",
532 FT_UINT8, BASE_DEC, NULL, START_OF_TRANSFER, NULL, HFILL}},
533 {&hf_uavcan_end_of_transfer,
534 {"End of transfer", "uavcan_can.end_of_transfer",
535 FT_UINT8, BASE_DEC, NULL, END_OF_TRANSFER, NULL, HFILL}},
536 {&hf_uavcan_toggle,
537 {"Toggle", "uavcan_can.toggle",
538 FT_UINT8, BASE_DEC, NULL, TOGGLE, NULL, HFILL}},
539 {&hf_uavcan_transfer_id,
540 {"Transfer-ID", "uavcan_can.transfer_id",
541 FT_UINT8, BASE_DEC, NULL, TRANSFER_ID, NULL, HFILL}},
542 {&hf_uavcan_fragments,
543 {"Message fragments", "uavcan_can.multiframe.fragments",
544 FT_NONE, BASE_NONE, NULL, 0x00,
545 NULL, HFILL}},
546 {&hf_uavcan_fragment,
547 {"Message fragment", "uavcan_can.multiframe.fragment",
548 FT_FRAMENUM, BASE_NONE, NULL, 0x00,
549 NULL, HFILL}},
550 {&hf_uavcan_fragment_overlap,
551 {"Message fragment overlap",
552 "uavcan_can.multiframe.fragment.overlap",
553 FT_BOOLEAN, BASE_NONE, NULL, 0x00,
554 NULL, HFILL}},
555 {&hf_uavcan_fragment_overlap_conflicts,
556 {"Message fragment overlapping with conflicting data",
557 "uavcan_can.multiframe.fragment.overlap.conflicts",
558 FT_BOOLEAN, BASE_NONE, NULL, 0x00,
559 NULL, HFILL}},
560 {&hf_uavcan_fragment_multiple_tails,
561 {"Message has multiple tail fragments",
562 "uavcan_can.multiframe.fragment.multiple_tails",
563 FT_BOOLEAN, BASE_NONE, NULL, 0x00,
564 NULL, HFILL}},
565 {&hf_uavcan_fragment_too_long_fragment,
566 {"Message fragment too long",
567 "uavcan_can.multiframe.fragment.too_long_fragment",
568 FT_BOOLEAN, BASE_NONE, NULL, 0x00,
569 NULL, HFILL}},
570 {&hf_uavcan_fragment_error,
571 {"Message defragmentation error",
572 "uavcan_can.multiframe.fragment.error",
573 FT_FRAMENUM, BASE_NONE, NULL, 0x00,
574 NULL, HFILL}},
575 {&hf_uavcan_fragment_count,
576 {"Message fragment count", "uavcan_can.fragment.count",
577 FT_UINT32, BASE_DEC, NULL, 0x00,
578 NULL, HFILL}},
579 {&hf_uavcan_reassembled_in,
580 {"Reassembled in",
581 "uavcan_can.multiframe.reassembled.in",
582 FT_FRAMENUM, BASE_NONE, NULL, 0x00,
583 NULL, HFILL}},
584 {&hf_uavcan_reassembled_length,
585 {"Reassembled payload length",
586 "uavcan_can.multiframe.reassembled.length",
587 FT_UINT32, BASE_DEC, NULL, 0x00,
588 NULL, HFILL}},
589 {&hf_uavcan_packet_crc,
590 {"Transfer CRC", "uavcan_can.multiframe.crc",
591 FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}}
594 static int *ett[] = {
595 &ett_uavcan,
596 &ett_uavcan_can,
597 &ett_uavcan_message,
598 &ett_uavcan_fragment,
599 &ett_uavcan_fragments
602 reassembly_table_register(&uavcan_reassembly_table,
603 &addresses_reassembly_table_functions);
604 fragment_info_table = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
607 expert_module_t *expert_uavcan;
609 proto_uavcan = proto_register_protocol("UAVCAN/CAN", "UAVCAN/CAN", "uavcan_can");
612 static ei_register_info ei[] = {
613 {&ei_uavcan_toggle_bit_error,
614 {"uavcan_can.toggle_bit.error", PI_MALFORMED, PI_ERROR,
615 "Toggle bit error",
616 EXPFILL}},
617 {&ei_uavcan_transfer_crc_error,
618 {"uavcan_can.transfer_crc.error", PI_MALFORMED, PI_ERROR,
619 "Transfer CRC don't match",
620 EXPFILL}}
624 proto_register_field_array(proto_uavcan, hf, array_length(hf));
625 proto_register_subtree_array(ett, array_length(ett));
627 uavcan_handle = register_dissector("uavcan_can", dissect_uavcan, proto_uavcan);
629 expert_uavcan = expert_register_protocol(proto_uavcan);
630 expert_register_field_array(expert_uavcan, ei, array_length(ei));
632 uavcan_address_type = address_type_dissector_register("AT_UAVCAN", "UAVCAN Address",
633 UAVCAN_addr_to_str, UAVCAN_addr_str_len,
634 NULL, UAVCAN_col_filter_str,
635 UAVCAN_addr_len, NULL, NULL);
638 void
639 proto_reg_handoff_uavcan(void)
641 dsdl_message_handle = find_dissector_add_dependency("uavcan_dsdl.message", proto_uavcan);
642 dsdl_request_handle = find_dissector_add_dependency("uavcan_dsdl.request", proto_uavcan);
643 dsdl_response_handle = find_dissector_add_dependency("uavcan_dsdl.response", proto_uavcan);
645 dissector_add_for_decode_as("can.subdissector", uavcan_handle);
649 * Editor modelines - https://www.wireshark.org/tools/modelines.html
651 * Local variables:
652 * c-basic-offset: 4
653 * tab-width: 8
654 * indent-tabs-mode: nil
655 * End:
657 * vi: set shiftwidth=4 tabstop=8 expandtab:
658 * :indentSize=4:tabSize=8:noTabs=true: