2019-06-27 18:19:53 +00:00
|
|
|
/* candump.c
|
|
|
|
*
|
|
|
|
* Wiretap Library
|
|
|
|
* Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
|
|
|
|
*
|
|
|
|
* Support for candump log file format
|
|
|
|
* Copyright (c) 2019 by Maksim Salau <maksim.salau@gmail.com>
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
#include <wtap-int.h>
|
|
|
|
#include <file_wrappers.h>
|
2021-08-20 09:17:14 +00:00
|
|
|
#include <wsutil/exported_pdu_tlvs.h>
|
2019-06-27 18:19:53 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <inttypes.h>
|
2019-07-18 18:20:03 +00:00
|
|
|
#include <errno.h>
|
2019-06-27 18:19:53 +00:00
|
|
|
#include "candump.h"
|
|
|
|
#include "candump_priv.h"
|
|
|
|
|
|
|
|
static gboolean candump_read(wtap *wth, wtap_rec *rec, Buffer *buf,
|
|
|
|
int *err, gchar **err_info,
|
|
|
|
gint64 *data_offset);
|
|
|
|
static gboolean candump_seek_read(wtap *wth, gint64 seek_off,
|
|
|
|
wtap_rec *rec, Buffer *buf,
|
|
|
|
int *err, gchar **err_info);
|
|
|
|
|
2021-02-18 06:26:02 +00:00
|
|
|
static int candump_file_type_subtype = -1;
|
|
|
|
|
|
|
|
void register_candump(void);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is written by the candump utility on Linux.
|
|
|
|
*/
|
|
|
|
|
2019-07-18 18:20:03 +00:00
|
|
|
static void
|
|
|
|
candump_write_packet(wtap_rec *rec, Buffer *buf, const msg_t *msg)
|
2019-06-27 18:19:53 +00:00
|
|
|
{
|
|
|
|
static const char *can_proto_name = "can-hostendian";
|
|
|
|
static const char *canfd_proto_name = "canfd";
|
|
|
|
const char *proto_name = msg->is_fd ? canfd_proto_name : can_proto_name;
|
|
|
|
guint proto_name_length = (guint)strlen(proto_name) + 1;
|
|
|
|
guint header_length;
|
|
|
|
guint packet_length;
|
|
|
|
guint frame_length;
|
2019-07-18 18:20:03 +00:00
|
|
|
guint8 *buf_data;
|
2019-06-27 18:19:53 +00:00
|
|
|
|
|
|
|
/* Adjust proto name length to be aligned on 4 byte boundary */
|
|
|
|
proto_name_length += (proto_name_length % 4) ? (4 - (proto_name_length % 4)) : 0;
|
|
|
|
|
|
|
|
header_length = 4 + proto_name_length + 4;
|
|
|
|
frame_length = msg->is_fd ? sizeof(canfd_frame_t) : sizeof(can_frame_t);
|
|
|
|
packet_length = header_length + frame_length;
|
|
|
|
|
2019-07-18 18:20:03 +00:00
|
|
|
ws_buffer_clean(buf);
|
|
|
|
ws_buffer_assure_space(buf, packet_length);
|
|
|
|
buf_data = ws_buffer_start_ptr(buf);
|
|
|
|
|
|
|
|
memset(buf_data, 0, packet_length);
|
|
|
|
|
2021-08-20 07:35:33 +00:00
|
|
|
phton16(buf_data + 0, EXP_PDU_TAG_PROTO_NAME);
|
|
|
|
phton16(buf_data + 2, proto_name_length);
|
2019-07-18 18:20:03 +00:00
|
|
|
memcpy(buf_data + 4, proto_name, strlen(proto_name));
|
2019-06-27 18:19:53 +00:00
|
|
|
|
|
|
|
if (msg->is_fd)
|
|
|
|
{
|
2020-04-13 21:39:32 +00:00
|
|
|
canfd_frame_t canfd_frame = {0};
|
2019-06-27 18:19:53 +00:00
|
|
|
|
|
|
|
canfd_frame.can_id = msg->id;
|
|
|
|
canfd_frame.flags = msg->flags;
|
|
|
|
canfd_frame.len = msg->data.length;
|
|
|
|
memcpy(canfd_frame.data, msg->data.data, msg->data.length);
|
|
|
|
|
2019-07-18 18:20:03 +00:00
|
|
|
memcpy(buf_data + header_length, (guint8 *)&canfd_frame, sizeof(canfd_frame));
|
2019-06-27 18:19:53 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-04-13 21:39:32 +00:00
|
|
|
can_frame_t can_frame = {0};
|
2019-06-27 18:19:53 +00:00
|
|
|
|
|
|
|
can_frame.can_id = msg->id;
|
|
|
|
can_frame.can_dlc = msg->data.length;
|
|
|
|
memcpy(can_frame.data, msg->data.data, msg->data.length);
|
|
|
|
|
2019-07-18 18:20:03 +00:00
|
|
|
memcpy(buf_data + header_length, (guint8 *)&can_frame, sizeof(can_frame));
|
2019-06-27 18:19:53 +00:00
|
|
|
}
|
|
|
|
|
2019-07-18 18:20:03 +00:00
|
|
|
rec->rec_type = REC_TYPE_PACKET;
|
2021-08-30 02:12:13 +00:00
|
|
|
rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
|
2019-07-18 18:20:03 +00:00
|
|
|
rec->presence_flags = WTAP_HAS_TS;
|
|
|
|
rec->ts = msg->ts;
|
|
|
|
rec->tsprec = WTAP_TSPREC_USEC;
|
2019-06-27 18:19:53 +00:00
|
|
|
|
2019-07-18 18:20:03 +00:00
|
|
|
rec->rec_header.packet_header.caplen = packet_length;
|
|
|
|
rec->rec_header.packet_header.len = packet_length;
|
2019-06-27 18:19:53 +00:00
|
|
|
}
|
|
|
|
|
2019-07-18 18:20:03 +00:00
|
|
|
static gboolean
|
|
|
|
candump_parse(FILE_T fh, msg_t *msg, gint64 *offset, int *err, char **err_info)
|
2019-06-27 18:19:53 +00:00
|
|
|
{
|
2020-04-13 21:39:32 +00:00
|
|
|
candump_state_t state = {0};
|
2019-07-18 18:20:03 +00:00
|
|
|
gboolean ok;
|
|
|
|
gint64 seek_off;
|
2019-06-27 18:19:53 +00:00
|
|
|
|
2019-07-12 12:54:40 +00:00
|
|
|
#ifdef CANDUMP_DEBUG
|
2021-02-27 03:38:15 +00:00
|
|
|
candump_debug_printf("%s: Trying candump file decoder\n", G_STRFUNC);
|
2019-07-12 12:54:40 +00:00
|
|
|
#endif
|
2019-06-27 18:19:53 +00:00
|
|
|
|
2019-07-18 18:20:03 +00:00
|
|
|
state.fh = fh;
|
2019-06-27 18:19:53 +00:00
|
|
|
|
2019-07-18 18:20:03 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
if (file_eof(fh))
|
|
|
|
return FALSE;
|
2019-06-27 18:19:53 +00:00
|
|
|
|
2019-07-18 18:20:03 +00:00
|
|
|
seek_off = file_tell(fh);
|
2019-07-12 12:54:40 +00:00
|
|
|
#ifdef CANDUMP_DEBUG
|
2021-02-27 03:38:15 +00:00
|
|
|
candump_debug_printf("%s: Starting parser at offset %" PRIi64 "\n", G_STRFUNC, seek_off);
|
2019-07-12 12:54:40 +00:00
|
|
|
#endif
|
2019-07-18 18:20:03 +00:00
|
|
|
state.file_bytes_read = 0;
|
|
|
|
ok = run_candump_parser(&state, err, err_info);
|
|
|
|
|
|
|
|
/* Rewind the file to the offset we have finished parsing */
|
|
|
|
if (file_seek(fh, seek_off + state.file_bytes_read, SEEK_SET, err) == -1)
|
|
|
|
{
|
|
|
|
g_free(*err_info);
|
|
|
|
*err = errno;
|
|
|
|
*err_info = g_strdup(g_strerror(errno));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (ok && !state.is_msg_valid);
|
2019-06-27 18:19:53 +00:00
|
|
|
|
2019-07-18 18:20:03 +00:00
|
|
|
if (!ok)
|
|
|
|
return FALSE;
|
2019-06-27 18:19:53 +00:00
|
|
|
|
2019-07-12 12:54:40 +00:00
|
|
|
#ifdef CANDUMP_DEBUG
|
2021-02-27 03:38:15 +00:00
|
|
|
candump_debug_printf("%s: Success\n", G_STRFUNC);
|
2019-07-12 12:54:40 +00:00
|
|
|
#endif
|
2019-06-27 18:19:53 +00:00
|
|
|
|
2019-07-18 18:20:03 +00:00
|
|
|
if (offset)
|
|
|
|
*offset = seek_off;
|
|
|
|
|
|
|
|
if (msg)
|
|
|
|
*msg = state.msg;
|
|
|
|
|
|
|
|
return TRUE;
|
2019-06-27 18:19:53 +00:00
|
|
|
}
|
|
|
|
|
2019-07-18 18:20:03 +00:00
|
|
|
wtap_open_return_val
|
|
|
|
candump_open(wtap *wth, int *err, char **err_info)
|
2019-06-27 18:19:53 +00:00
|
|
|
{
|
2019-07-18 18:20:03 +00:00
|
|
|
if (!candump_parse(wth->fh, NULL, NULL, err, err_info))
|
|
|
|
{
|
|
|
|
g_free(*err_info);
|
2019-06-27 18:19:53 +00:00
|
|
|
|
2019-07-18 18:20:03 +00:00
|
|
|
*err = 0;
|
|
|
|
*err_info = NULL;
|
2019-06-27 18:19:53 +00:00
|
|
|
|
|
|
|
return WTAP_OPEN_NOT_MINE;
|
|
|
|
}
|
|
|
|
|
2019-07-12 12:54:40 +00:00
|
|
|
#ifdef CANDUMP_DEBUG
|
2021-02-27 03:38:15 +00:00
|
|
|
candump_debug_printf("%s: This is our file\n", G_STRFUNC);
|
2019-07-12 12:54:40 +00:00
|
|
|
#endif
|
2019-06-27 18:19:53 +00:00
|
|
|
|
2019-07-18 18:20:03 +00:00
|
|
|
if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
|
2019-06-27 18:19:53 +00:00
|
|
|
{
|
2019-07-18 18:20:03 +00:00
|
|
|
*err = errno;
|
|
|
|
*err_info = g_strdup(g_strerror(errno));
|
2019-06-27 18:19:53 +00:00
|
|
|
|
|
|
|
return WTAP_OPEN_ERROR;
|
2019-07-18 18:20:03 +00:00
|
|
|
}
|
2019-06-27 18:19:53 +00:00
|
|
|
|
2019-07-18 18:20:03 +00:00
|
|
|
wth->priv = NULL;
|
2021-02-18 06:26:02 +00:00
|
|
|
wth->file_type_subtype = candump_file_type_subtype;
|
2019-07-18 18:20:03 +00:00
|
|
|
wth->file_encap = WTAP_ENCAP_WIRESHARK_UPPER_PDU;
|
|
|
|
wth->file_tsprec = WTAP_TSPREC_USEC;
|
2019-06-27 18:19:53 +00:00
|
|
|
wth->subtype_read = candump_read;
|
|
|
|
wth->subtype_seek_read = candump_seek_read;
|
|
|
|
|
|
|
|
return WTAP_OPEN_MINE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
candump_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err, gchar **err_info,
|
|
|
|
gint64 *data_offset)
|
|
|
|
{
|
2019-07-18 18:20:03 +00:00
|
|
|
msg_t msg;
|
2019-06-27 18:19:53 +00:00
|
|
|
|
2019-07-18 18:20:03 +00:00
|
|
|
#ifdef CANDUMP_DEBUG
|
2021-02-27 03:38:15 +00:00
|
|
|
candump_debug_printf("%s: Try reading at offset %" PRIi64 "\n", G_STRFUNC, file_tell(wth->fh));
|
2019-07-18 18:20:03 +00:00
|
|
|
#endif
|
2019-06-27 18:19:53 +00:00
|
|
|
|
2019-07-18 18:20:03 +00:00
|
|
|
if (!candump_parse(wth->fh, &msg, data_offset, err, err_info))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
#ifdef CANDUMP_DEBUG
|
2021-02-27 03:38:15 +00:00
|
|
|
candump_debug_printf("%s: Stopped at offset %" PRIi64 "\n", G_STRFUNC, file_tell(wth->fh));
|
2019-07-18 18:20:03 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
candump_write_packet(rec, buf, &msg);
|
|
|
|
|
|
|
|
return TRUE;
|
2019-06-27 18:19:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
candump_seek_read(wtap *wth , gint64 seek_off, wtap_rec *rec,
|
|
|
|
Buffer *buf, int *err, gchar **err_info)
|
|
|
|
{
|
2019-07-18 18:20:03 +00:00
|
|
|
msg_t msg;
|
2019-06-27 18:19:53 +00:00
|
|
|
|
2019-07-18 18:20:03 +00:00
|
|
|
#ifdef CANDUMP_DEBUG
|
2021-02-27 03:38:15 +00:00
|
|
|
candump_debug_printf("%s: Read at offset %" PRIi64 "\n", G_STRFUNC, seek_off);
|
2019-07-18 18:20:03 +00:00
|
|
|
#endif
|
2019-06-27 18:19:53 +00:00
|
|
|
|
2019-07-18 18:20:03 +00:00
|
|
|
if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
|
|
|
|
{
|
|
|
|
*err = errno;
|
|
|
|
*err_info = g_strdup(g_strerror(errno));
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!candump_parse(wth->random_fh, &msg, NULL, err, err_info))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
candump_write_packet(rec, buf, &msg);
|
2019-06-27 18:19:53 +00:00
|
|
|
|
2019-07-18 18:20:03 +00:00
|
|
|
return TRUE;
|
2019-06-27 18:19:53 +00:00
|
|
|
}
|
|
|
|
|
wiretap: have file handlers advertise blocks and options supported.
Instead of a "supports name resolution" Boolean and bitflags for types of
comments supported, provide a list of block types that the file
type/subtype supports, with each block type having a list of options
supported. Indicate whether "supported" means "one instance" or
"multiple instances".
"Supports" doesn't just mean "can be written", it also means "could be
read".
Rename WTAP_BLOCK_IF_DESCRIPTION to WTAP_BLOCK_IF_ID_AND_INFO, to
indicate that it provides, in addition to information about the
interface, an ID (implicitly, in pcapng files, by its ordinal number)
that is associated with every packet in the file. Emphasize that in
comments - just because your capture file format can list the interfaces
on which a capture was done, that doesn't mean it supports this; it
doesn't do so if the file doesn't indicate, for every packet, on which
of those interfaces it was captured (I'm looking at *you*, Microsoft
Network Monitor...).
Use APIs to query that information to do what the "does this file
type/subtype support name resolution information", "does this file
type/subtype support all of these comment types", and "does this file
type/subtype support - and require - interface IDs" APIs did.
Provide backwards compatibility for Lua.
This allows us to eliminate the WTAP_FILE_TYPE_SUBTYPE_ values for IBM's
iptrace; do so.
2021-02-21 22:18:04 +00:00
|
|
|
static const struct supported_block_type candump_blocks_supported[] = {
|
|
|
|
/*
|
|
|
|
* We support packet blocks, with no comments or other options.
|
|
|
|
*/
|
|
|
|
{ WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
|
|
|
|
};
|
|
|
|
|
2021-02-18 06:26:02 +00:00
|
|
|
static const struct file_type_subtype_info candump_info = {
|
|
|
|
"Linux candump file", "candump", NULL, NULL,
|
wiretap: have file handlers advertise blocks and options supported.
Instead of a "supports name resolution" Boolean and bitflags for types of
comments supported, provide a list of block types that the file
type/subtype supports, with each block type having a list of options
supported. Indicate whether "supported" means "one instance" or
"multiple instances".
"Supports" doesn't just mean "can be written", it also means "could be
read".
Rename WTAP_BLOCK_IF_DESCRIPTION to WTAP_BLOCK_IF_ID_AND_INFO, to
indicate that it provides, in addition to information about the
interface, an ID (implicitly, in pcapng files, by its ordinal number)
that is associated with every packet in the file. Emphasize that in
comments - just because your capture file format can list the interfaces
on which a capture was done, that doesn't mean it supports this; it
doesn't do so if the file doesn't indicate, for every packet, on which
of those interfaces it was captured (I'm looking at *you*, Microsoft
Network Monitor...).
Use APIs to query that information to do what the "does this file
type/subtype support name resolution information", "does this file
type/subtype support all of these comment types", and "does this file
type/subtype support - and require - interface IDs" APIs did.
Provide backwards compatibility for Lua.
This allows us to eliminate the WTAP_FILE_TYPE_SUBTYPE_ values for IBM's
iptrace; do so.
2021-02-21 22:18:04 +00:00
|
|
|
FALSE, BLOCKS_SUPPORTED(candump_blocks_supported),
|
2021-02-18 06:26:02 +00:00
|
|
|
NULL, NULL, NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
void register_candump(void)
|
|
|
|
{
|
2021-02-24 03:10:35 +00:00
|
|
|
candump_file_type_subtype = wtap_register_file_type_subtype(&candump_info);
|
2021-02-18 06:26:02 +00:00
|
|
|
}
|
|
|
|
|
2019-06-27 18:19:53 +00:00
|
|
|
/*
|
2019-07-26 18:43:17 +00:00
|
|
|
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
2019-06-27 18:19:53 +00:00
|
|
|
*
|
|
|
|
* Local variables:
|
|
|
|
* c-basic-offset: 4
|
|
|
|
* tab-width: 8
|
|
|
|
* indent-tabs-mode: nil
|
|
|
|
* End:
|
|
|
|
*
|
|
|
|
* vi: set shiftwidth=4 tabstop=8 expandtab:
|
|
|
|
* :indentSize=4:tabSize=8:noTabs=true:
|
|
|
|
*/
|