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
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
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
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
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
,
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 */
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" },
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
;
164 struct can_info can_info
;
165 uint16_t *src_addr
, *dest_addr
;
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 */
186 if ((tail_byte
& (START_OF_TRANSFER
| TOGGLE
)) ==
187 (START_OF_TRANSFER
)) {
188 /* UAVCAN v0 Frame */
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 */
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",
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"));
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,
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
)) {
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
)) {
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(
326 proto_item_append_text(dsdl_tree
, "Service response");
327 call_dissector_with_data(dsdl_response_handle
, tvb
, pinfo
, dsdl_tree
, GUINT_TO_POINTER(
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 */
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
;
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
);
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
,
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
,
402 process_reassembled_data(tvb
, offset
, pinfo
,
403 "Reassembled Message", reassembled
, &uavcan_frag_items
,
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
,
410 tvb_reported_length(reassembled_tvb
) - 2,
413 uint16_t packet_crc
= tvb_get_uint16(reassembled_tvb
,
414 tvb_reported_length(reassembled_tvb
) - 2,
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
,
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
));
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
);
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");
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
);
476 UAVCAN_addr_str_len(const address
*addr _U_
)
478 return 12; /* Leaves required space (10 bytes) for uint_to_str_back() */
482 UAVCAN_col_filter_str(const address
*addr _U_
, bool is_src
)
485 return "uavcan_can.src_addr";
487 return "uavcan_can.dst_addr";
491 UAVCAN_addr_len(void)
497 proto_register_uavcan(void)
499 static hf_register_info hf
[] = {
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
}},
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
}},
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,
546 {&hf_uavcan_fragment
,
547 {"Message fragment", "uavcan_can.multiframe.fragment",
548 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x00,
550 {&hf_uavcan_fragment_overlap
,
551 {"Message fragment overlap",
552 "uavcan_can.multiframe.fragment.overlap",
553 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00,
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,
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,
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,
570 {&hf_uavcan_fragment_error
,
571 {"Message defragmentation error",
572 "uavcan_can.multiframe.fragment.error",
573 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x00,
575 {&hf_uavcan_fragment_count
,
576 {"Message fragment count", "uavcan_can.fragment.count",
577 FT_UINT32
, BASE_DEC
, NULL
, 0x00,
579 {&hf_uavcan_reassembled_in
,
581 "uavcan_can.multiframe.reassembled.in",
582 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x00,
584 {&hf_uavcan_reassembled_length
,
585 {"Reassembled payload length",
586 "uavcan_can.multiframe.reassembled.length",
587 FT_UINT32
, BASE_DEC
, NULL
, 0x00,
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
[] = {
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
,
617 {&ei_uavcan_transfer_crc_error
,
618 {"uavcan_can.transfer_crc.error", PI_MALFORMED
, PI_ERROR
,
619 "Transfer CRC don't match",
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
);
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
654 * indent-tabs-mode: nil
657 * vi: set shiftwidth=4 tabstop=8 expandtab:
658 * :indentSize=4:tabSize=8:noTabs=true: