forked from osmocom/wireshark
UAVCAN/CAN dissector see https://uavcan.org/
This commit is contained in:
parent
f15d35b0c8
commit
4959ae652e
|
@ -89,6 +89,7 @@ Kerberos SPAKE
|
||||||
O-RAN fronthaul UC-plane (O-RAN)
|
O-RAN fronthaul UC-plane (O-RAN)
|
||||||
PDU Transport Protocol
|
PDU Transport Protocol
|
||||||
State Synchronization Protocol (SSyncP)
|
State Synchronization Protocol (SSyncP)
|
||||||
|
UAVCAN\CAN
|
||||||
--
|
--
|
||||||
|
|
||||||
=== Updated Protocol Support
|
=== Updated Protocol Support
|
||||||
|
|
|
@ -584,6 +584,7 @@ set(DISSECTOR_PUBLIC_HEADERS
|
||||||
packet-tte.h
|
packet-tte.h
|
||||||
packet-ua.h
|
packet-ua.h
|
||||||
packet-uaudp.h
|
packet-uaudp.h
|
||||||
|
packet-uavcan-dsdl.h
|
||||||
packet-ubertooth.h
|
packet-ubertooth.h
|
||||||
packet-udp.h
|
packet-udp.h
|
||||||
packet-umts_fp.h
|
packet-umts_fp.h
|
||||||
|
@ -1852,6 +1853,8 @@ set(DISSECTOR_SRC
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-ua3g.c
|
${CMAKE_CURRENT_SOURCE_DIR}/packet-ua3g.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-uasip.c
|
${CMAKE_CURRENT_SOURCE_DIR}/packet-uasip.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-uaudp.c
|
${CMAKE_CURRENT_SOURCE_DIR}/packet-uaudp.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/packet-uavcan-can.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/packet-uavcan-dsdl.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-ubdp.c
|
${CMAKE_CURRENT_SOURCE_DIR}/packet-ubdp.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-ubertooth.c
|
${CMAKE_CURRENT_SOURCE_DIR}/packet-ubertooth.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-ucp.c
|
${CMAKE_CURRENT_SOURCE_DIR}/packet-ucp.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 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;
|
||||||
|
|
||||||
|
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) g_snprintf(buf, buf_len, "Anonymous");
|
||||||
|
} else if ((*addrdata & BROADCAST_FLAG) != 0) {
|
||||||
|
return (int) g_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));
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
dissector_handle_t uavcan_handle;
|
||||||
|
|
||||||
|
uavcan_handle = create_dissector_handle(dissect_uavcan, proto_uavcan);
|
||||||
|
|
||||||
|
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:
|
||||||
|
*/
|
|
@ -0,0 +1,689 @@
|
||||||
|
/* packet-uavcan-dsdl.c
|
||||||
|
* Routines for dissection of DSDL used in UAVCAN
|
||||||
|
*
|
||||||
|
* 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/proto_data.h>
|
||||||
|
|
||||||
|
#include "packet-uavcan-dsdl.h"
|
||||||
|
|
||||||
|
void proto_register_dsdl(void);
|
||||||
|
void proto_reg_handoff_dsdl(void);
|
||||||
|
|
||||||
|
static int proto_dsdl = -1;
|
||||||
|
|
||||||
|
static int hf_heartbeat_uptime = -1;
|
||||||
|
static int hf_heartbeat_health = -1;
|
||||||
|
static int hf_heartbeat_mode = -1;
|
||||||
|
static int hf_heartbeat_status_code = -1;
|
||||||
|
|
||||||
|
static int hf_list_index = -1;
|
||||||
|
static int hf_register_name = -1;
|
||||||
|
static int hf_register_access_mutable = -1;
|
||||||
|
static int hf_register_access_persistent = -1;
|
||||||
|
static int hf_register_value_tag = -1;
|
||||||
|
static int hf_register_value_size = -1;
|
||||||
|
|
||||||
|
|
||||||
|
static int hf_node_id = -1;
|
||||||
|
static int hf_pnp_unique_id = -1;
|
||||||
|
static int hf_pnp_unique_id_hash = -1;
|
||||||
|
static int hf_pnp_alloc = -1;
|
||||||
|
|
||||||
|
static int hf_uavcan_primitive_Empty = -1;
|
||||||
|
static int hf_uavcan_primitive_String = -1;
|
||||||
|
static int hf_uavcan_primitive_Unstructured = -1;
|
||||||
|
static int hf_uavcan_primitive_array_Integer64 = -1;
|
||||||
|
static int hf_uavcan_primitive_array_Integer32 = -1;
|
||||||
|
static int hf_uavcan_primitive_array_Integer16 = -1;
|
||||||
|
static int hf_uavcan_primitive_array_Integer8 = -1;
|
||||||
|
static int hf_uavcan_primitive_array_Natural64 = -1;
|
||||||
|
static int hf_uavcan_primitive_array_Natural32 = -1;
|
||||||
|
static int hf_uavcan_primitive_array_Natural16 = -1;
|
||||||
|
static int hf_uavcan_primitive_array_Natural8 = -1;
|
||||||
|
static int hf_uavcan_primitive_array_Real64 = -1;
|
||||||
|
static int hf_uavcan_primitive_array_Real32 = -1;
|
||||||
|
static int hf_uavcan_primitive_array_Real16 = -1;
|
||||||
|
|
||||||
|
|
||||||
|
static int hf_uavcan_getinfo_path = -1;
|
||||||
|
static int hf_uavcan_getinfo_error = -1;
|
||||||
|
static int hf_uavcan_getinfo_size = -1;
|
||||||
|
static int hf_uavcan_getinfo_timestamp = -1;
|
||||||
|
static int hf_uavcan_getinfo_is_file_not_directory = -1;
|
||||||
|
static int hf_uavcan_getinfo_is_link = -1;
|
||||||
|
static int hf_uavcan_getinfo_is_readable = -1;
|
||||||
|
static int hf_uavcan_getinfo_is_writeable = -1;
|
||||||
|
static int hf_uavcan_directory_path = -1;
|
||||||
|
static int hf_uavcan_entry_base_name = -1;
|
||||||
|
static int hf_uavcan_modify_error = -1;
|
||||||
|
static int hf_uavcan_modify_source_path = -1;
|
||||||
|
static int hf_uavcan_modify_destination_path = -1;
|
||||||
|
static int hf_uavcan_modify_preserve_source = -1;
|
||||||
|
static int hf_uavcan_modify_overwrite_destination = -1;
|
||||||
|
static int hf_uavcan_read_offset = -1;
|
||||||
|
static int hf_uavcan_read_path = -1;
|
||||||
|
static int hf_uavcan_read_error = -1;
|
||||||
|
static int hf_uavcan_write_offset = -1;
|
||||||
|
static int hf_uavcan_write_path = -1;
|
||||||
|
static int hf_uavcan_write_error = -1;
|
||||||
|
static int hf_uavcan_entry_index = -1;
|
||||||
|
|
||||||
|
static int hf_uavcan_time_syncronizedtimestamp = -1;
|
||||||
|
static int hf_uavcan_diagnostic_severity = -1;
|
||||||
|
|
||||||
|
static gint ett_dsdl = -1;
|
||||||
|
|
||||||
|
const range_string uavcan_subject_id_vals[] = {
|
||||||
|
{ 0, 6143, "Unregulated identifier" },
|
||||||
|
{ 6144, 7167, "Non-standard fixed regulated identifier"},
|
||||||
|
{ 7168, 7168, "Synchronization.1.0" },
|
||||||
|
{ 7509, 7509, "Heartbeat.1.0" },
|
||||||
|
{ 7510, 7510, "List.0.1" },
|
||||||
|
{ 8165, 8165, "NodeIDAllocationData.2.0" },
|
||||||
|
{ 8166, 8166, "NodeIDAllocationData.1.0" },
|
||||||
|
{ 8184, 8184, "Record.1.X" },
|
||||||
|
{ 0, 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
const range_string uavcan_service_id_vals[] = {
|
||||||
|
{ 0, 255, "Unregulated identifier" },
|
||||||
|
{ 256, 383, "Non-standard fixed regulated identifier"},
|
||||||
|
{ 384, 384, "Access.1.0" },
|
||||||
|
{ 385, 385, "List.1.0" },
|
||||||
|
{ 405, 405, "GetInfo.0.X" },
|
||||||
|
{ 406, 406, "List.0.X" },
|
||||||
|
{ 407, 407, "Modify.1.X" },
|
||||||
|
{ 408, 408, "Read.1.X" },
|
||||||
|
{ 409, 409, "Write.1.X" },
|
||||||
|
{ 430, 430, "GetInfo.1.0" },
|
||||||
|
{ 434, 434, "GetTransportStatistics.1.0" },
|
||||||
|
{ 435, 435, "ExecuteCommand.1.X" },
|
||||||
|
{ 0, 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const address anonymous_address = {
|
||||||
|
AT_NONE,
|
||||||
|
9,
|
||||||
|
"Anonymous",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
const value_string uavcan_file_error_vals[] = {
|
||||||
|
{ 0, "Ok" },
|
||||||
|
{ 2, "Not found" },
|
||||||
|
{ 5, "I/O error" },
|
||||||
|
{ 13, "Access denied" },
|
||||||
|
{ 21, "Is directory" },
|
||||||
|
{ 22, "Invalid value" },
|
||||||
|
{ 27, "File too large" },
|
||||||
|
{ 28, "Out of space" },
|
||||||
|
{ 38, "Not supported" },
|
||||||
|
{ 65535, "Unknown" },
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
const value_string uavcan_diagnostic_severity_vals[] = {
|
||||||
|
{ 0, "Trace" },
|
||||||
|
{ 1, "Debug" },
|
||||||
|
{ 2, "Info" },
|
||||||
|
{ 3, "Notice" },
|
||||||
|
{ 4, "Warning" },
|
||||||
|
{ 5, "Error" },
|
||||||
|
{ 6, "Critical" },
|
||||||
|
{ 7, "Alert" },
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
const value_string uavcan_heartbeat_mode_vals[] = {
|
||||||
|
{ 0, "Operational" },
|
||||||
|
{ 1, "Initialization" },
|
||||||
|
{ 2, "Maintenance" },
|
||||||
|
{ 3, "Software update" },
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
const value_string uavcan_heartbeat_health_vals[] = {
|
||||||
|
{ 0, "Nominal" },
|
||||||
|
{ 1, "Advisory" },
|
||||||
|
{ 2, "Caution" },
|
||||||
|
{ 3, "Warning" },
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
const value_string uavcan_value_tag_vals[] = {
|
||||||
|
{ 0, "Empty" },
|
||||||
|
{ 1, "String" },
|
||||||
|
{ 2, "Unstructured" },
|
||||||
|
{ 3, "Bit array" },
|
||||||
|
{ 4, "Integer 64 Array" },
|
||||||
|
{ 5, "Integer 32 Array" },
|
||||||
|
{ 6, "Integer 16 Array" },
|
||||||
|
{ 7, "Integer 8 Array" },
|
||||||
|
{ 8, "Natural 64 Array" },
|
||||||
|
{ 9, "Natural 32 Array" },
|
||||||
|
{ 10, "Natural 16 Array" },
|
||||||
|
{ 11, "Natural 8 Array" },
|
||||||
|
{ 12, "Real 64 Array" },
|
||||||
|
{ 13, "Real 32 Array" },
|
||||||
|
{ 14, "Real 16 Array" },
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
const value_string uavcan_nodeid_alloc_vals[] = {
|
||||||
|
{ 0, "request message" },
|
||||||
|
{ 1, "response message" },
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
dissect_list_service_data(tvbuff_t *tvb, int tvb_offset, proto_tree *tree, gboolean is_request)
|
||||||
|
{
|
||||||
|
if (is_request == TRUE) {
|
||||||
|
proto_tree_add_item(tree, hf_list_index, tvb, tvb_offset, 2, ENC_LITTLE_ENDIAN);
|
||||||
|
} else {
|
||||||
|
/* FT_UINT_STRING counted string, with count being the first byte */
|
||||||
|
proto_tree_add_item(tree, hf_register_name,
|
||||||
|
tvb, tvb_offset, 1, ENC_ASCII|ENC_BIG_ENDIAN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dissect_access_service_data(tvbuff_t *tvb, int tvb_offset, proto_tree *tree, gboolean is_request)
|
||||||
|
{
|
||||||
|
guint32 tag;
|
||||||
|
gint offset;
|
||||||
|
|
||||||
|
offset = tvb_offset;
|
||||||
|
|
||||||
|
if (is_request == TRUE) {
|
||||||
|
gint len;
|
||||||
|
/* FT_UINT_STRING counted string, with count being the first byte */
|
||||||
|
proto_tree_add_item_ret_length(tree, hf_register_name,
|
||||||
|
tvb, offset, 1, ENC_ASCII|ENC_BIG_ENDIAN, &len);
|
||||||
|
offset += len;
|
||||||
|
} else {
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_time_syncronizedtimestamp,
|
||||||
|
tvb, offset, 7, ENC_LITTLE_ENDIAN);
|
||||||
|
offset += 7;
|
||||||
|
proto_tree_add_item(tree, hf_register_access_mutable,
|
||||||
|
tvb, offset, 1, ENC_NA);
|
||||||
|
proto_tree_add_item(tree, hf_register_access_persistent,
|
||||||
|
tvb, offset, 1, ENC_NA);
|
||||||
|
|
||||||
|
offset += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
proto_tree_add_item_ret_uint(tree, hf_register_value_tag,
|
||||||
|
tvb, offset, 1, ENC_NA, &tag);
|
||||||
|
offset += 1;
|
||||||
|
|
||||||
|
if (tag == 1) { /* String */
|
||||||
|
proto_tree_add_item(tree, hf_register_value_size,
|
||||||
|
tvb, offset, 1, ENC_NA);
|
||||||
|
/* FT_UINT_STRING counted string, with count being the first byte */
|
||||||
|
proto_tree_add_item(tree, hf_register_name,
|
||||||
|
tvb, offset, 1, ENC_ASCII|ENC_BIG_ENDIAN);
|
||||||
|
} else if (tag == 2 || tag == 3) {
|
||||||
|
return; // Raw data do nothing
|
||||||
|
} else {
|
||||||
|
guint8 array_len = tvb_get_guint8(tvb, offset);
|
||||||
|
|
||||||
|
if (array_len == 0 || tag == 0) {
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_primitive_Empty,
|
||||||
|
tvb, 0, 0, ENC_NA);
|
||||||
|
} else {
|
||||||
|
proto_tree_add_item(tree, hf_register_value_size,
|
||||||
|
tvb, offset, 1, ENC_NA);
|
||||||
|
offset += 1;
|
||||||
|
|
||||||
|
for (guint8 i = 0; i < array_len; i++) {
|
||||||
|
switch (tag) {
|
||||||
|
case 4: /*Integer64*/
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_primitive_array_Integer64,
|
||||||
|
tvb, offset, 8, ENC_LITTLE_ENDIAN);
|
||||||
|
offset += 8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5: /*Integer32*/
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_primitive_array_Integer32,
|
||||||
|
tvb, offset, 4, ENC_LITTLE_ENDIAN);
|
||||||
|
offset += 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6: /*Integer16*/
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_primitive_array_Integer16,
|
||||||
|
tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
||||||
|
offset += 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 7: /*Integer8*/
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_primitive_array_Integer8,
|
||||||
|
tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
||||||
|
offset += 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 8: /*Natural64*/
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_primitive_array_Natural64,
|
||||||
|
tvb, offset, 8, ENC_LITTLE_ENDIAN);
|
||||||
|
offset += 8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 9: /*Natural32*/
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_primitive_array_Natural32,
|
||||||
|
tvb, offset, 4, ENC_LITTLE_ENDIAN);
|
||||||
|
offset += 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 10: /*Natural16*/
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_primitive_array_Natural16,
|
||||||
|
tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
||||||
|
offset += 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 11: /*Natural8*/
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_primitive_array_Natural8,
|
||||||
|
tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
||||||
|
offset += 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 12: /*Real64*/
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_primitive_array_Real64,
|
||||||
|
tvb, offset, 8, ENC_LITTLE_ENDIAN);
|
||||||
|
offset += 8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 13: /*Real32*/
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_primitive_array_Real32,
|
||||||
|
tvb, offset, 4, ENC_LITTLE_ENDIAN);
|
||||||
|
offset += 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 14: /*Real16*/
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_primitive_array_Real16,
|
||||||
|
tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
||||||
|
offset += 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_primitive_Empty,
|
||||||
|
tvb, 0, 0, ENC_NA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dissect_dsdl_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
||||||
|
{
|
||||||
|
guint32 id = GPOINTER_TO_INT(data);
|
||||||
|
|
||||||
|
proto_item_append_text(tree, " DSDL (%s)",
|
||||||
|
rval_to_str_const(id, uavcan_subject_id_vals, "Reserved"));
|
||||||
|
|
||||||
|
if (id == 7509) {
|
||||||
|
/* Dissect Heartbeat1.0 frame */
|
||||||
|
proto_tree_add_item(tree, hf_heartbeat_uptime, tvb, 0, 4, ENC_LITTLE_ENDIAN);
|
||||||
|
proto_tree_add_item(tree, hf_heartbeat_health, tvb, 4, 1, ENC_NA);
|
||||||
|
proto_tree_add_item(tree, hf_heartbeat_mode, tvb, 5, 1, ENC_NA);
|
||||||
|
proto_tree_add_item(tree, hf_heartbeat_status_code, tvb, 6, 1, ENC_NA);
|
||||||
|
return tvb_captured_length(tvb);
|
||||||
|
} else if (id == 8166) {
|
||||||
|
/* Dissect NodeIDAllocationData1.0 allocation request */
|
||||||
|
proto_tree_add_item(tree, hf_pnp_unique_id_hash, tvb, 0, 6, ENC_NA);
|
||||||
|
proto_tree_add_item(tree, hf_pnp_alloc, tvb, 6, 1, ENC_NA);
|
||||||
|
if (tvb_captured_length(tvb) > 8) {
|
||||||
|
proto_tree_add_item(tree, hf_node_id, tvb, 7, 2, ENC_LITTLE_ENDIAN);
|
||||||
|
}
|
||||||
|
return tvb_captured_length(tvb);
|
||||||
|
} else if (id == 8165) {
|
||||||
|
/* Dissect NodeIDAllocationData2.0 allocation request/response */
|
||||||
|
proto_tree_add_item(tree, hf_node_id, tvb, 0, 2, ENC_LITTLE_ENDIAN);
|
||||||
|
proto_tree_add_item(tree, hf_pnp_unique_id, tvb, 2, 16, ENC_NA);
|
||||||
|
proto_tree_add_uint(tree, hf_pnp_alloc, tvb, 0, 0,
|
||||||
|
(cmp_address(&anonymous_address, (const address *) &pinfo->src) != 0));
|
||||||
|
return tvb_captured_length(tvb);
|
||||||
|
} else if (id == 8184) {
|
||||||
|
/* Dissect Synchronization.1.0 frame */
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_time_syncronizedtimestamp, tvb, 0, 7,
|
||||||
|
ENC_LITTLE_ENDIAN);
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_diagnostic_severity, tvb, 7, 1, ENC_NA);
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_primitive_String, tvb, 8, 1,
|
||||||
|
ENC_ASCII|ENC_BIG_ENDIAN);
|
||||||
|
return tvb_captured_length(tvb);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dissect_dsdl_service_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
||||||
|
{
|
||||||
|
guint32 id = GPOINTER_TO_INT(data);
|
||||||
|
|
||||||
|
(void) pinfo;
|
||||||
|
|
||||||
|
proto_item_append_text(tree, " DSDL (%s)",
|
||||||
|
rval_to_str_const(id, uavcan_service_id_vals, "Reserved"));
|
||||||
|
|
||||||
|
if (id == 384) { /* Dissect Access.1.0 frame */
|
||||||
|
dissect_access_service_data(tvb, 0, tree, TRUE);
|
||||||
|
return tvb_captured_length(tvb);
|
||||||
|
} else if (id == 385) { /* Dissect List.1.0 frame */
|
||||||
|
dissect_list_service_data(tvb, 0, tree, TRUE);
|
||||||
|
return tvb_captured_length(tvb);
|
||||||
|
} else if (id == 405) { /* Dissect GetInfo.0.X frame */
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_getinfo_path,
|
||||||
|
tvb, 0, 1, ENC_ASCII|ENC_BIG_ENDIAN);
|
||||||
|
return tvb_captured_length(tvb);
|
||||||
|
} else if (id == 406) { /* Dissect List.0.X frame */
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_entry_index,
|
||||||
|
tvb, 0, 4, ENC_LITTLE_ENDIAN);
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_directory_path,
|
||||||
|
tvb, 8, 1, ENC_ASCII|ENC_BIG_ENDIAN);
|
||||||
|
return tvb_captured_length(tvb);
|
||||||
|
} else if (id == 407) { /* Dissect Modify.1.X frame */
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_modify_preserve_source,
|
||||||
|
tvb, 0, 1, ENC_NA);
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_modify_overwrite_destination,
|
||||||
|
tvb, 0, 1, ENC_NA);
|
||||||
|
gint len;
|
||||||
|
proto_tree_add_item_ret_length(tree, hf_uavcan_modify_source_path,
|
||||||
|
tvb, 4, 1, ENC_ASCII|ENC_BIG_ENDIAN, &len);
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_modify_destination_path,
|
||||||
|
tvb, 4 + len, 1, ENC_ASCII|ENC_BIG_ENDIAN);
|
||||||
|
return tvb_captured_length(tvb);
|
||||||
|
} else if (id == 408) { /* Dissect Read.1.X frame */
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_read_offset,
|
||||||
|
tvb, 0, 5, ENC_LITTLE_ENDIAN);
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_read_path,
|
||||||
|
tvb, 5, 1, ENC_ASCII|ENC_BIG_ENDIAN);
|
||||||
|
return tvb_captured_length(tvb);
|
||||||
|
} else if (id == 409) { /* Dissect Write.1.X frame */
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_write_offset,
|
||||||
|
tvb, 0, 5, ENC_LITTLE_ENDIAN);
|
||||||
|
gint len;
|
||||||
|
proto_tree_add_item_ret_length(tree, hf_uavcan_write_path,
|
||||||
|
tvb, 5, 1, ENC_ASCII|ENC_BIG_ENDIAN, &len);
|
||||||
|
guint16 data_len = tvb_get_guint16(tvb, 5 + len, ENC_LITTLE_ENDIAN);
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_primitive_Unstructured,
|
||||||
|
tvb, 7 + len, data_len, ENC_NA);
|
||||||
|
return tvb_captured_length(tvb);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dissect_dsdl_service_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
||||||
|
{
|
||||||
|
guint32 id = GPOINTER_TO_INT(data);
|
||||||
|
|
||||||
|
(void) pinfo;
|
||||||
|
|
||||||
|
proto_item_append_text(tree, " DSDL (%s)",
|
||||||
|
rval_to_str_const(id, uavcan_service_id_vals, "Reserved"));
|
||||||
|
|
||||||
|
if (id == 384) { /* Dissect Access.1.0 frame */
|
||||||
|
dissect_access_service_data(tvb, 0, tree, FALSE);
|
||||||
|
return tvb_captured_length(tvb);
|
||||||
|
} else if (id == 385) { /* Dissect List.1.0 frame */
|
||||||
|
dissect_list_service_data(tvb, 0, tree, FALSE);
|
||||||
|
return tvb_captured_length(tvb);
|
||||||
|
} else if (id == 405) { /* Dissect GetInfo.0.X frame */
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_getinfo_error,
|
||||||
|
tvb, 0, 2, ENC_LITTLE_ENDIAN);
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_getinfo_size,
|
||||||
|
tvb, 2, 5, ENC_LITTLE_ENDIAN);
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_getinfo_timestamp,
|
||||||
|
tvb, 7, 5, ENC_LITTLE_ENDIAN);
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_getinfo_is_file_not_directory,
|
||||||
|
tvb, 13, 1, ENC_LITTLE_ENDIAN);
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_getinfo_is_link,
|
||||||
|
tvb, 13, 1, ENC_LITTLE_ENDIAN);
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_getinfo_is_readable,
|
||||||
|
tvb, 13, 1, ENC_LITTLE_ENDIAN);
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_getinfo_is_writeable,
|
||||||
|
tvb, 13, 1, ENC_LITTLE_ENDIAN);
|
||||||
|
return tvb_captured_length(tvb);
|
||||||
|
} else if (id == 406) { /* Dissect List.0.X frame */
|
||||||
|
/* FT_UINT_STRING counted string, with count being the first byte */
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_entry_base_name,
|
||||||
|
tvb, 4, 1, ENC_ASCII|ENC_BIG_ENDIAN);
|
||||||
|
return tvb_captured_length(tvb);
|
||||||
|
} else if (id == 407) { /* Dissect Modify.1.X frame */
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_modify_error,
|
||||||
|
tvb, 0, 2, ENC_LITTLE_ENDIAN);
|
||||||
|
return tvb_captured_length(tvb);
|
||||||
|
} else if (id == 408) { /* Dissect Read.1.X frame */
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_read_error,
|
||||||
|
tvb, 0, 2, ENC_LITTLE_ENDIAN);
|
||||||
|
guint16 data_len = tvb_get_guint16(tvb, 2, ENC_LITTLE_ENDIAN);
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_primitive_Unstructured,
|
||||||
|
tvb, 4, data_len, ENC_NA);
|
||||||
|
return tvb_captured_length(tvb);
|
||||||
|
} else if (id == 409) { /* Dissect Write.1.X frame */
|
||||||
|
proto_tree_add_item(tree, hf_uavcan_write_error,
|
||||||
|
tvb, 0, 2, ENC_LITTLE_ENDIAN);
|
||||||
|
return tvb_captured_length(tvb);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
proto_register_dsdl(void)
|
||||||
|
{
|
||||||
|
static hf_register_info hf[] = {
|
||||||
|
{&hf_node_id,
|
||||||
|
{"Node ID", "uavcan_dsdl.node.id",
|
||||||
|
FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_pnp_unique_id,
|
||||||
|
{"Unique ID", "uavcan_dsdl.pnp.unique_id",
|
||||||
|
FT_BYTES, BASE_NONE | BASE_ALLOW_ZERO, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_pnp_unique_id_hash,
|
||||||
|
{"Unique ID hash", "uavcan_dsdl.pnp.unique_id_hash",
|
||||||
|
FT_BYTES, BASE_NONE | BASE_ALLOW_ZERO, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_pnp_alloc,
|
||||||
|
{"allocation type", "uavcan_dsdl.pnp.allocation",
|
||||||
|
FT_UINT8, BASE_DEC, VALS(uavcan_nodeid_alloc_vals), 0x0, NULL, HFILL}},
|
||||||
|
|
||||||
|
// Heartbeat 1.0
|
||||||
|
{&hf_heartbeat_uptime,
|
||||||
|
{"Uptime", "uavcan_dsdl.Heartbeat.uptime",
|
||||||
|
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_heartbeat_health,
|
||||||
|
{"Health", "uavcan_dsdl.Heartbeat.health",
|
||||||
|
FT_UINT8, BASE_DEC, VALS(uavcan_heartbeat_health_vals), 0x0, NULL, HFILL}},
|
||||||
|
{&hf_heartbeat_mode,
|
||||||
|
{"Mode", "uavcan_dsdl.Heartbeat.mode",
|
||||||
|
FT_UINT8, BASE_DEC, VALS(uavcan_heartbeat_mode_vals), 0x0, NULL, HFILL}},
|
||||||
|
{&hf_heartbeat_status_code,
|
||||||
|
{"Vendor specific status code",
|
||||||
|
"uavcan_dsdl.Heartbeat.vendor_specific_status_code",
|
||||||
|
FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_time_syncronizedtimestamp,
|
||||||
|
{"Timestamp (usec)", "uavcan_dsdl.time.SynchronizedTimestamp",
|
||||||
|
FT_UINT56, BASE_DEC, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_diagnostic_severity,
|
||||||
|
{"Severity", "uavcan_dsdl.diagnostic.severity",
|
||||||
|
FT_UINT8, BASE_DEC, VALS(uavcan_diagnostic_severity_vals), 0x0, NULL, HFILL}},
|
||||||
|
|
||||||
|
// List1.0 Request
|
||||||
|
{&hf_list_index,
|
||||||
|
{"Index", "uavcan_dsdl.register.List.index",
|
||||||
|
FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_register_name,
|
||||||
|
{"Name", "uavcan_dsdl.register.Name",
|
||||||
|
FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
|
||||||
|
|
||||||
|
// Access1.0 Value1.0
|
||||||
|
{&hf_register_access_mutable,
|
||||||
|
{"Mutable", "uavcan_dsdl.register.Access.mutable",
|
||||||
|
FT_UINT8, BASE_DEC, NULL, 0x1, NULL, HFILL}},
|
||||||
|
{&hf_register_access_persistent,
|
||||||
|
{"Persistent", "uavcan_dsdl.register.Access.persistent",
|
||||||
|
FT_UINT8, BASE_DEC, NULL, 0x2, NULL, HFILL}},
|
||||||
|
{&hf_register_value_tag,
|
||||||
|
{"Tag", "uavcan_dsdl.register.Value.tag",
|
||||||
|
FT_UINT8, BASE_DEC, VALS(uavcan_value_tag_vals), 0x0, NULL, HFILL}},
|
||||||
|
{&hf_register_value_size,
|
||||||
|
{"Array size", "uavcan_dsdl.primitive.array.size",
|
||||||
|
FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_primitive_Empty,
|
||||||
|
{"Empty", "uavcan_dsdl.primitive.Empty",
|
||||||
|
FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_primitive_String,
|
||||||
|
{"String", "uavcan_dsdl.primitive.String",
|
||||||
|
FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_primitive_Unstructured,
|
||||||
|
{"Unstructured", "uavcan_dsdl.primitive.array.Unstructured",
|
||||||
|
FT_BYTES, BASE_NONE | BASE_ALLOW_ZERO, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_primitive_array_Integer64,
|
||||||
|
{"Integer64", "uavcan_dsdl.primitive.array.Integer64",
|
||||||
|
FT_INT64, BASE_DEC, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_primitive_array_Integer32,
|
||||||
|
{"Integer32", "uavcan_dsdl.primitive.array.Integer32",
|
||||||
|
FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_primitive_array_Integer16,
|
||||||
|
{"Integer16", "uavcan_dsdl.primitive.array.Integer16",
|
||||||
|
FT_INT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_primitive_array_Integer8,
|
||||||
|
{"Integer8", "uavcan_dsdl.primitive.array.Integer8",
|
||||||
|
FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_primitive_array_Natural64,
|
||||||
|
{"Natural64", "uavcan_dsdl.primitive.array.Natural64",
|
||||||
|
FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_primitive_array_Natural32,
|
||||||
|
{"Natural32", "uavcan_dsdl.primitive.array.Natural32",
|
||||||
|
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_primitive_array_Natural16,
|
||||||
|
{"Natural16", "uavcan_dsdl.primitive.array.Natural16",
|
||||||
|
FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_primitive_array_Natural8,
|
||||||
|
{"Natural8", "uavcan_dsdl.primitive.array.Natural8",
|
||||||
|
FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_primitive_array_Real64,
|
||||||
|
{"Real64", "uavcan_dsdl.primitive.array.Real64",
|
||||||
|
FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_primitive_array_Real32,
|
||||||
|
{"Real32", "uavcan_dsdl.primitive.array.Real32",
|
||||||
|
FT_FLOAT, BASE_NONE, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_primitive_array_Real16,
|
||||||
|
{"Real16", "uavcan_dsdl.primitive.array.Real16",
|
||||||
|
FT_IEEE_11073_SFLOAT, BASE_NONE, NULL, 0x0, NULL, HFILL} /* TODO not sure check */
|
||||||
|
},
|
||||||
|
{&hf_uavcan_getinfo_path,
|
||||||
|
{"Path", "uavcan_dsdl.file.GetInfo.path",
|
||||||
|
FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_getinfo_error,
|
||||||
|
{"Error", "uavcan_dsdl.file.GetInfo.error",
|
||||||
|
FT_UINT16, BASE_DEC, VALS(uavcan_file_error_vals), 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_getinfo_size,
|
||||||
|
{"Size", "uavcan_dsdl.file.GetInfo.size",
|
||||||
|
FT_UINT40, BASE_DEC, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_getinfo_timestamp,
|
||||||
|
{"Path", "uavcan_dsdl.file.GetInfo.timestamp",
|
||||||
|
FT_UINT40, BASE_DEC, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_getinfo_is_file_not_directory,
|
||||||
|
{"Is file not directory",
|
||||||
|
"uavcan_dsdl.file.GetInfo.is_file_not_directory",
|
||||||
|
FT_UINT8, BASE_DEC, NULL, 0x1, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_getinfo_is_link,
|
||||||
|
{"Is link", "uavcan_dsdl.file.GetInfo.is_link",
|
||||||
|
FT_UINT8, BASE_DEC, NULL, 0x2, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_getinfo_is_readable,
|
||||||
|
{"Is readable", "uavcan_dsdl.file.GetInfo.is_readable",
|
||||||
|
FT_UINT8, BASE_DEC, NULL, 0x4, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_getinfo_is_writeable,
|
||||||
|
{"Is writeable", "uavcan_dsdl.file.GetInfo.is_writeable",
|
||||||
|
FT_UINT8, BASE_DEC, NULL, 0x8, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_read_path,
|
||||||
|
{"Path", "uavcan_dsdl.file.Read.path",
|
||||||
|
FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_write_path,
|
||||||
|
{"Path", "uavcan_dsdl.file.Write.path",
|
||||||
|
FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_directory_path,
|
||||||
|
{"Directory path", "uavcan_dsdl.file.list.directory_path",
|
||||||
|
FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_entry_base_name,
|
||||||
|
{"Directory path", "uavcan_dsdl.file.list.entry_base_name",
|
||||||
|
FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_modify_source_path,
|
||||||
|
{"Source", "uavcan_dsdl.file.Modify.source",
|
||||||
|
FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_modify_destination_path,
|
||||||
|
{"Destination", "uavcan_dsdl.file.Modify.Destination",
|
||||||
|
FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_modify_preserve_source,
|
||||||
|
{"Preserve source", "uavcan_dsdl.Modify.preserve_source",
|
||||||
|
FT_UINT8, BASE_DEC, NULL, 0x1, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_modify_overwrite_destination,
|
||||||
|
{"Overwrite destination", "uavcan_dsdl.Modify.overwrite_destination",
|
||||||
|
FT_UINT8, BASE_DEC, NULL, 0x2, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_modify_error,
|
||||||
|
{"Error", "uavcan_dsdl.Modify.error",
|
||||||
|
FT_UINT16, BASE_DEC, VALS(uavcan_file_error_vals), 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_read_offset,
|
||||||
|
{"Offset", "uavcan_dsdl.Read.offset",
|
||||||
|
FT_UINT40, BASE_DEC, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_read_error,
|
||||||
|
{"Error", "uavcan_dsdl.Read.error",
|
||||||
|
FT_UINT16, BASE_DEC, VALS(uavcan_file_error_vals), 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_write_offset,
|
||||||
|
{"Offset", "uavcan_dsdl.Write.offset",
|
||||||
|
FT_UINT40, BASE_DEC, NULL, 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_write_error,
|
||||||
|
{"Error", "uavcan_dsdl.Write.error",
|
||||||
|
FT_UINT16, BASE_DEC, VALS(uavcan_file_error_vals), 0x0, NULL, HFILL}},
|
||||||
|
{&hf_uavcan_entry_index,
|
||||||
|
{"Entry index", "uavcan_dsdl.file.list.entry_index",
|
||||||
|
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
|
||||||
|
};
|
||||||
|
|
||||||
|
static gint *ett[] = {
|
||||||
|
&ett_dsdl,
|
||||||
|
};
|
||||||
|
|
||||||
|
proto_dsdl = proto_register_protocol("DSDL", "DSDL", "uavcan_dsdl");
|
||||||
|
|
||||||
|
proto_register_field_array(proto_dsdl, hf, array_length(hf));
|
||||||
|
proto_register_subtree_array(ett, array_length(ett));
|
||||||
|
|
||||||
|
register_dissector("uavcan_dsdl.message", dissect_dsdl_message, proto_dsdl);
|
||||||
|
register_dissector("uavcan_dsdl.request", dissect_dsdl_service_request, proto_dsdl);
|
||||||
|
register_dissector("uavcan_dsdl.response", dissect_dsdl_service_response, proto_dsdl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
proto_reg_handoff_dsdl(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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:
|
||||||
|
*/
|
|
@ -0,0 +1,20 @@
|
||||||
|
/* packet-uavcan-dsdl.h
|
||||||
|
* Routines for dissection of DSDL used in UAVCAN
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PACKET_UAVCAN_DSDL_H_
|
||||||
|
#define _PACKET_UAVCAN_DSDL_H_
|
||||||
|
|
||||||
|
extern const range_string uavcan_subject_id_vals[];
|
||||||
|
extern const range_string uavcan_service_id_vals[];
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _PACKET_UAVCAN_DSDL_H_ */
|
Loading…
Reference in New Issue