diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
commit | e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch) | |
tree | 68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/dissectors/packet-uavcan-can.c | |
parent | Initial commit. (diff) | |
download | wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip |
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/dissectors/packet-uavcan-can.c')
-rw-r--r-- | epan/dissectors/packet-uavcan-can.c | 659 |
1 files changed, 659 insertions, 0 deletions
diff --git a/epan/dissectors/packet-uavcan-can.c b/epan/dissectors/packet-uavcan-can.c new file mode 100644 index 00000000..0240bf98 --- /dev/null +++ b/epan/dissectors/packet-uavcan-can.c @@ -0,0 +1,659 @@ +/* packet-uavcan-can.c + * Routines for dissection of UAVCAN/CAN + * + * Copyright 2020-2021 NXP + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#include "config.h" + +#include <inttypes.h> +#include <epan/packet.h> +#include <epan/prefs.h> +#include <epan/address_types.h> +#include <epan/to_str.h> +#include <epan/expert.h> +#include <epan/reassemble.h> +#include <epan/proto_data.h> +#include <epan/crc16-tvb.h> + +#include "packet-socketcan.h" +#include "packet-uavcan-dsdl.h" + +#define ANONYMOUS_FLAG 0x8000 +#define BROADCAST_FLAG 0x4000 +#define ADDR_MASK 0XFF + +#define START_OF_TRANSFER 0x80 +#define END_OF_TRANSFER 0x40 +#define TOGGLE 0x20 +#define TRANSFER_ID 0x1F + +#define UAVCAN_SUBJECT_ID(can_id) ((can_id & 0x001FFF00) >> 8) +#define UAVCAN_SERVICE_ID(can_id) ((can_id & 0x007FC000) >> 14) +#define UAVCAN_DESTINATION_ID(can_id) ((can_id & 0x00003F80) >> 7) +#define UAVCAN_SOURCE_ID(can_id) ((can_id & 0x0000007F)) +#define UAVCAN_IS_SERVICE(can_id) ((can_id & 0x2000000) != 0) +#define UAVCAN_IS_MESSAGE(can_id) ((can_id & 0x2000000) == 0) +#define UAVCAN_IS_REQUEST(can_id) ((can_id & 0x01000000) != 0) +#define UAVCAN_IS_RESPONSE(can_id) ((can_id & 0x01000000) == 0) +#define UAVCAN_IS_ANONYMOUS(can_id) ((can_id & 0x01000000) != 0) + +struct uavcan_proto_data +{ + guint32 seq_id; + gboolean toggle_error; +}; + +void proto_register_uavcan(void); +void proto_reg_handoff_uavcan(void); + +static dissector_handle_t uavcan_handle; + +static int proto_uavcan = -1; + +static int hf_uavcan_can_id = -1; +static int hf_uavcan_priority = -1; +static int hf_uavcan_anonymous = -1; +static int hf_uavcan_req_not_rsp = -1; +static int hf_uavcan_serv_not_msg = -1; +static int hf_uavcan_subject_id = -1; +static int hf_uavcan_service_id = -1; +static int hf_uavcan_dst_addr = -1; +static int hf_uavcan_src_addr = -1; +static int hf_uavcan_data = -1; +static int hf_uavcan_start_of_transfer = -1; +static int hf_uavcan_end_of_transfer = -1; +static int hf_uavcan_toggle = -1; +static int hf_uavcan_transfer_id = -1; + +static int uavcan_address_type = -1; + +static wmem_tree_t *fragment_info_table = NULL; + +static reassembly_table uavcan_reassembly_table; + +static int hf_uavcan_packet_crc = -1; + +static gint ett_uavcan = -1; +static gint ett_uavcan_can = -1; +static gint ett_uavcan_message = -1; + +static expert_field ei_uavcan_toggle_bit_error = EI_INIT; +static expert_field ei_uavcan_transfer_crc_error = EI_INIT; + +static gint ett_uavcan_fragment = -1; +static gint ett_uavcan_fragments = -1; +static int hf_uavcan_fragments = -1; +static int hf_uavcan_fragment = -1; +static int hf_uavcan_fragment_overlap = -1; +static int hf_uavcan_fragment_overlap_conflicts = -1; +static int hf_uavcan_fragment_multiple_tails = -1; +static int hf_uavcan_fragment_too_long_fragment = -1; +static int hf_uavcan_fragment_error = -1; +static int hf_uavcan_fragment_count = -1; +static int hf_uavcan_reassembled_in = -1; +static int hf_uavcan_reassembled_length = -1; + +/* fragment struct to store packet assembly data */ +typedef struct _fragment_info_t +{ + gint toggle; + gint fragment_id; + guint32 seq_id; +} fragment_info_t; + +guint32 uavcan_seq_id = 0; + +static const fragment_items uavcan_frag_items = { + /* Fragment subtrees */ + &ett_uavcan_fragment, + &ett_uavcan_fragments, + + /* Fragment fields */ + &hf_uavcan_fragments, + &hf_uavcan_fragment, + &hf_uavcan_fragment_overlap, + &hf_uavcan_fragment_overlap_conflicts, + &hf_uavcan_fragment_multiple_tails, + &hf_uavcan_fragment_too_long_fragment, + &hf_uavcan_fragment_error, + + &hf_uavcan_fragment_count, + + /* Reassembled in field */ + &hf_uavcan_reassembled_in, + + /* Reassembled length field */ + &hf_uavcan_reassembled_length, + + /* Reassembled data field */ + NULL, + + /* Tag */ + "Message fragments" +}; + +static dissector_handle_t dsdl_message_handle; +static dissector_handle_t dsdl_request_handle; +static dissector_handle_t dsdl_response_handle; + +static const value_string uavcan_priority_vals[] = { + { 0, "Exceptional" }, + { 1, "Immediate" }, + { 2, "Fast" }, + { 3, "High" }, + { 4, "Nominal" }, + { 5, "Low" }, + { 6, "Slow" }, + { 7, "Optional" }, + { 0, NULL } +}; + +static int +dissect_uavcan(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) +{ + proto_item *ti, *toggle, *transfer_crc; + proto_tree *uavcan_tree, *can_id_tree, *can_data_tree, *dsdl_tree; + + gint offset = 0; + struct can_info can_info; + guint16 *src_addr, *dest_addr; + guint8 tail_byte; + fragment_info_t *fragment_info = NULL; + guint reported_length; + guint32 lookup_id = 0; + + /* Semi-unique lookup id for reassembly lookup table note transfer-ID rolls-over every 32 times */ + + reported_length = tvb_reported_length(tvb); + + DISSECTOR_ASSERT(data); + can_info = *((struct can_info *) data); + + tail_byte = tvb_get_guint8(tvb, reported_length - 1); + + if ((can_info.id & CAN_ERR_FLAG) || + !(can_info.id & CAN_EFF_FLAG)) { + /* Error frames and frames with standards ids are not for us */ + return 0; + } + + if ((tail_byte & (START_OF_TRANSFER | TOGGLE)) == + (START_OF_TRANSFER)) { + /* UAVCAN v0 Frame */ + return 0; + } + + if ((tail_byte & (START_OF_TRANSFER | END_OF_TRANSFER)) != + (START_OF_TRANSFER | END_OF_TRANSFER)) { /* Multi-frame */ + if (UAVCAN_IS_MESSAGE(can_info.id)) { /* Message */ + lookup_id = 0; // Bit 0 false indicates message + lookup_id |= UAVCAN_SUBJECT_ID(can_info.id) << 1; + lookup_id |= UAVCAN_SOURCE_ID(can_info.id) << 11; + lookup_id |= (tail_byte & TRANSFER_ID) << 18; + } else { /* Service */ + lookup_id = 1; // Bit 0 true indicates service + lookup_id |= ((can_info.id & 0x01000000) >> 24) << 1; + lookup_id |= UAVCAN_SERVICE_ID(can_info.id) << 2; + lookup_id |= UAVCAN_DESTINATION_ID(can_info.id) << 11; + lookup_id |= UAVCAN_SOURCE_ID(can_info.id) << 18; + lookup_id |= (tail_byte & TRANSFER_ID) << 25; + } + + fragment_info = (fragment_info_t *) wmem_tree_lookup32(fragment_info_table, lookup_id); + + if (!(tail_byte & START_OF_TRANSFER) && fragment_info == NULL) { + /* Lookup id doesn't exist, but not a start of transfer discard potentially a UAVCANv0 frame */ + return 0; + } + } + + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "UAVCAN/CAN"); + col_clear(pinfo->cinfo, COL_INFO); + + ti = proto_tree_add_item(tree, proto_uavcan, tvb, offset, reported_length, ENC_NA); + uavcan_tree = proto_item_add_subtree(ti, ett_uavcan); + + can_id_tree = proto_tree_add_subtree_format(uavcan_tree, tvb, 0, 0, + ett_uavcan_can, &ti, "CAN ID field: 0x%08x", + can_info.id); + proto_item_set_generated(ti); + + ti = proto_tree_add_uint(can_id_tree, hf_uavcan_can_id, tvb, 0, 0, can_info.id); + proto_item_set_generated(ti); + + /* Dissect UAVCAN/CAN Message frame */ + if (UAVCAN_IS_MESSAGE(can_info.id)) { + ti = proto_tree_add_uint(can_id_tree, hf_uavcan_priority, tvb, 0, 0, can_info.id); + proto_item_set_generated(ti); + ti = proto_tree_add_uint(can_id_tree, hf_uavcan_serv_not_msg, tvb, 0, 0, can_info.id); + proto_item_set_generated(ti); + ti = proto_tree_add_uint(can_id_tree, hf_uavcan_anonymous, tvb, 0, 0, can_info.id); + proto_item_set_generated(ti); + ti = proto_tree_add_uint(can_id_tree, hf_uavcan_subject_id, tvb, 0, 0, can_info.id); + proto_item_set_generated(ti); + ti = proto_tree_add_uint(can_id_tree, hf_uavcan_src_addr, tvb, 0, 0, can_info.id); + proto_item_set_generated(ti); + + /* Set source address */ + src_addr = wmem_new(pinfo->pool, guint16); + *src_addr = (guint16) UAVCAN_SOURCE_ID(can_info.id); + + if (UAVCAN_IS_ANONYMOUS(can_info.id)) { + *src_addr |= ANONYMOUS_FLAG; + } + + set_address(&pinfo->src, uavcan_address_type, 2, (const void *) src_addr); + + /* Fill in "destination" address even if its "broadcast" */ + dest_addr = wmem_new(pinfo->pool, guint16); + *dest_addr = BROADCAST_FLAG; + set_address(&pinfo->dst, uavcan_address_type, 2, (const void *) dest_addr); + + col_add_fstr(pinfo->cinfo, COL_INFO, "Message: %d (%s)", UAVCAN_SUBJECT_ID(can_info.id), + rval_to_str_const(UAVCAN_SUBJECT_ID(can_info.id), uavcan_subject_id_vals, "Reserved")); + } else { /* UAVCAN/CAN Service frame */ + ti = proto_tree_add_uint(can_id_tree, hf_uavcan_priority, tvb, 0, 0, can_info.id); + proto_item_set_generated(ti); + ti = proto_tree_add_uint(can_id_tree, hf_uavcan_serv_not_msg, tvb, 0, 0, can_info.id); + proto_item_set_generated(ti); + ti = proto_tree_add_uint(can_id_tree, hf_uavcan_req_not_rsp, tvb, 0, 0, can_info.id); + proto_item_set_generated(ti); + ti = proto_tree_add_uint(can_id_tree, hf_uavcan_service_id, tvb, 0, 0, can_info.id); + proto_item_set_generated(ti); + ti = proto_tree_add_uint(can_id_tree, hf_uavcan_dst_addr, tvb, 0, 0, can_info.id); + proto_item_set_generated(ti); + ti = proto_tree_add_uint(can_id_tree, hf_uavcan_src_addr, tvb, 0, 0, can_info.id); + proto_item_set_generated(ti); + + /* Set source address */ + src_addr = wmem_new(pinfo->pool, guint16); + *src_addr = (guint16) UAVCAN_SOURCE_ID(can_info.id); + set_address(&pinfo->src, uavcan_address_type, 2, (const void *) src_addr); + + dest_addr = wmem_new(pinfo->pool, guint16); + *dest_addr = (guint16) UAVCAN_DESTINATION_ID(can_info.id); + set_address(&pinfo->dst, uavcan_address_type, 2, (const void *) dest_addr); + if (UAVCAN_IS_RESPONSE(can_info.id)) { + col_add_fstr(pinfo->cinfo, COL_INFO, "Service response: %d (%s)", UAVCAN_SERVICE_ID(can_info.id), + rval_to_str_const(UAVCAN_SERVICE_ID(can_info.id), uavcan_service_id_vals, "Reserved")); + } else { + col_add_fstr(pinfo->cinfo, COL_INFO, "Service request: %d (%s)", UAVCAN_SERVICE_ID(can_info.id), + rval_to_str_const(UAVCAN_SERVICE_ID(can_info.id), uavcan_service_id_vals, "Reserved")); + } + } + + can_data_tree = proto_tree_add_subtree(uavcan_tree, tvb, 0, -1, ett_uavcan_message, NULL, "CAN data field"); + + proto_tree_add_item(can_data_tree, hf_uavcan_start_of_transfer, tvb, + reported_length - 1, 1, ENC_NA); + proto_tree_add_item(can_data_tree, hf_uavcan_end_of_transfer, tvb, + reported_length - 1, 1, ENC_NA); + toggle = proto_tree_add_item(can_data_tree, hf_uavcan_toggle, tvb, + reported_length - 1, 1, ENC_NA); + proto_tree_add_item(can_data_tree, hf_uavcan_transfer_id, tvb, + reported_length - 1, 1, ENC_NA); + proto_tree_add_item(can_data_tree, hf_uavcan_data, tvb, 0, reported_length - 1, + ENC_NA); + + if ((tail_byte & (START_OF_TRANSFER | END_OF_TRANSFER)) == + (START_OF_TRANSFER | END_OF_TRANSFER)) { /* Single frame */ + dsdl_tree = proto_tree_add_subtree(uavcan_tree, tvb, 0, tvb_reported_length( + tvb) - 1, ett_uavcan_message, NULL, ""); + tvb_set_reported_length(tvb, reported_length - 1); /* Don't pass Tail byte to DSDL */ + + if (UAVCAN_IS_MESSAGE(can_info.id)) { + guint32 id; + id = UAVCAN_SUBJECT_ID(can_info.id); + proto_item_append_text(dsdl_tree, "Message"); + call_dissector_with_data(dsdl_message_handle, tvb, pinfo, dsdl_tree, + GUINT_TO_POINTER((guint) id)); + } else if (UAVCAN_IS_SERVICE(can_info.id)) { + guint32 id; + id = UAVCAN_SERVICE_ID(can_info.id); + + if (UAVCAN_IS_REQUEST(can_info.id)) { + proto_item_append_text(dsdl_tree, "Service request"); + call_dissector_with_data(dsdl_request_handle, tvb, pinfo, dsdl_tree, GUINT_TO_POINTER( + (guint) id)); + } else { + proto_item_append_text(dsdl_tree, "Service response"); + call_dissector_with_data(dsdl_response_handle, tvb, pinfo, dsdl_tree, GUINT_TO_POINTER( + (guint) id)); + } + } + } + + /* Re-assembly attempt */ + + if ((tail_byte & (START_OF_TRANSFER | END_OF_TRANSFER)) != + (START_OF_TRANSFER | END_OF_TRANSFER)) { /* Multi-frame */ + struct uavcan_proto_data *uavcan_frame_data; + + if (!PINFO_FD_VISITED(pinfo)) { /* Not visited */ + if (fragment_info == NULL) { /* Doesn't exist, allocate lookup_id */ + fragment_info = (fragment_info_t *) wmem_new(wmem_file_scope(), fragment_info_t); + fragment_info->fragment_id = 0; + fragment_info->toggle = tail_byte & TOGGLE; + + wmem_tree_insert32(fragment_info_table, lookup_id, fragment_info); + } + + /* Store sequence number and status in pinfo so we can revisit later */ + uavcan_frame_data = + wmem_new0(wmem_file_scope(), struct uavcan_proto_data); + p_add_proto_data(wmem_file_scope(), pinfo, proto_uavcan, 0, uavcan_frame_data); + + if ((tail_byte & START_OF_TRANSFER) != 0) { /* Start of transfer */ + uavcan_frame_data->toggle_error = 0; + fragment_info->fragment_id = 0; + fragment_info->seq_id = uavcan_seq_id; + uavcan_seq_id += 1; + } else { /* Update transfer */ + fragment_info->fragment_id += 1; + uavcan_frame_data->toggle_error = + ((tail_byte & TOGGLE) == fragment_info->toggle) ? TRUE : FALSE; + } + + uavcan_frame_data->seq_id = fragment_info->seq_id; + + fragment_info->toggle = tail_byte & TOGGLE; + + pinfo->fragmented = TRUE; + fragment_add_seq_check(&uavcan_reassembly_table, + tvb, offset, pinfo, fragment_info->seq_id, NULL, /* ID for fragments belonging together */ + fragment_info->fragment_id, /* fragment sequence number */ + tvb_captured_length_remaining(tvb, offset) - 1, /* fragment length - minus tail byte */ + ((tail_byte & END_OF_TRANSFER) == 0) ? TRUE : FALSE); /* More fragments? */ + } else { /* Visited reassembled data */ + fragment_head *reassembled = NULL; + tvbuff_t *reassembled_tvb; + proto_tree *multi_tree; + + uavcan_frame_data = (struct uavcan_proto_data *) p_get_proto_data( + wmem_file_scope(), pinfo, proto_uavcan, 0); + + reassembled = fragment_get_reassembled_id(&uavcan_reassembly_table, pinfo, + uavcan_frame_data->seq_id); + + if (reassembled) { + if (uavcan_frame_data->toggle_error == 1) { + expert_add_info_format(pinfo, toggle, &ei_uavcan_toggle_bit_error, + "Expected Toggle %u got %u.", + !((tail_byte & TOGGLE) != 0), + ((tail_byte & TOGGLE) != 0)); + } + + col_append_str(pinfo->cinfo, COL_INFO, + " (Multi-frame)"); + + reassembled_tvb = tvb_new_chain(tvb, reassembled->tvb_data); /* Reassembled tvb chain */ + + multi_tree = proto_tree_add_subtree(uavcan_tree, reassembled_tvb, 0, + -1, ett_uavcan_message, NULL, + "Multi-frame"); + + process_reassembled_data(tvb, offset, pinfo, + "Reassembled Message", reassembled, &uavcan_frag_items, + NULL, multi_tree); + + /* Parsing reassembled data */ + if ((tail_byte & END_OF_TRANSFER) != 0) { + transfer_crc = proto_tree_add_item(multi_tree, hf_uavcan_packet_crc, + reassembled_tvb, + tvb_reported_length(reassembled_tvb) - 2, + 2, ENC_BIG_ENDIAN); + + guint16 packet_crc = tvb_get_guint16(reassembled_tvb, + tvb_reported_length(reassembled_tvb) - 2, + ENC_BIG_ENDIAN); + guint16 calc_crc = crc16_x25_ccitt_tvb(reassembled_tvb, + tvb_reported_length(reassembled_tvb) - 2); + + if (packet_crc != calc_crc) { + expert_add_info_format(pinfo, transfer_crc, &ei_uavcan_transfer_crc_error, + "Expected CRC16 %X got %X.", + calc_crc, packet_crc); + } + + tvb_set_reported_length(reassembled_tvb, tvb_reported_length(reassembled_tvb) - 2); /* Don't pass CRC16 to DSDL */ + + dsdl_tree = proto_tree_add_subtree(uavcan_tree, reassembled_tvb, 0, + -1, ett_uavcan_message, NULL, ""); + + /* Pass payload to DSDL dissector */ + if (UAVCAN_IS_MESSAGE(can_info.id)) { + guint32 id = UAVCAN_SUBJECT_ID(can_info.id); + proto_item_append_text(dsdl_tree, "Message"); + + call_dissector_with_data(dsdl_message_handle, reassembled_tvb, pinfo, + dsdl_tree, + GUINT_TO_POINTER((guint) id)); + } else if (UAVCAN_IS_SERVICE(can_info.id)) { + guint32 id = UAVCAN_SERVICE_ID(can_info.id); + + if (UAVCAN_IS_REQUEST(can_info.id)) { + proto_item_append_text(dsdl_tree, "Service request"); + call_dissector_with_data(dsdl_request_handle, reassembled_tvb, pinfo, + dsdl_tree, GUINT_TO_POINTER((guint) id)); + } else { + proto_item_append_text(dsdl_tree, "Service response"); + call_dissector_with_data(dsdl_response_handle, reassembled_tvb, pinfo, + dsdl_tree, GUINT_TO_POINTER((guint) id)); + } + } + } + } + } + } + + return tvb_captured_length(tvb); +} + +static int +UAVCAN_addr_to_str(const address *addr, gchar *buf, int buf_len) +{ + const guint16 *addrdata = (const guint16 *) addr->data; + + if ((*addrdata & ANONYMOUS_FLAG) != 0) { + return (int) snprintf(buf, buf_len, "Anonymous"); + } else if ((*addrdata & BROADCAST_FLAG) != 0) { + return (int) snprintf(buf, buf_len, "Broadcast"); + } else { + guint8 real_addr = (guint8) (*addrdata & ADDR_MASK); + guint32_to_str_buf(real_addr, buf, buf_len); + return (int) strlen(buf); + } +} + +static int +UAVCAN_addr_str_len(const address *addr _U_) +{ + return 12; /* Leaves required space (10 bytes) for uint_to_str_back() */ +} + +static const char * +UAVCAN_col_filter_str(const address *addr _U_, gboolean is_src) +{ + if (is_src) + return "uavcan_can.src_addr"; + + return "uavcan_can.dst_addr"; +} + +static int +UAVCAN_addr_len(void) +{ + return 2; +} + +void +proto_register_uavcan(void) +{ + static hf_register_info hf[] = { + {&hf_uavcan_can_id, + {"CAN Identifier", "uavcan_can.can_id", + FT_UINT32, BASE_HEX, NULL, CAN_EFF_MASK, NULL, HFILL}}, + {&hf_uavcan_priority, + {"Priority", "uavcan_can.priority", + FT_UINT32, BASE_DEC, VALS(uavcan_priority_vals), 0x1C000000, NULL, HFILL}}, + {&hf_uavcan_serv_not_msg, + {"Service, not message", "uavcan_can.serv_not_msg", + FT_UINT32, BASE_DEC, NULL, 0x02000000, NULL, HFILL}}, + {&hf_uavcan_anonymous, + {"Anonymous", "uavcan_can.anonymous", + FT_UINT32, BASE_DEC, NULL, 0x01000000, NULL, HFILL}}, + {&hf_uavcan_req_not_rsp, + {"Request, not response", "uavcan_can.req_not_rsp", + FT_UINT32, BASE_DEC, NULL, 0x01000000, NULL, HFILL}}, + {&hf_uavcan_subject_id, + {"Subject ID", "uavcan_can.subject_id", + FT_UINT32, BASE_DEC|BASE_RANGE_STRING, RVALS(uavcan_subject_id_vals), 0x001FFF00, NULL, HFILL}}, + {&hf_uavcan_service_id, + {"Service ID", "uavcan_can.service_id", + FT_UINT32, BASE_DEC|BASE_RANGE_STRING, RVALS(uavcan_service_id_vals), 0x007FC000, NULL, HFILL}}, + {&hf_uavcan_dst_addr, + {"Destination node-ID", "uavcan_can.dst_addr", + FT_UINT32, BASE_DEC, NULL, 0x00003F80, NULL, HFILL}}, + {&hf_uavcan_src_addr, + {"Source node-ID", "uavcan_can.src_addr", + FT_UINT32, BASE_DEC, NULL, 0x0000007F, NULL, HFILL}}, + {&hf_uavcan_data, + {"Payload", "uavcan_can.payload", + FT_BYTES, BASE_NONE | BASE_ALLOW_ZERO, NULL, 0x0, NULL, HFILL}}, + {&hf_uavcan_start_of_transfer, + {"Start of transfer", "uavcan_can.start_of_transfer", + FT_UINT8, BASE_DEC, NULL, START_OF_TRANSFER, NULL, HFILL}}, + {&hf_uavcan_end_of_transfer, + {"End of transfer", "uavcan_can.end_of_transfer", + FT_UINT8, BASE_DEC, NULL, END_OF_TRANSFER, NULL, HFILL}}, + {&hf_uavcan_toggle, + {"Toggle", "uavcan_can.toggle", + FT_UINT8, BASE_DEC, NULL, TOGGLE, NULL, HFILL}}, + {&hf_uavcan_transfer_id, + {"Transfer-ID", "uavcan_can.transfer_id", + FT_UINT8, BASE_DEC, NULL, TRANSFER_ID, NULL, HFILL}}, + {&hf_uavcan_fragments, + {"Message fragments", "uavcan_can.multiframe.fragments", + FT_NONE, BASE_NONE, NULL, 0x00, + NULL, HFILL}}, + {&hf_uavcan_fragment, + {"Message fragment", "uavcan_can.multiframe.fragment", + FT_FRAMENUM, BASE_NONE, NULL, 0x00, + NULL, HFILL}}, + {&hf_uavcan_fragment_overlap, + {"Message fragment overlap", + "uavcan_can.multiframe.fragment.overlap", + FT_BOOLEAN, BASE_NONE, NULL, 0x00, + NULL, HFILL}}, + {&hf_uavcan_fragment_overlap_conflicts, + {"Message fragment overlapping with conflicting data", + "uavcan_can.multiframe.fragment.overlap.conflicts", + FT_BOOLEAN, BASE_NONE, NULL, 0x00, + NULL, HFILL}}, + {&hf_uavcan_fragment_multiple_tails, + {"Message has multiple tail fragments", + "uavcan_can.multiframe.fragment.multiple_tails", + FT_BOOLEAN, BASE_NONE, NULL, 0x00, + NULL, HFILL}}, + {&hf_uavcan_fragment_too_long_fragment, + {"Message fragment too long", + "uavcan_can.multiframe.fragment.too_long_fragment", + FT_BOOLEAN, BASE_NONE, NULL, 0x00, + NULL, HFILL}}, + {&hf_uavcan_fragment_error, + {"Message defragmentation error", + "uavcan_can.multiframe.fragment.error", + FT_FRAMENUM, BASE_NONE, NULL, 0x00, + NULL, HFILL}}, + {&hf_uavcan_fragment_count, + {"Message fragment count", "uavcan_can.fragment.count", + FT_UINT32, BASE_DEC, NULL, 0x00, + NULL, HFILL}}, + {&hf_uavcan_reassembled_in, + {"Reassembled in", + "uavcan_can.multiframe.reassembled.in", + FT_FRAMENUM, BASE_NONE, NULL, 0x00, + NULL, HFILL}}, + {&hf_uavcan_reassembled_length, + {"Reassembled payload length", + "uavcan_can.multiframe.reassembled.length", + FT_UINT32, BASE_DEC, NULL, 0x00, + NULL, HFILL}}, + {&hf_uavcan_packet_crc, + {"Transfer CRC", "uavcan_can.multiframe.crc", + FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}} + }; + + static gint *ett[] = { + &ett_uavcan, + &ett_uavcan_can, + &ett_uavcan_message, + &ett_uavcan_fragment, + &ett_uavcan_fragments + }; + + reassembly_table_register(&uavcan_reassembly_table, + &addresses_reassembly_table_functions); + fragment_info_table = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope()); + + + expert_module_t *expert_uavcan; + + proto_uavcan = proto_register_protocol("UAVCAN/CAN", "UAVCAN/CAN", "uavcan_can"); + + + static ei_register_info ei[] = { + {&ei_uavcan_toggle_bit_error, + {"uavcan_can.toggle_bit.error", PI_MALFORMED, PI_ERROR, + "Toggle bit error", + EXPFILL}}, + {&ei_uavcan_transfer_crc_error, + {"uavcan_can.transfer_crc.error", PI_MALFORMED, PI_ERROR, + "Transfer CRC don't match", + EXPFILL}} + }; + + + proto_register_field_array(proto_uavcan, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + uavcan_handle = register_dissector("uavcan_can", dissect_uavcan, proto_uavcan); + + expert_uavcan = expert_register_protocol(proto_uavcan); + expert_register_field_array(expert_uavcan, ei, array_length(ei)); + + uavcan_address_type = address_type_dissector_register("AT_UAVCAN", "UAVCAN Address", + UAVCAN_addr_to_str, UAVCAN_addr_str_len, + NULL, UAVCAN_col_filter_str, + UAVCAN_addr_len, NULL, NULL); +} + +void +proto_reg_handoff_uavcan(void) +{ + dsdl_message_handle = find_dissector_add_dependency("uavcan_dsdl.message", proto_uavcan); + dsdl_request_handle = find_dissector_add_dependency("uavcan_dsdl.request", proto_uavcan); + dsdl_response_handle = find_dissector_add_dependency("uavcan_dsdl.response", proto_uavcan); + + dissector_add_for_decode_as("can.subdissector", uavcan_handle); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ |