dcerpc-netlogon: improve NetrLogonGetCapabilities dissection
[wireshark-sm.git] / wiretap / autosar_dlt.c
blob721da3c7c75eb129d56b9dd8e4c21d3ba67f73c1
1 /* autosar_dlt.c
3 * Wiretap Library
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
19 #include <config.h>
21 #define WS_LOG_DOMAIN LOG_DOMAIN_WIRETAP
23 #include <errno.h>
24 #include "autosar_dlt.h"
26 #include "file_wrappers.h"
27 #include "wtap-int.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 {
41 uint8_t magic[4];
42 uint32_t timestamp_s;
43 uint32_t timestamp_us;
44 uint8_t ecu_id[4];
45 } autosar_dlt_blockheader_t;
47 typedef struct autosar_dlt_itemheader {
48 uint8_t header_type;
49 uint8_t counter;
50 uint16_t length;
51 } autosar_dlt_itemheader_t;
54 typedef struct autosar_dlt_data {
55 GHashTable *ecu_to_iface_ht;
56 uint32_t next_interface_id;
57 } autosar_dlt_t;
59 typedef struct autosar_dlt_params {
60 wtap *wth;
61 wtap_rec *rec;
62 Buffer *buf;
63 FILE_T fh;
65 autosar_dlt_t *dlt_data;
66 } autosar_dlt_params_t;
68 static int
69 autosar_dlt_calc_key(uint8_t ecu[4]) {
70 return (int)(ecu[0] << 24 | ecu[1] << 16 | ecu[2] << 8 | ecu[3]);
73 static uint32_t
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;
90 } else {
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));
100 return iface_id;
103 static uint32_t
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) {
108 return 0;
111 void *iface = NULL;
112 bool found = g_hash_table_lookup_extended(params->dlt_data->ecu_to_iface_ht, GINT_TO_POINTER(key), NULL, &iface);
114 if (found) {
115 return GPOINTER_TO_UINT(iface);
116 } else {
117 return autosar_dlt_add_interface(params, ecu);
121 static void
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);
127 static void
128 fix_endianness_autosar_dlt_itemheader(autosar_dlt_itemheader_t *header) {
129 header->length = GUINT16_FROM_BE(header->length);
132 static bool
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;
137 while (1) {
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;
143 g_free(*err_info);
144 *err_info = ws_strdup_printf("AUTOSAR DLT: Capture file cut short! Cannot find storage header at pos 0x%" PRIx64 "!", start_pos);
146 return false;
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);
154 return false;
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;
162 g_free(*err_info);
163 *err_info = ws_strdup_printf("AUTOSAR DLT: Capture file cut short! Not enough bytes for item header at pos 0x%" PRIx64 "!", start_pos);
164 return false;
167 fix_endianness_autosar_dlt_itemheader(&item_header);
169 if (file_seek(params->fh, current_start_of_item, SEEK_SET, err) < 0) {
170 return false;
173 ws_buffer_assure_space(params->buf, (size_t)(item_header.length + sizeof header));
175 /* Creating AUTOSAR DLT Encapsulation Header:
176 * uint32_t time_s
177 * uint32_t time_us
178 * uint8_t[4] ecuname
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;
186 g_free(*err_info);
187 *err_info = ws_strdup_printf("AUTOSAR DLT: Internal Error! Not enough bytes for storage header at pos 0x%" PRIx64 "!", start_pos);
188 return false;
190 ws_buffer_append(params->buf, tmpbuf, (size_t)(sizeof header));
191 g_free(tmpbuf);
193 tmpbuf = g_try_malloc0(item_header.length);
194 if (tmpbuf == NULL) {
195 *err = ENOMEM; /* we assume we're out of memory */
196 return false;
199 if (!wtap_read_bytes_or_eof(params->fh, tmpbuf, item_header.length, err, err_info)) {
200 *err = WTAP_ERR_BAD_FILE;
201 g_free(*err_info);
202 *err_info = ws_strdup_printf("AUTOSAR DLT: Capture file cut short! Not enough bytes for item at pos 0x%" PRIx64 "!", start_pos);
203 return false;
205 ws_buffer_append(params->buf, tmpbuf, (size_t)(item_header.length));
206 g_free(tmpbuf);
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);
220 return true;
223 return false;
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;
229 dlt_tmp.wth = wth;
230 dlt_tmp.fh = wth->fh;
231 dlt_tmp.rec = rec;
232 dlt_tmp.buf = buf;
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);
239 return false;
242 return true;
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;
248 dlt_tmp.wth = wth;
249 dlt_tmp.fh = wth->random_fh;
250 dlt_tmp.rec = rec;
251 dlt_tmp.buf = buf;
252 dlt_tmp.dlt_data = (autosar_dlt_t *)wth->priv;
254 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
255 return false;
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);
259 return false;
262 return true;
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;
273 g_free(dlt);
274 wth->priv = NULL;
276 return;
279 wtap_open_return_val
280 autosar_dlt_open(wtap *wth, int *err, char **err_info) {
281 uint8_t magic[4];
282 autosar_dlt_t *dlt;
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) {
289 *err = 0;
290 g_free(*err_info);
291 *err_info = NULL;
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),
333 NULL, NULL, NULL
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
351 * Local variables:
352 * c-basic-offset: 4
353 * tab-width: 8
354 * indent-tabs-mode: nil
355 * End:
357 * vi: set shiftwidth=4 tabstop=8 expandtab:
358 * :indentSize=4:tabSize=8:noTabs=true: