Coverage Report

Created: 2026-09-28 06:52

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