Coverage Report

Created: 2025-12-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/wiretap/socketcan.c
Line
Count
Source
1
/** @file
2
 *
3
 * Common functionality for all wiretaps handling SocketCAN encapsulation
4
 *
5
 * Wiretap Library
6
 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
7
 *
8
 * SPDX-License-Identifier: GPL-2.0-or-later
9
 */
10
11
12
#include "config.h"
13
#include "socketcan.h"
14
#include <epan/dissectors/packet-socketcan.h>
15
16
typedef struct can_frame {
17
    uint32_t can_id;                       /* 32 bit CAN_ID + EFF/RTR/ERR flags */
18
    uint8_t can_dlc;                      /* frame payload length in byte (0 .. CAN_MAX_DLEN) */
19
    uint8_t __pad;                        /* padding */
20
    uint8_t __res0;                       /* reserved / padding */
21
    uint8_t __res1;                       /* reserved / padding */
22
    uint8_t data[CAN_MAX_DLEN];
23
} can_frame_t;
24
25
typedef struct canfd_frame {
26
    uint32_t can_id;                       /* 32 bit CAN_ID + EFF flag */
27
    uint8_t len;                          /* frame payload length in byte */
28
    uint8_t flags;                        /* additional flags for CAN FD */
29
    uint8_t __res0;                       /* reserved / padding */
30
    uint8_t __res1;                       /* reserved / padding */
31
    uint8_t data[CANFD_MAX_DLEN];
32
} canfd_frame_t;
33
34
typedef struct can_priv_data {
35
    GHashTable* interface_ids;  /* map name/description/link-layer type to interface ID */
36
    unsigned num_interface_ids; /* Number of interface IDs assigned */
37
38
    void (*tap_close)(void*);
39
    void* tap_priv;
40
41
} can_priv_data_t;
42
43
/*
44
 * Hash table to map interface name to interface ID.
45
 */
46
47
static gboolean
48
destroy_if_name(void* key, void* value _U_, void* user_data _U_)
49
0
{
50
0
    char* name = (char*)key;
51
52
0
    g_free(name);
53
54
0
    return true;
55
0
}
56
57
static void
58
add_new_if_name(can_priv_data_t* can_data, const char* name, void** result)
59
0
{
60
0
    char* new_name;
61
62
0
    new_name = g_strdup(name);
63
0
    *result = GUINT_TO_POINTER(can_data->num_interface_ids);
64
0
    g_hash_table_insert(can_data->interface_ids, (void*)new_name, *result);
65
0
    can_data->num_interface_ids++;
66
0
}
67
68
static void
69
wtap_socketcan_close(wtap* wth)
70
0
{
71
    //Clean up wiretap data
72
0
    can_priv_data_t* data = (can_priv_data_t*)wth->priv;
73
0
    if (data->tap_close != NULL)
74
0
        data->tap_close(data->tap_priv);
75
76
    //Cleanup our interface data
77
0
    g_hash_table_foreach_remove(data->interface_ids, destroy_if_name, NULL);
78
0
    g_hash_table_destroy(data->interface_ids);
79
0
    g_free(data);
80
81
0
    wth->priv = NULL;
82
0
}
83
84
void*
85
wtap_socketcan_get_private_data(wtap* wth)
86
0
{
87
0
    can_priv_data_t* socket_can_data = (can_priv_data_t*)wth->priv;
88
0
    return socket_can_data->tap_priv;
89
0
}
90
91
void
92
wtap_set_as_socketcan(wtap* wth, int file_type_subtype, int tsprec, void* tap_priv, void (*tap_close)(void*))
93
0
{
94
    //Create the private data that wraps over the wiretap's private data
95
0
    can_priv_data_t* socketcan_priv_data = g_new0(can_priv_data_t, 1);
96
0
    socketcan_priv_data->interface_ids = g_hash_table_new(g_str_hash, g_str_equal);
97
98
0
    socketcan_priv_data->tap_priv = tap_priv;
99
0
    socketcan_priv_data->tap_close = tap_close;
100
101
0
    wth->file_type_subtype = file_type_subtype;
102
0
    wth->file_encap = WTAP_ENCAP_SOCKETCAN;
103
0
    wth->file_tsprec = tsprec;
104
0
    wth->subtype_close = wtap_socketcan_close;
105
0
    wth->priv = socketcan_priv_data;
106
0
}
107
108
bool
109
wtap_socketcan_gen_packet(wtap* wth, wtap_rec* rec, const wtap_can_msg_t* msg, char* module_name, int* err, char** err_info)
110
0
{
111
0
    bool is_fd = false,
112
0
         is_eff = false,
113
0
         is_rtr = false,
114
0
         is_err = false;
115
116
0
    switch (msg->type)
117
0
    {
118
0
    case MSG_TYPE_STD:
119
        //No flags
120
0
        break;
121
0
    case MSG_TYPE_EXT:
122
0
        is_eff = true;
123
0
        break;
124
0
    case MSG_TYPE_STD_RTR:
125
0
        is_rtr = true;
126
0
        break;
127
0
    case MSG_TYPE_EXT_RTR:
128
0
        is_rtr = is_eff = true;
129
0
        break;
130
0
    case MSG_TYPE_STD_FD:
131
0
        is_fd = true;
132
0
        break;
133
0
    case MSG_TYPE_EXT_FD:
134
0
        is_fd = is_eff = true;
135
0
        break;
136
0
    case MSG_TYPE_ERR:
137
0
        is_err = true;
138
0
        break;
139
140
0
    }
141
142
    /* Generate Exported PDU tags for the packet info */
143
0
    ws_buffer_clean(&rec->data);
144
145
0
    if (is_fd)
146
0
    {
147
0
        canfd_frame_t canfd_frame = { 0 };
148
149
        /*
150
         * There's a maximum of CANFD_MAX_DLEN bytes in a CAN-FD frame.
151
         */
152
0
        if (msg->data.length > CANFD_MAX_DLEN) {
153
0
            *err = WTAP_ERR_BAD_FILE;
154
0
            if (err_info != NULL) {
155
0
                *err_info = ws_strdup_printf("%s: File has %u-byte CAN FD packet, bigger than maximum of %u",
156
0
                    module_name, msg->data.length, CANFD_MAX_DLEN);
157
0
            }
158
0
            return false;
159
0
        }
160
161
0
        canfd_frame.can_id = g_htonl((msg->id & (is_eff ? CAN_EFF_MASK : CAN_SFF_MASK)) |
162
0
            (is_eff ? CAN_EFF_FLAG : 0) |
163
0
            (is_err ? CAN_ERR_FLAG : 0));
164
0
        canfd_frame.flags = msg->flags | CANFD_FDF;
165
0
        canfd_frame.len = msg->data.length;
166
0
        memcpy(canfd_frame.data, msg->data.data, msg->data.length);
167
168
0
        ws_buffer_append(&rec->data, (uint8_t*)&canfd_frame, sizeof(canfd_frame));
169
0
    }
170
0
    else
171
0
    {
172
0
        can_frame_t can_frame = { 0 };
173
174
        /*
175
         * There's a maximum of CAN_MAX_DLEN bytes in a CAN frame.
176
         */
177
0
        if (msg->data.length > CAN_MAX_DLEN) {
178
0
            *err = WTAP_ERR_BAD_FILE;
179
0
            if (err_info != NULL) {
180
0
                *err_info = ws_strdup_printf("%s: File has %u-byte CAN packet, bigger than maximum of %u",
181
0
                    module_name, msg->data.length, CAN_MAX_DLEN);
182
0
            }
183
0
            return false;
184
0
        }
185
186
0
        can_frame.can_id = g_htonl((msg->id & (is_eff ? CAN_EFF_MASK : CAN_SFF_MASK)) |
187
0
            (is_rtr ? CAN_RTR_FLAG : 0) |
188
0
            (is_eff ? CAN_EFF_FLAG : 0) |
189
0
            (is_err ? CAN_ERR_FLAG : 0));
190
0
        can_frame.can_dlc = msg->data.length;
191
0
        memcpy(can_frame.data, msg->data.data, msg->data.length);
192
193
0
        ws_buffer_append(&rec->data, (uint8_t*)&can_frame, sizeof(can_frame));
194
0
    }
195
196
0
    wtap_setup_packet_rec(rec, wth->file_encap);
197
0
    rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
198
0
    rec->presence_flags = WTAP_HAS_TS;
199
0
    rec->ts = msg->ts;
200
0
    rec->tsprec = wth->file_tsprec;
201
202
0
    rec->rec_header.packet_header.caplen = (uint32_t)ws_buffer_length(&rec->data);
203
0
    rec->rec_header.packet_header.len = (uint32_t)ws_buffer_length(&rec->data);
204
205
0
    if (msg->interface_id != 0xFFFFFFFF) {
206
0
        rec->presence_flags |= WTAP_HAS_INTERFACE_ID;
207
0
        rec->rec_header.packet_header.interface_id = msg->interface_id;
208
0
    }
209
210
0
    return true;
211
0
}
212
213
uint32_t
214
wtap_socketcan_find_or_create_new_interface(wtap* wth, const char* name)
215
0
{
216
0
    void* result = NULL;
217
0
    can_priv_data_t* can_data = (can_priv_data_t*)wth->priv;
218
219
0
    if (!g_hash_table_lookup_extended(can_data->interface_ids, name, NULL, &result))
220
0
    {
221
0
        wtap_block_t int_data;
222
0
        wtapng_if_descr_mandatory_t* int_data_mand;
223
224
        /*
225
         * Not found; make a new entry.
226
         */
227
0
        add_new_if_name(can_data, name, &result);
228
229
        /*
230
         * Now make a new IDB and add it.
231
         */
232
0
        int_data = wtap_block_create(WTAP_BLOCK_IF_ID_AND_INFO);
233
0
        int_data_mand = (wtapng_if_descr_mandatory_t*)wtap_block_get_mandatory_data(int_data);
234
235
0
        int_data_mand->wtap_encap = WTAP_ENCAP_SOCKETCAN;
236
0
        int_data_mand->tsprecision = WTAP_TSPREC_USEC;
237
0
        int_data_mand->time_units_per_second = 1000000; /* Microsecond resolution */
238
0
        int_data_mand->snap_len = WTAP_MAX_PACKET_SIZE_STANDARD; /* XXX - not known */
239
240
0
        wtap_block_add_uint8_option(int_data, OPT_IDB_TSRESOL, 0x06); /* microsecond resolution */
241
        /* Interface statistics */
242
0
        int_data_mand->num_stat_entries = 0;
243
0
        int_data_mand->interface_statistics = NULL;
244
245
0
        wtap_block_set_string_option_value(int_data, OPT_IDB_NAME, name, strlen(name));
246
0
        wtap_add_idb(wth, int_data);
247
0
    }
248
    return GPOINTER_TO_UINT(result);
249
0
}