4 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
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>
9 * SPDX-License-Identifier: GPL-2.0-or-later
13 * Sources for specification:
14 * https://www.autosar.org/fileadmin/user_upload/standards/classic/21-11/AUTOSAR_SWS_DiagnosticLogAndTrace.pdf
15 * https://www.autosar.org/fileadmin/user_upload/standards/foundation/21-11/AUTOSAR_PRS_LogAndTraceProtocol.pdf
16 * https://github.com/COVESA/dlt-viewer
21 #define WS_LOG_DOMAIN LOG_DOMAIN_WIRETAP
24 #include "autosar_dlt.h"
26 #include "file_wrappers.h"
29 static const uint8_t dlt_magic
[] = { 'D', 'L', 'T', 0x01 };
31 static int autosar_dlt_file_type_subtype
= -1;
34 void register_autosar_dlt(void);
35 static bool autosar_dlt_read(wtap
*wth
, wtap_rec
*rec
, Buffer
*buf
, int *err
, char **err_info
, int64_t *data_offset
);
36 static bool autosar_dlt_seek_read(wtap
*wth
, int64_t seek_off
, wtap_rec
* rec
, Buffer
*buf
, int *err
, char **err_info
);
37 static void autosar_dlt_close(wtap
*wth
);
40 typedef struct autosar_dlt_blockheader
{
43 uint32_t timestamp_us
;
45 } autosar_dlt_blockheader_t
;
47 typedef struct autosar_dlt_itemheader
{
51 } autosar_dlt_itemheader_t
;
54 typedef struct autosar_dlt_data
{
55 GHashTable
*ecu_to_iface_ht
;
56 uint32_t next_interface_id
;
59 typedef struct autosar_dlt_params
{
65 autosar_dlt_t
*dlt_data
;
66 } autosar_dlt_params_t
;
69 autosar_dlt_calc_key(uint8_t ecu
[4]) {
70 return (int)(ecu
[0] << 24 | ecu
[1] << 16 | ecu
[2] << 8 | ecu
[3]);
74 autosar_dlt_add_interface(autosar_dlt_params_t
*params
, uint8_t ecu
[4]) {
75 wtap_block_t int_data
= wtap_block_create(WTAP_BLOCK_IF_ID_AND_INFO
);
76 wtapng_if_descr_mandatory_t
*if_descr_mand
= (wtapng_if_descr_mandatory_t
*)wtap_block_get_mandatory_data(int_data
);
78 if_descr_mand
->wtap_encap
= WTAP_ENCAP_AUTOSAR_DLT
;
79 wtap_block_add_string_option(int_data
, OPT_IDB_NAME
, (char *)ecu
, 4);
80 if_descr_mand
->time_units_per_second
= 1000 * 1000 * 1000;
81 if_descr_mand
->tsprecision
= WTAP_TSPREC_NSEC
;
82 wtap_block_add_uint8_option(int_data
, OPT_IDB_TSRESOL
, 9);
83 if_descr_mand
->snap_len
= WTAP_MAX_PACKET_SIZE_STANDARD
;
84 if_descr_mand
->num_stat_entries
= 0;
85 if_descr_mand
->interface_statistics
= NULL
;
86 wtap_add_idb(params
->wth
, int_data
);
88 if (params
->wth
->file_encap
== WTAP_ENCAP_UNKNOWN
) {
89 params
->wth
->file_encap
= if_descr_mand
->wtap_encap
;
91 if (params
->wth
->file_encap
!= if_descr_mand
->wtap_encap
) {
92 params
->wth
->file_encap
= WTAP_ENCAP_PER_PACKET
;
96 int32_t key
= autosar_dlt_calc_key(ecu
);
97 uint32_t iface_id
= params
->dlt_data
->next_interface_id
++;
98 g_hash_table_insert(params
->dlt_data
->ecu_to_iface_ht
, GINT_TO_POINTER(key
), GUINT_TO_POINTER(iface_id
));
104 autosar_dlt_lookup_interface(autosar_dlt_params_t
*params
, uint8_t ecu
[4]) {
105 int32_t key
= autosar_dlt_calc_key(ecu
);
107 if (params
->dlt_data
->ecu_to_iface_ht
== NULL
) {
112 bool found
= g_hash_table_lookup_extended(params
->dlt_data
->ecu_to_iface_ht
, GINT_TO_POINTER(key
), NULL
, &iface
);
115 return GPOINTER_TO_UINT(iface
);
117 return autosar_dlt_add_interface(params
, ecu
);
122 fix_endianness_autosar_dlt_blockheader(autosar_dlt_blockheader_t
*header
) {
123 header
->timestamp_s
= GUINT32_FROM_LE(header
->timestamp_s
);
124 header
->timestamp_us
= GUINT32_FROM_LE(header
->timestamp_us
);
128 fix_endianness_autosar_dlt_itemheader(autosar_dlt_itemheader_t
*header
) {
129 header
->length
= GUINT16_FROM_BE(header
->length
);
133 autosar_dlt_read_block(autosar_dlt_params_t
*params
, int64_t start_pos
, int *err
, char **err_info
) {
134 autosar_dlt_blockheader_t header
;
135 autosar_dlt_itemheader_t item_header
;
138 params
->buf
->first_free
= params
->buf
->start
;
140 if (!wtap_read_bytes_or_eof(params
->fh
, &header
, sizeof header
, err
, err_info
)) {
141 if (*err
== WTAP_ERR_SHORT_READ
) {
142 *err
= WTAP_ERR_BAD_FILE
;
144 *err_info
= ws_strdup_printf("AUTOSAR DLT: Capture file cut short! Cannot find storage header at pos 0x%" PRIx64
"!", start_pos
);
149 fix_endianness_autosar_dlt_blockheader(&header
);
151 if (memcmp(header
.magic
, dlt_magic
, sizeof(dlt_magic
))) {
152 *err
= WTAP_ERR_BAD_FILE
;
153 *err_info
= ws_strdup_printf("AUTOSAR DLT: Bad capture file! Object magic is not DLT\\x01 at pos 0x%" PRIx64
"!", start_pos
);
157 /* Set to the byte after the magic. */
158 uint64_t current_start_of_item
= file_tell(params
->fh
) - sizeof header
+ 4;
160 if (!wtap_read_bytes_or_eof(params
->fh
, &item_header
, sizeof item_header
, err
, err_info
)) {
161 *err
= WTAP_ERR_BAD_FILE
;
163 *err_info
= ws_strdup_printf("AUTOSAR DLT: Capture file cut short! Not enough bytes for item header at pos 0x%" PRIx64
"!", start_pos
);
167 fix_endianness_autosar_dlt_itemheader(&item_header
);
169 if (file_seek(params
->fh
, current_start_of_item
, SEEK_SET
, err
) < 0) {
173 ws_buffer_assure_space(params
->buf
, (size_t)(item_header
.length
+ sizeof header
));
175 /* Creating AUTOSAR DLT Encapsulation Header:
179 * uint8_t[1] 0x00 (termination)
180 * uint8_t[3] reserved
182 void *tmpbuf
= g_malloc0(sizeof header
);
183 if (!wtap_read_bytes_or_eof(params
->fh
, tmpbuf
, sizeof header
- 4, err
, err_info
)) {
184 /* this would have been caught before ...*/
185 *err
= WTAP_ERR_BAD_FILE
;
187 *err_info
= ws_strdup_printf("AUTOSAR DLT: Internal Error! Not enough bytes for storage header at pos 0x%" PRIx64
"!", start_pos
);
190 ws_buffer_append(params
->buf
, tmpbuf
, (size_t)(sizeof header
));
193 tmpbuf
= g_try_malloc0(item_header
.length
);
194 if (tmpbuf
== NULL
) {
195 *err
= ENOMEM
; /* we assume we're out of memory */
199 if (!wtap_read_bytes_or_eof(params
->fh
, tmpbuf
, item_header
.length
, err
, err_info
)) {
200 *err
= WTAP_ERR_BAD_FILE
;
202 *err_info
= ws_strdup_printf("AUTOSAR DLT: Capture file cut short! Not enough bytes for item at pos 0x%" PRIx64
"!", start_pos
);
205 ws_buffer_append(params
->buf
, tmpbuf
, (size_t)(item_header
.length
));
208 params
->rec
->rec_type
= REC_TYPE_PACKET
;
209 params
->rec
->block
= wtap_block_create(WTAP_BLOCK_PACKET
);
210 params
->rec
->presence_flags
= WTAP_HAS_TS
| WTAP_HAS_CAP_LEN
| WTAP_HAS_INTERFACE_ID
;
211 params
->rec
->tsprec
= WTAP_TSPREC_USEC
;
212 params
->rec
->ts
.secs
= header
.timestamp_s
;
213 params
->rec
->ts
.nsecs
= header
.timestamp_us
* 1000;
215 params
->rec
->rec_header
.packet_header
.caplen
= (uint32_t)(item_header
.length
+ sizeof header
);
216 params
->rec
->rec_header
.packet_header
.len
= (uint32_t)(item_header
.length
+ sizeof header
);
217 params
->rec
->rec_header
.packet_header
.pkt_encap
= WTAP_ENCAP_AUTOSAR_DLT
;
218 params
->rec
->rec_header
.packet_header
.interface_id
= autosar_dlt_lookup_interface(params
, header
.ecu_id
);
226 static bool autosar_dlt_read(wtap
*wth
, wtap_rec
*rec
, Buffer
*buf
, int *err
, char **err_info
, int64_t *data_offset
) {
227 autosar_dlt_params_t dlt_tmp
;
230 dlt_tmp
.fh
= wth
->fh
;
233 dlt_tmp
.dlt_data
= (autosar_dlt_t
*)wth
->priv
;
235 *data_offset
= file_tell(wth
->fh
);
237 if (!autosar_dlt_read_block(&dlt_tmp
, *data_offset
, err
, err_info
)) {
238 ws_debug("couldn't read packet block (data_offset is %" PRId64
")", *data_offset
);
245 static bool autosar_dlt_seek_read(wtap
*wth
, int64_t seek_off
, wtap_rec
*rec
, Buffer
*buf
, int *err
, char **err_info
) {
246 autosar_dlt_params_t dlt_tmp
;
249 dlt_tmp
.fh
= wth
->random_fh
;
252 dlt_tmp
.dlt_data
= (autosar_dlt_t
*)wth
->priv
;
254 if (file_seek(wth
->random_fh
, seek_off
, SEEK_SET
, err
) == -1)
257 if (!autosar_dlt_read_block(&dlt_tmp
, seek_off
, err
, err_info
)) {
258 ws_debug("couldn't read packet block (seek_off: %" PRId64
") (err=%d).", seek_off
, *err
);
265 static void autosar_dlt_close(wtap
*wth
) {
266 autosar_dlt_t
*dlt
= (autosar_dlt_t
*)wth
->priv
;
268 if (dlt
!= NULL
&& dlt
->ecu_to_iface_ht
!= NULL
) {
269 g_hash_table_destroy(dlt
->ecu_to_iface_ht
);
270 dlt
->ecu_to_iface_ht
= NULL
;
280 autosar_dlt_open(wtap
*wth
, int *err
, char **err_info
) {
284 ws_debug("opening file");
286 if (!wtap_read_bytes_or_eof(wth
->fh
, &magic
, sizeof magic
, err
, err_info
)) {
287 ws_debug("wtap_read_bytes_or_eof() failed, err = %d.", *err
);
288 if (*err
== 0 || *err
== WTAP_ERR_SHORT_READ
) {
292 return WTAP_OPEN_NOT_MINE
;
294 return WTAP_OPEN_ERROR
;
297 if (memcmp(magic
, dlt_magic
, sizeof(dlt_magic
))) {
298 return WTAP_OPEN_NOT_MINE
;
301 file_seek(wth
->fh
, 0, SEEK_SET
, err
);
303 dlt
= g_new(autosar_dlt_t
, 1);
304 dlt
->ecu_to_iface_ht
= g_hash_table_new_full(g_direct_hash
, g_direct_equal
, NULL
, NULL
);
305 dlt
->next_interface_id
= 0;
307 wth
->priv
= (void *)dlt
;
308 wth
->file_encap
= WTAP_ENCAP_UNKNOWN
;
309 wth
->snapshot_length
= 0;
310 wth
->file_tsprec
= WTAP_TSPREC_UNKNOWN
;
311 wth
->subtype_read
= autosar_dlt_read
;
312 wth
->subtype_seek_read
= autosar_dlt_seek_read
;
313 wth
->subtype_close
= autosar_dlt_close
;
314 wth
->file_type_subtype
= autosar_dlt_file_type_subtype
;
316 return WTAP_OPEN_MINE
;
319 /* Options for interface blocks. */
320 static const struct supported_option_type interface_block_options_supported
[] = {
321 /* No comments, just an interface name. */
322 { OPT_IDB_NAME
, ONE_OPTION_SUPPORTED
}
325 static const struct supported_block_type dlt_blocks_supported
[] = {
326 { WTAP_BLOCK_PACKET
, MULTIPLE_BLOCKS_SUPPORTED
, NO_OPTIONS_SUPPORTED
},
327 { WTAP_BLOCK_IF_ID_AND_INFO
, MULTIPLE_BLOCKS_SUPPORTED
, OPTION_TYPES_SUPPORTED(interface_block_options_supported
) },
330 static const struct file_type_subtype_info dlt_info
= {
331 "AUTOSAR DLT Logfile", "dlt", "dlt", NULL
,
332 false, BLOCKS_SUPPORTED(dlt_blocks_supported
),
336 void register_autosar_dlt(void)
338 autosar_dlt_file_type_subtype
= wtap_register_file_type_subtype(&dlt_info
);
341 * Register name for backwards compatibility with the
342 * wtap_filetypes table in Lua.
344 wtap_register_backwards_compatibility_lua_name("DLT", autosar_dlt_file_type_subtype
);
349 * Editor modelines - https://www.wireshark.org/tools/modelines.html
354 * indent-tabs-mode: nil
357 * vi: set shiftwidth=4 tabstop=8 expandtab:
358 * :indentSize=4:tabSize=8:noTabs=true: