Coverage Report

Created: 2026-07-12 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/wiretap/autosar_dlt.c
Line
Count
Source
1
/* autosar_dlt.c
2
 *
3
 * Wiretap Library
4
 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
5
 *
6
 * Support for DLT file format as defined by AUTOSAR et. al.
7
 * Copyright (c) 2022-2022 by Dr. Lars Voelker <lars.voelker@technica-engineering.de>
8
 *
9
 * SPDX-License-Identifier: GPL-2.0-or-later
10
 */
11
12
/*
13
 * Sources for specification:
14
 * https://www.autosar.org/fileadmin/standards/R24-11/CP/AUTOSAR_CP_SWS_DiagnosticLogAndTrace.pdf
15
 * https://www.autosar.org/fileadmin/standards/R24-11/FO/AUTOSAR_FO_PRS_LogAndTraceProtocol.pdf
16
 * https://github.com/COVESA/dlt-viewer
17
 */
18
19
#include <config.h>
20
0
#define WS_LOG_DOMAIN LOG_DOMAIN_WIRETAP
21
22
#include <errno.h>
23
#include "autosar_dlt.h"
24
25
#include "file_wrappers.h"
26
#include "wtap_module.h"
27
28
static const uint8_t dlt_magic[] = { 'D', 'L', 'T', 0x01 };
29
30
static int autosar_dlt_file_type_subtype = -1;
31
32
33
void register_autosar_dlt(void);
34
static bool autosar_dlt_read(wtap *wth, wtap_rec *rec, int *err, char **err_info, int64_t *data_offset);
35
static bool autosar_dlt_seek_read(wtap *wth, int64_t seek_off, wtap_rec* rec, int *err, char **err_info);
36
static void autosar_dlt_close(wtap *wth);
37
38
39
typedef struct autosar_dlt_blockheader {
40
    uint8_t  magic[4];
41
    uint32_t timestamp_s;
42
    uint32_t timestamp_us;
43
    uint8_t  ecu_id[4];
44
} autosar_dlt_blockheader_t;
45
46
typedef struct autosar_dlt_itemheader {
47
    uint8_t  header_type;
48
    uint8_t  counter;
49
    uint16_t length;
50
} autosar_dlt_itemheader_t;
51
52
53
typedef struct autosar_dlt_data {
54
    GHashTable *ecu_to_iface_ht;
55
    uint32_t    next_interface_id;
56
} autosar_dlt_t;
57
58
typedef struct autosar_dlt_params {
59
    wtap           *wth;
60
    wtap_rec       *rec;
61
    FILE_T          fh;
62
63
    autosar_dlt_t  *dlt_data;
64
} autosar_dlt_params_t;
65
66
static int
67
0
autosar_dlt_calc_key(uint8_t ecu[4]) {
68
0
    return (int)(ecu[0] << 24 | ecu[1] << 16 | ecu[2] << 8 | ecu[3]);
69
0
}
70
71
static uint32_t
72
0
autosar_dlt_add_interface(autosar_dlt_params_t *params, uint8_t ecu[4]) {
73
0
    wtap_block_t int_data = wtap_block_create(WTAP_BLOCK_IF_ID_AND_INFO);
74
0
    wtapng_if_descr_mandatory_t *if_descr_mand = (wtapng_if_descr_mandatory_t*)wtap_block_get_mandatory_data(int_data);
75
76
0
    if_descr_mand->wtap_encap = WTAP_ENCAP_AUTOSAR_DLT;
77
0
    wtap_block_add_string_option(int_data, OPT_IDB_NAME, (char *)ecu, 4);
78
0
    if_descr_mand->time_units_per_second = 1000 * 1000 * 1000;
79
0
    if_descr_mand->tsprecision = WTAP_TSPREC_NSEC;
80
0
    wtap_block_add_uint8_option(int_data, OPT_IDB_TSRESOL, 9);
81
0
    if_descr_mand->snap_len = WTAP_MAX_PACKET_SIZE_STANDARD;
82
0
    if_descr_mand->num_stat_entries = 0;
83
0
    if_descr_mand->interface_statistics = NULL;
84
0
    wtap_add_idb(params->wth, int_data);
85
86
0
    int32_t key = autosar_dlt_calc_key(ecu);
87
0
    uint32_t iface_id = params->dlt_data->next_interface_id++;
88
0
    g_hash_table_insert(params->dlt_data->ecu_to_iface_ht, GINT_TO_POINTER(key), GUINT_TO_POINTER(iface_id));
89
90
0
    return iface_id;
91
0
}
92
93
static uint32_t
94
0
autosar_dlt_lookup_interface(autosar_dlt_params_t *params, uint8_t ecu[4]) {
95
0
    int32_t key = autosar_dlt_calc_key(ecu);
96
97
0
    if (params->dlt_data->ecu_to_iface_ht == NULL) {
98
0
        return 0;
99
0
    }
100
101
0
    void *iface = NULL;
102
0
    bool found = g_hash_table_lookup_extended(params->dlt_data->ecu_to_iface_ht, GINT_TO_POINTER(key), NULL, &iface);
103
104
0
    if (found) {
105
0
        return GPOINTER_TO_UINT(iface);
106
0
    } else {
107
0
        return autosar_dlt_add_interface(params, ecu);
108
0
    }
109
0
}
110
111
static void
112
0
fix_endianness_autosar_dlt_blockheader(autosar_dlt_blockheader_t *header) {
113
0
    header->timestamp_s = GUINT32_FROM_LE(header->timestamp_s);
114
0
    header->timestamp_us = GUINT32_FROM_LE(header->timestamp_us);
115
0
}
116
117
static void
118
0
fix_endianness_autosar_dlt_itemheader(autosar_dlt_itemheader_t *header) {
119
0
    header->length = GUINT16_FROM_BE(header->length);
120
0
}
121
122
static bool
123
0
autosar_dlt_read_block(autosar_dlt_params_t *params, int64_t start_pos, int *err, char **err_info) {
124
0
    autosar_dlt_blockheader_t header;
125
0
    autosar_dlt_itemheader_t  item_header;
126
127
0
    if (!wtap_read_bytes_or_eof(params->fh, &header, sizeof header, err, err_info)) {
128
0
        if (*err == WTAP_ERR_SHORT_READ) {
129
0
            *err = WTAP_ERR_BAD_FILE;
130
0
            g_free(*err_info);
131
0
            *err_info = ws_strdup_printf("AUTOSAR DLT: Capture file cut short! Cannot find storage header at pos 0x%" PRIx64 "!", start_pos);
132
0
        }
133
0
        return false;
134
0
    }
135
136
0
    fix_endianness_autosar_dlt_blockheader(&header);
137
138
0
    if (memcmp(header.magic, dlt_magic, sizeof(dlt_magic))) {
139
0
        *err = WTAP_ERR_BAD_FILE;
140
0
        *err_info = ws_strdup_printf("AUTOSAR DLT: Bad capture file! Object magic is not DLT\\x01 at pos 0x%" PRIx64 "!", start_pos);
141
0
        return false;
142
0
    }
143
144
    /* Set to the byte after the magic. */
145
0
    uint64_t current_start_of_item = file_tell(params->fh) - sizeof header + 4;
146
147
0
    if (!wtap_read_bytes_or_eof(params->fh, &item_header, sizeof item_header, err, err_info)) {
148
0
        *err = WTAP_ERR_BAD_FILE;
149
0
        g_free(*err_info);
150
0
        *err_info = ws_strdup_printf("AUTOSAR DLT: Capture file cut short! Not enough bytes for item header at pos 0x%" PRIx64 "!", start_pos);
151
0
        return false;
152
0
    }
153
154
0
    fix_endianness_autosar_dlt_itemheader(&item_header);
155
156
0
    if (file_seek(params->fh, current_start_of_item, SEEK_SET, err) < 0) {
157
0
        return false;
158
0
    }
159
160
0
    ws_buffer_assure_space(&params->rec->data, (size_t)(item_header.length + sizeof header));
161
162
    /* Creating AUTOSAR DLT Encapsulation Header:
163
     * uint32_t   time_s
164
     * uint32_t   time_us
165
     * uint8_t[4] ecuname
166
     * uint8_t[1] 0x00 (termination)
167
     * uint8_t[3] reserved
168
     */
169
0
    void *tmpbuf = g_malloc0(sizeof header);
170
0
    if (!wtap_read_bytes_or_eof(params->fh, tmpbuf, sizeof header - 4, err, err_info)) {
171
        /* this would have been caught before ...*/
172
0
        g_free(tmpbuf);
173
0
        *err = WTAP_ERR_BAD_FILE;
174
0
        g_free(*err_info);
175
0
        *err_info = ws_strdup_printf("AUTOSAR DLT: Internal Error! Not enough bytes for storage header at pos 0x%" PRIx64 "!", start_pos);
176
0
        return false;
177
0
    }
178
0
    ws_buffer_append(&params->rec->data, tmpbuf, (size_t)(sizeof header));
179
0
    g_free(tmpbuf);
180
181
0
    tmpbuf = g_try_malloc0(item_header.length);
182
0
    if (tmpbuf == NULL) {
183
0
        *err = ENOMEM;  /* we assume we're out of memory */
184
0
        return false;
185
0
    }
186
187
0
    if (!wtap_read_bytes_or_eof(params->fh, tmpbuf, item_header.length, err, err_info)) {
188
0
        g_free(tmpbuf);
189
0
        *err = WTAP_ERR_BAD_FILE;
190
0
        g_free(*err_info);
191
0
        *err_info = ws_strdup_printf("AUTOSAR DLT: Capture file cut short! Not enough bytes for item at pos 0x%" PRIx64 "!", start_pos);
192
0
        return false;
193
0
    }
194
0
    ws_buffer_append(&params->rec->data, tmpbuf, (size_t)(item_header.length));
195
0
    g_free(tmpbuf);
196
197
0
    wtap_setup_packet_rec(params->rec, WTAP_ENCAP_AUTOSAR_DLT);
198
0
    params->rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
199
0
    params->rec->presence_flags = WTAP_HAS_TS | WTAP_HAS_CAP_LEN | WTAP_HAS_INTERFACE_ID;
200
0
    params->rec->tsprec = WTAP_TSPREC_USEC;
201
0
    params->rec->ts.secs = header.timestamp_s;
202
0
    params->rec->ts.nsecs = header.timestamp_us * 1000;
203
204
0
    params->rec->rec_header.packet_header.caplen = (uint32_t)(item_header.length + sizeof header);
205
0
    params->rec->rec_header.packet_header.len = (uint32_t)(item_header.length + sizeof header);
206
0
    params->rec->rec_header.packet_header.interface_id = autosar_dlt_lookup_interface(params, header.ecu_id);
207
208
0
    return true;
209
0
}
210
211
0
static bool autosar_dlt_read(wtap *wth, wtap_rec *rec, int *err, char **err_info, int64_t *data_offset) {
212
0
    autosar_dlt_params_t dlt_tmp;
213
214
0
    dlt_tmp.wth = wth;
215
0
    dlt_tmp.fh = wth->fh;
216
0
    dlt_tmp.rec = rec;
217
0
    dlt_tmp.dlt_data = (autosar_dlt_t *)wth->priv;
218
219
0
    *data_offset = file_tell(wth->fh);
220
221
0
    if (!autosar_dlt_read_block(&dlt_tmp, *data_offset, err, err_info)) {
222
0
        ws_debug("couldn't read packet block (data_offset is %" PRId64 ")", *data_offset);
223
0
        return false;
224
0
    }
225
226
0
    return true;
227
0
}
228
229
0
static bool autosar_dlt_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec, int *err, char **err_info) {
230
0
    autosar_dlt_params_t dlt_tmp;
231
232
0
    dlt_tmp.wth = wth;
233
0
    dlt_tmp.fh = wth->random_fh;
234
0
    dlt_tmp.rec = rec;
235
0
    dlt_tmp.dlt_data = (autosar_dlt_t *)wth->priv;
236
237
0
    if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
238
0
        return false;
239
240
0
    if (!autosar_dlt_read_block(&dlt_tmp, seek_off, err, err_info)) {
241
0
        ws_debug("couldn't read packet block (seek_off: %" PRId64 ") (err=%d).", seek_off, *err);
242
0
        return false;
243
0
    }
244
245
0
    return true;
246
0
}
247
248
0
static void autosar_dlt_close(wtap *wth) {
249
0
    autosar_dlt_t *dlt = (autosar_dlt_t *)wth->priv;
250
251
0
    if (dlt != NULL && dlt->ecu_to_iface_ht != NULL) {
252
0
        g_hash_table_destroy(dlt->ecu_to_iface_ht);
253
0
        dlt->ecu_to_iface_ht = NULL;
254
0
    }
255
256
0
    g_free(dlt);
257
0
    wth->priv = NULL;
258
259
0
    return;
260
0
}
261
262
wtap_open_return_val
263
0
autosar_dlt_open(wtap *wth, int *err, char **err_info) {
264
0
    uint8_t magic[4];
265
0
    autosar_dlt_t *dlt;
266
267
0
    ws_debug("opening file");
268
269
0
    if (!wtap_read_bytes_or_eof(wth->fh, &magic, sizeof magic, err, err_info)) {
270
0
        ws_debug("wtap_read_bytes_or_eof() failed, err = %d.", *err);
271
0
        if (*err == 0 || *err == WTAP_ERR_SHORT_READ) {
272
0
            *err = 0;
273
0
            g_free(*err_info);
274
0
            *err_info = NULL;
275
0
            return WTAP_OPEN_NOT_MINE;
276
0
        }
277
0
        return WTAP_OPEN_ERROR;
278
0
    }
279
280
0
    if (memcmp(magic, dlt_magic, sizeof(dlt_magic))) {
281
0
        return WTAP_OPEN_NOT_MINE;
282
0
    }
283
284
0
    if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
285
0
        return WTAP_OPEN_ERROR;
286
0
    }
287
288
0
    dlt = g_new(autosar_dlt_t, 1);
289
0
    dlt->ecu_to_iface_ht = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL);
290
0
    dlt->next_interface_id = 0;
291
292
0
    wth->priv = (void *)dlt;
293
0
    wth->file_encap = WTAP_ENCAP_AUTOSAR_DLT;
294
0
    wth->snapshot_length = 0;
295
0
    wth->file_tsprec = WTAP_TSPREC_UNKNOWN;
296
0
    wth->subtype_read = autosar_dlt_read;
297
0
    wth->subtype_seek_read = autosar_dlt_seek_read;
298
0
    wth->subtype_close = autosar_dlt_close;
299
0
    wth->file_type_subtype = autosar_dlt_file_type_subtype;
300
301
0
    return WTAP_OPEN_MINE;
302
0
}
303
304
/* Options for interface blocks. */
305
static const struct supported_option_type interface_block_options_supported[] = {
306
    /* No comments, just an interface name. */
307
    { OPT_IDB_NAME, ONE_OPTION_SUPPORTED }
308
};
309
310
static const struct supported_block_type dlt_blocks_supported[] = {
311
    { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED },
312
    { WTAP_BLOCK_IF_ID_AND_INFO, MULTIPLE_BLOCKS_SUPPORTED, OPTION_TYPES_SUPPORTED(interface_block_options_supported) },
313
};
314
315
static const struct file_type_subtype_info dlt_info = {
316
        "AUTOSAR DLT Logfile", "dlt", "dlt", NULL,
317
        false, BLOCKS_SUPPORTED(dlt_blocks_supported),
318
        NULL, NULL, NULL
319
};
320
321
void register_autosar_dlt(void)
322
15
{
323
15
    autosar_dlt_file_type_subtype = wtap_register_file_type_subtype(&dlt_info);
324
325
    /*
326
     * Register name for backwards compatibility with the
327
     * wtap_filetypes table in Lua.
328
     */
329
15
    wtap_register_backwards_compatibility_lua_name("DLT", autosar_dlt_file_type_subtype);
330
15
}
331
332
333
 /*
334
  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
335
  *
336
  * Local variables:
337
  * c-basic-offset: 4
338
  * tab-width: 8
339
  * indent-tabs-mode: nil
340
  * End:
341
  *
342
  * vi: set shiftwidth=4 tabstop=8 expandtab:
343
  * :indentSize=4:tabSize=8:noTabs=true:
344
  */