Coverage Report

Created: 2025-12-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-caneth.c
Line
Count
Source
1
/* packet-caneth.c
2
 * Routines for Controller Area Network over Ethernet dissection
3
 * Copyright 2018, Lazar Sumar <bugzilla@lazar.co.nz>
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998 Gerald Combs
8
 *
9
 * SPDX-License-Identifier: GPL-2.0-or-later
10
 */
11
12
/*
13
 * The CAN-ETH protocol is used for transmitting the Controller Area Network
14
 * (CAN) protocol over UDP.
15
 *
16
 * The protocol definition can be found at http://www.proconx.com/assets/files/products/caneth/canframe.pdf
17
 */
18
19
#include <config.h>
20
21
#include <epan/packet.h>
22
#include "packet-udp.h"
23
#include "packet-socketcan.h"
24
25
0
#define CAN_FRAME_LEN   15
26
27
0
#define CAN_ID_OFFSET       0
28
0
#define CAN_DLC_OFFSET      4
29
0
#define CAN_DATA_OFFSET     5
30
0
#define CAN_EXT_FLAG_OFFSET 13
31
0
#define CAN_RTR_FLAG_OFFSET 14
32
33
static const char magic[] = "ISO11898";
34
35
void proto_reg_handoff_caneth(void);
36
void proto_register_caneth(void);
37
38
static dissector_handle_t caneth_handle;
39
40
static int proto_caneth;
41
static int hf_caneth_magic;
42
static int hf_caneth_version;
43
static int hf_caneth_frames;
44
static int hf_caneth_options;
45
46
static int hf_caneth_can_ident_ext;
47
static int hf_caneth_can_ident_std;
48
static int hf_caneth_can_extflag;
49
static int hf_caneth_can_rtrflag;
50
static int hf_caneth_can_len;
51
static int hf_caneth_can_padding;
52
53
14
#define CANETH_UDP_PORT 11898
54
55
static int ett_caneth;
56
static int ett_caneth_frames;
57
static int ett_caneth_can;
58
59
static int proto_can;      // use CAN protocol for consistent filtering
60
61
/* A sample #define of the minimum length (in bytes) of the protocol data.
62
 * If data is received with fewer than this many bytes it is rejected by
63
 * the current dissector. */
64
2
#define CANETH_MIN_LENGTH 10
65
66
static bool
67
test_caneth(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
68
2
{
69
    /* Check that we have enough length for the Magic, Version, and Length */
70
2
    if (tvb_reported_length(tvb) < CANETH_MIN_LENGTH)
71
1
        return false;
72
    /* Check that the magic id matches */
73
1
    if (tvb_strneql(tvb, offset, magic, 8) != 0)
74
1
        return false;
75
    /* Check that the version is 1 as that is the only supported version */
76
0
    if (tvb_get_uint8(tvb, offset+8) != 1)
77
0
        return false;
78
    /* Check that the version 1 limit of 16 can frames is respected */
79
0
    if (tvb_get_uint8(tvb, offset+9) > 16)
80
0
        return false;
81
0
    return true;
82
0
}
83
84
static unsigned
85
get_caneth_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
86
0
{
87
0
    return (unsigned) tvb_get_ntohs(tvb, offset+3);
88
0
}
89
90
static int
91
dissect_caneth_can(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
92
0
{
93
0
    proto_tree *can_tree;
94
0
    proto_item *ti;
95
0
    uint32_t    raw_can_id;
96
0
    int8_t      ext_flag;
97
0
    int8_t      rtr_flag;
98
0
    tvbuff_t*   next_tvb;
99
0
    struct can_info can_info;
100
101
0
    ti = proto_tree_add_item(tree, proto_can, tvb, 0, -1, ENC_NA);
102
0
    can_tree = proto_item_add_subtree(ti, ett_caneth_can);
103
104
0
    ext_flag = tvb_get_uint8(tvb, CAN_EXT_FLAG_OFFSET);
105
0
    rtr_flag = tvb_get_uint8(tvb, CAN_RTR_FLAG_OFFSET);
106
107
0
    if (ext_flag)
108
0
    {
109
0
        proto_tree_add_item_ret_uint(can_tree, hf_caneth_can_ident_ext, tvb, CAN_ID_OFFSET, 4, ENC_LITTLE_ENDIAN, &raw_can_id);
110
0
        can_info.id = raw_can_id & CAN_EFF_MASK;
111
0
    }
112
0
    else
113
0
    {
114
0
        proto_tree_add_item_ret_uint(can_tree, hf_caneth_can_ident_std, tvb, CAN_ID_OFFSET, 4, ENC_LITTLE_ENDIAN, &raw_can_id);
115
0
        can_info.id = raw_can_id & CAN_SFF_MASK;
116
0
    }
117
118
0
    can_info.id |= (ext_flag ? CAN_EFF_FLAG : 0) | (rtr_flag ? CAN_RTR_FLAG : 0);
119
0
    can_info.fd = CAN_TYPE_CAN_CLASSIC;
120
0
    can_info.bus_id = 0; /* see get_bus_id in packet-socketcan.c? */
121
122
0
    proto_tree_add_item_ret_uint(can_tree, hf_caneth_can_len, tvb, CAN_DLC_OFFSET, 1, ENC_NA, &can_info.len);
123
0
    proto_tree_add_item(can_tree, hf_caneth_can_extflag, tvb, CAN_EXT_FLAG_OFFSET, 1, ENC_NA);
124
0
    proto_tree_add_item(can_tree, hf_caneth_can_rtrflag, tvb, CAN_RTR_FLAG_OFFSET, 1, ENC_NA);
125
126
0
    next_tvb = tvb_new_subset_length(tvb, CAN_DATA_OFFSET, can_info.len);
127
128
0
    if (!socketcan_call_subdissectors(next_tvb, pinfo, tree, &can_info, false)) {
129
0
        call_data_dissector(next_tvb, pinfo, tree);
130
0
    }
131
132
0
    if (tvb_captured_length_remaining(tvb, CAN_DATA_OFFSET + can_info.len) > 0)
133
0
    {
134
0
        proto_tree_add_item(can_tree, hf_caneth_can_padding, tvb, CAN_DATA_OFFSET + can_info.len, -1, ENC_NA);
135
0
    }
136
0
    return tvb_captured_length(tvb);
137
0
}
138
139
static int
140
dissect_caneth(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
141
2
{
142
2
    proto_tree *caneth_tree;
143
2
    proto_item *ti;
144
2
    uint32_t    frame_count, offset;
145
2
    tvbuff_t*   next_tvb;
146
147
2
    if (!test_caneth(pinfo, tvb, 0, data))
148
2
        return 0;
149
150
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "CAN-ETH");
151
0
    col_clear(pinfo->cinfo, COL_INFO);
152
153
0
    ti = proto_tree_add_item(tree, proto_caneth, tvb, 0, -1, ENC_NA);
154
0
    caneth_tree = proto_item_add_subtree(ti, ett_caneth);
155
156
0
    proto_tree_add_item(caneth_tree, hf_caneth_magic, tvb, 0, 8, ENC_ASCII);
157
0
    proto_tree_add_item(caneth_tree, hf_caneth_version, tvb, 8, 1, ENC_NA);
158
0
    proto_tree_add_item_ret_uint(caneth_tree, hf_caneth_frames, tvb, 9, 1, ENC_NA, &frame_count);
159
160
0
    for (offset = 10; frame_count-- > 0; offset += CAN_FRAME_LEN)
161
0
    {
162
0
        next_tvb = tvb_new_subset_length(tvb, offset, CAN_FRAME_LEN);
163
0
        dissect_caneth_can(next_tvb, pinfo, tree, data);
164
0
    }
165
166
0
    if (tvb_captured_length_remaining(tvb, offset) > 0)
167
0
    {
168
0
        proto_tree_add_item(caneth_tree, hf_caneth_options, tvb, offset, -1, ENC_NA);
169
0
    }
170
171
0
    return tvb_captured_length(tvb);
172
2
}
173
174
static bool
175
dissect_caneth_heur_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
176
0
{
177
0
    return (udp_dissect_pdus(tvb, pinfo, tree, CANETH_MIN_LENGTH, test_caneth,
178
0
                     get_caneth_len, dissect_caneth, data) != 0);
179
0
}
180
181
void
182
proto_register_caneth(void)
183
14
{
184
14
    static hf_register_info hf[] = {
185
14
        {
186
14
            &hf_caneth_magic,
187
14
            {
188
14
                "Magic", "caneth.magic",
189
14
                FT_STRING, BASE_NONE,
190
14
                NULL, 0x0,
191
14
                "The magic identifier used to denote the start of a CAN-ETH packet", HFILL
192
14
            }
193
14
        },
194
14
        {
195
14
            &hf_caneth_version,
196
14
            {
197
14
                "Version", "caneth.version",
198
14
                FT_UINT8, BASE_DEC,
199
14
                NULL, 0x0,
200
14
                NULL, HFILL
201
14
            }
202
14
        },
203
14
        {
204
14
            &hf_caneth_frames,
205
14
            {
206
14
                "CAN Frames", "caneth.frames",
207
14
                FT_UINT8, BASE_DEC,
208
14
                NULL, 0x0,
209
14
                "Number of enclosed CAN frames", HFILL
210
14
            }
211
14
        },
212
14
        {
213
14
            &hf_caneth_options,
214
14
            {
215
14
                "Options (Reserved)", "caneth.options",
216
14
                FT_BYTES, BASE_NONE,
217
14
                NULL, 0x0,
218
14
                "Options field, reserved for future use, should be empty", HFILL
219
14
            }
220
14
        },
221
14
        {
222
14
            &hf_caneth_can_ident_ext,
223
14
            {
224
14
                "Identifier", "can.id",
225
14
                FT_UINT32, BASE_HEX,
226
14
                NULL, CAN_EFF_MASK,
227
14
                NULL, HFILL
228
14
            }
229
14
        },
230
14
        {
231
14
            &hf_caneth_can_ident_std,
232
14
            {
233
14
                "Identifier", "can.id",
234
14
                FT_UINT32, BASE_HEX,
235
14
                NULL, CAN_SFF_MASK,
236
14
                NULL, HFILL
237
14
            }
238
14
        },
239
14
        {
240
14
            &hf_caneth_can_extflag,
241
14
            {
242
14
                "Extended Flag", "can.flags.xtd",
243
14
                FT_BOOLEAN, BASE_NONE,
244
14
                NULL, 0,
245
14
                NULL, HFILL
246
14
            }
247
14
        },
248
14
        {
249
14
            &hf_caneth_can_rtrflag,
250
14
            {
251
14
                "Remote Transmission Request Flag", "can.flags.rtr",
252
14
                FT_BOOLEAN, BASE_NONE,
253
14
                NULL, 0,
254
14
                NULL, HFILL
255
14
            }
256
14
        },
257
14
        {
258
14
            &hf_caneth_can_len,
259
14
            {
260
14
                "Frame-Length", "can.len",
261
14
                FT_UINT8, BASE_DEC,
262
14
                NULL, 0x0,
263
14
                NULL, HFILL
264
14
            }
265
14
        },
266
14
        {
267
14
            &hf_caneth_can_padding,
268
14
            {
269
14
                "Padding", "caneth.can.padding",
270
14
                FT_BYTES, BASE_NONE,
271
14
                NULL, 0x0,
272
14
                NULL, HFILL
273
14
            }
274
14
        },
275
14
    };
276
277
14
    static int *ett[] = {
278
14
        &ett_caneth,
279
14
        &ett_caneth_frames,
280
14
        &ett_caneth_can,
281
14
    };
282
283
14
    proto_caneth = proto_register_protocol("Controller Area Network over Ethernet", "CAN-ETH", "caneth");
284
285
14
    proto_register_field_array(proto_caneth, hf, array_length(hf));
286
14
    proto_register_subtree_array(ett, array_length(ett));
287
288
14
    caneth_handle = register_dissector("caneth", dissect_caneth, proto_caneth);
289
14
}
290
291
void
292
proto_reg_handoff_caneth(void)
293
14
{
294
14
    dissector_add_uint_with_preference("udp.port", CANETH_UDP_PORT, caneth_handle);
295
296
14
    heur_dissector_add("udp", dissect_caneth_heur_udp, "CAN-ETH over UDP", "caneth_udp", proto_caneth, HEURISTIC_DISABLE);
297
298
14
    proto_can = proto_get_id_by_filter_name("can");
299
14
}
300
301
/*
302
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
303
 *
304
 * Local variables:
305
 * c-basic-offset: 4
306
 * tab-width: 8
307
 * indent-tabs-mode: nil
308
 * End:
309
 *
310
 * vi: set shiftwidth=4 tabstop=8 expandtab:
311
 * :indentSize=4:tabSize=8:noTabs=true:
312
 */