/* blf.c * * Wiretap Library * Copyright (c) 1998 by Gilbert Ramirez * * File format support for blf file format * Copyright (c) 2021 by Dr. Lars Voelker * * SPDX-License-Identifier: GPL-2.0-or-later */ /* * The following was used as a reference for the file format: * https://bitbucket.org/tobylorenz/vector_blf * The repo above includes multiple examples files as well. */ #include #include "blf.h" #include #include #include #include "file_wrappers.h" #include "wtap-int.h" #ifdef HAVE_ZLIB #define ZLIB_CONST #include #endif /* HAVE_ZLIB */ static const guint8 blf_magic[] = { 'L', 'O', 'G', 'G' }; static const guint8 blf_obj_magic[] = { 'L', 'O', 'B', 'J' }; static int blf_file_type_subtype = -1; void register_blf(void); static gboolean blf_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err, gchar **err_info, gint64 *data_offset); static gboolean blf_seek_read(wtap *wth, gint64 seek_off, wtap_rec* rec, Buffer *buf, int *err, gchar **err_info); static void blf_close(wtap *wth); /* * The virtual buffer looks like this (skips all headers): * uncompressed log container data * uncompressed log container data * ... * * The "real" positions, length, etc. reference this layout and not the file. * When no compression is used the file is accessed directly. */ typedef struct blf_log_container { gint64 infile_start_pos; /* start position of log container in file */ guint64 infile_length; /* length of log container in file */ guint64 infile_data_start; /* start position of data in log container in file */ gint64 real_start_pos; /* decompressed (virtual) start position including header */ guint64 real_length; /* decompressed length */ gint64 real_first_object_pos; /* where does the first obj start? */ guint64 real_leftover_bytes; /* how many bytes are left over for the next container? */ guint16 compression_method; /* 0: uncompressed, 2: zlib */ unsigned char *real_data; /* cache for decompressed data */ } blf_log_container_t; typedef struct blf_data { gint64 start_of_last_obj; gint64 current_real_seek_pos; guint current_log_container; GArray *log_containers; } blf_t; typedef struct blf_params { wtap *wth; wtap_rec *rec; Buffer *buf; FILE_T fh; blf_t *blf_data; } blf_params_t; gboolean blf_read_block(blf_params_t *params, gint64 start_pos, int *err, gchar **err_info); void fix_endianness_blf_date(blf_date_t *date) { date->year = GUINT16_FROM_LE(date->year); date->month = GUINT16_FROM_LE(date->month); date->dayofweek = GUINT16_FROM_LE(date->dayofweek); date->day = GUINT16_FROM_LE(date->day); date->hour = GUINT16_FROM_LE(date->hour); date->mins = GUINT16_FROM_LE(date->mins); date->sec = GUINT16_FROM_LE(date->sec); date->ms = GUINT16_FROM_LE(date->ms); } void fix_endianness_blf_fileheader(blf_fileheader_t *header) { header->header_length = GUINT32_FROM_LE(header->header_length); header->len_compressed = GUINT64_FROM_LE(header->len_compressed); header->len_uncompressed = GUINT64_FROM_LE(header->len_uncompressed); header->obj_count = GUINT32_FROM_LE(header->obj_count); header->obj_read = GUINT32_FROM_LE(header->obj_read); fix_endianness_blf_date(&(header->start_date)); fix_endianness_blf_date(&(header->end_date)); header->length3 = GUINT32_FROM_LE(header->length3); } void fix_endianness_blf_blockheader(blf_blockheader_t *header) { header->header_length = GUINT16_FROM_LE(header->header_length); header->header_type = GUINT16_FROM_LE(header->header_type); header->object_length = GUINT32_FROM_LE(header->object_length); header->object_type = GUINT32_FROM_LE(header->object_type); } void fix_endianness_blf_logcontainerheader(blf_logcontainerheader_t *header) { header->compression_method = GUINT16_FROM_LE(header->compression_method); header->res1 = GUINT16_FROM_LE(header->res1); header->res2 = GUINT32_FROM_LE(header->res2); header->uncompressed_size = GUINT32_FROM_LE(header->uncompressed_size); header->res4 = GUINT32_FROM_LE(header->res4); } void fix_endianness_blf_logobjectheader(blf_logobjectheader_t *header) { header->flags = GUINT32_FROM_LE(header->flags); header->client_index = GUINT16_FROM_LE(header->client_index); header->object_version = GUINT16_FROM_LE(header->object_version); header->object_timestamp = GUINT64_FROM_LE(header->object_timestamp); } void fix_endianness_blf_ethernetframeheader(blf_ethernetframeheader_t *header) { header->channel = GUINT16_FROM_LE(header->channel); header->direction = GUINT16_FROM_LE(header->direction); header->ethtype = GUINT16_FROM_LE(header->ethtype); header->tpid = GUINT16_FROM_LE(header->tpid); header->tci = GUINT16_FROM_LE(header->tci); header->payloadlength = GUINT16_FROM_LE(header->payloadlength); } void fix_endianness_blf_ethernetframeheader_ex(blf_ethernetframeheader_ex_t *header) { header->struct_length = GUINT16_FROM_LE(header->struct_length); header->flags = GUINT16_FROM_LE(header->flags); header->channel = GUINT16_FROM_LE(header->channel); header->hw_channel = GUINT16_FROM_LE(header->hw_channel); header->frame_duration = GUINT64_FROM_LE(header->frame_duration); header->frame_checksum = GUINT32_FROM_LE(header->frame_checksum); header->direction = GUINT16_FROM_LE(header->direction); header->frame_length = GUINT16_FROM_LE(header->frame_length); header->frame_handle = GUINT32_FROM_LE(header->frame_handle); header->error = GUINT32_FROM_LE(header->error); } void fix_endianness_blf_canmessage(blf_canmessage_t *header) { header->channel = GUINT16_FROM_LE(header->channel); header->id = GUINT32_FROM_LE(header->id); } void fix_endianness_blf_canmessage2_trailer(blf_canmessage2_trailer_t *header) { header->frameLength_in_ns = GUINT32_FROM_LE(header->frameLength_in_ns); header->reserved2 = GUINT16_FROM_LE(header->reserved1); } void fix_endianness_blf_canfdmessage(blf_canfdmessage_t *header) { header->channel = GUINT16_FROM_LE(header->channel); header->id = GUINT32_FROM_LE(header->id); header->frameLength_in_ns = GUINT32_FROM_LE(header->frameLength_in_ns); header->reservedCanFdMessage2 = GUINT32_FROM_LE(header->reservedCanFdMessage2); } void fix_endianness_blf_canfdmessage64(blf_canfdmessage64_t *header) { header->id = GUINT32_FROM_LE(header->id); header->frameLength_in_ns = GUINT32_FROM_LE(header->frameLength_in_ns); header->flags = GUINT32_FROM_LE(header->flags); header->btrCfgArb = GUINT32_FROM_LE(header->btrCfgArb); header->btrCfgData = GUINT32_FROM_LE(header->btrCfgData); header->timeOffsetBrsNs = GUINT32_FROM_LE(header->timeOffsetBrsNs); header->timeOffsetCrcDelNs = GUINT32_FROM_LE(header->timeOffsetCrcDelNs); header->bitCount = GUINT16_FROM_LE(header->bitCount); header->crc = GUINT32_FROM_LE(header->crc); } void fix_endianness_blf_flexraydata(blf_flexraydata_t *header) { header->channel = GUINT16_FROM_LE(header->channel); header->messageId = GUINT16_FROM_LE(header->messageId); header->crc = GUINT16_FROM_LE(header->crc); header->reservedFlexRayData2 = GUINT16_FROM_LE(header->reservedFlexRayData2); } void fix_endianness_blf_flexraymessage(blf_flexraymessage_t *header) { header->channel = GUINT16_FROM_LE(header->channel); header->fpgaTick = GUINT32_FROM_LE(header->fpgaTick); header->fpgaTickOverflow = GUINT32_FROM_LE(header->fpgaTickOverflow); header->clientIndexFlexRayV6Message = GUINT32_FROM_LE(header->clientIndexFlexRayV6Message); header->clusterTime = GUINT32_FROM_LE(header->clusterTime); header->frameId = GUINT16_FROM_LE(header->frameId); header->headerCrc = GUINT16_FROM_LE(header->headerCrc); header->frameState = GUINT16_FROM_LE(header->frameState); header->reservedFlexRayV6Message2 = GUINT16_FROM_LE(header->reservedFlexRayV6Message2); } void fix_endianness_blf_flexrayrcvmessage(blf_flexrayrcvmessage_t *header) { header->channel = GUINT16_FROM_LE(header->channel); header->version = GUINT16_FROM_LE(header->version); header->channelMask = GUINT16_FROM_LE(header->channelMask); header->dir = GUINT16_FROM_LE(header->dir); header->clientIndex = GUINT32_FROM_LE(header->clientIndex); header->clusterNo = GUINT32_FROM_LE(header->clusterNo); header->frameId = GUINT16_FROM_LE(header->frameId); header->headerCrc1 = GUINT16_FROM_LE(header->headerCrc1); header->headerCrc2 = GUINT16_FROM_LE(header->headerCrc2); header->payloadLength = GUINT16_FROM_LE(header->payloadLength); header->payloadLengthValid = GUINT16_FROM_LE(header->payloadLengthValid); header->cycle = GUINT16_FROM_LE(header->cycle); header->tag = GUINT32_FROM_LE(header->tag); header->data = GUINT32_FROM_LE(header->data); header->frameFlags = GUINT32_FROM_LE(header->frameFlags); header->appParameter = GUINT32_FROM_LE(header->appParameter); /* this would be extra for ext format: header->frameCRC = GUINT32_FROM_LE(header->frameCRC); header->frameLengthInNs = GUINT32_FROM_LE(header->frameLengthInNs); header->frameId1 = GUINT16_FROM_LE(header->frameId1); header->pduOffset = GUINT16_FROM_LE(header->pduOffset); header->blfLogMask = GUINT16_FROM_LE(header->blfLogMask); */ } guint64 blf_timestamp_to_ns(blf_logobjectheader_t *header) { switch (header->flags) { case BLF_TIMESTAMP_RESOLUTION_10US: return 10000 * header->object_timestamp; break; case BLF_TIMESTAMP_RESOLUTION_1NS: return header->object_timestamp; break; default: ws_debug("i dont understand the flags 0x%x", header->flags); return 0; break; } } void blf_init_logcontainer(blf_log_container_t *tmp) { tmp->infile_start_pos = 0; tmp->infile_length = 0; tmp->infile_data_start = 0; tmp->real_start_pos = 0; tmp->real_length = 0; tmp->real_first_object_pos = -1; tmp->real_leftover_bytes = G_MAXUINT64; tmp->real_data = NULL; tmp->compression_method = 0; } void blf_add_logcontainer(blf_t *blf_data, blf_log_container_t log_container) { if (blf_data->log_containers == NULL) { blf_data->log_containers = g_array_sized_new(FALSE, FALSE, sizeof(blf_log_container_t), 1); blf_data->current_log_container = 0; } else { blf_data->current_log_container++; } g_array_append_val(blf_data->log_containers, log_container); } gboolean blf_get_logcontainer_by_index(blf_t *blf_data, guint index, blf_log_container_t **ret) { if (blf_data == NULL || blf_data->log_containers == NULL || index >= blf_data->log_containers->len) { return FALSE; } *ret = &g_array_index(blf_data->log_containers, blf_log_container_t, index); return TRUE; } gboolean blf_get_current_logcontainer(blf_t *blf_data, blf_log_container_t **ret) { return blf_get_logcontainer_by_index(blf_data, blf_data->current_log_container, ret); } gint blf_number_of_logcontainers(blf_t *blf_data) { if (blf_data == NULL) { return -1; } if (blf_data->log_containers == NULL) { return 0; } return (gint)blf_data->log_containers->len; } guint64 blf_get_num_prev_leftover_bytes(blf_t *blf_data) { if (blf_data->current_log_container == 0) { return 0; } else { blf_log_container_t tmp = g_array_index(blf_data->log_containers, blf_log_container_t, blf_data->current_log_container-1); return tmp.real_leftover_bytes; } } gboolean blf_find_logcontainer_for_address(blf_t *blf_data, gint64 pos, blf_log_container_t **container, gint *container_index) { blf_log_container_t *tmp; if (blf_data == NULL || blf_data->log_containers == NULL) { return FALSE; } for (guint i = 0; i < blf_data->log_containers->len; i++) { tmp = &g_array_index(blf_data->log_containers, blf_log_container_t, i); if (tmp->real_start_pos <= pos && pos < tmp->real_start_pos + (gint64)tmp->real_length) { *container = tmp; *container_index = i; return TRUE; } } return FALSE; } gboolean blf_pull_logcontainer_into_memory(blf_params_t *params, guint index_log_container) { blf_t *blf_data = params->blf_data; blf_log_container_t tmp; if (index_log_container >= blf_data->log_containers->len) { ws_debug("blf_pull_logcontainer_into_memory: cannot pull an unknown log container into memory"); return FALSE; } tmp = g_array_index(blf_data->log_containers, blf_log_container_t, index_log_container); if (tmp.real_data != NULL) { return TRUE; } if (tmp.compression_method == BLF_COMPRESSION_ZLIB) { #ifdef HAVE_ZLIB int err = 0; gchar *err_info; file_seek(params->fh, tmp.infile_data_start, SEEK_SET, &err); if (err < 0) { ws_debug("blf_pull_logcontainer_into_memory: cannot seek to start of log_container"); return FALSE; } /* pull compressed data into buffer */ unsigned char *compressed_data = g_try_malloc0((gsize)tmp.infile_length); guint64 data_length = (unsigned int)tmp.infile_length - (tmp.infile_data_start - tmp.infile_start_pos); if (!wtap_read_bytes_or_eof(params->fh, compressed_data, (unsigned int)data_length, &err, &err_info)) { ws_debug("blf_pull_logcontainer_into_memory: cannot read compressed data"); return FALSE; } unsigned char *buf = g_try_malloc0((gsize)tmp.real_length); z_stream infstream; infstream.zalloc = Z_NULL; infstream.zfree = Z_NULL; infstream.opaque = Z_NULL; infstream.avail_in = (unsigned int)data_length; infstream.next_in = compressed_data; infstream.avail_out = (unsigned int)tmp.real_length; infstream.next_out = buf; // the actual DE-compression work. inflateInit(&infstream); inflate(&infstream, Z_NO_FLUSH); inflateEnd(&infstream); tmp.real_data = buf; g_array_index(blf_data->log_containers, blf_log_container_t, index_log_container) = tmp; return TRUE; #else return FALSE; #endif } return FALSE; } /* returns position and -1, if compressed or split */ gint64 blf_translate_pos(blf_t *blf_data, gint64 pos) { blf_log_container_t *tmp; gint container_index; if (blf_find_logcontainer_for_address(blf_data, pos, &tmp, &container_index)) { if (tmp->compression_method == BLF_COMPRESSION_NONE) { /* this should be the same as pos, as long as infile and real start pos stay the same. */ return tmp->infile_start_pos + pos - tmp->real_start_pos; } } return -1; } gboolean blf_read_bytes_or_eof(blf_params_t *params, guint64 real_pos, void *target_buffer, unsigned int count, int *err, gchar **err_info) { blf_log_container_t *start_container; blf_log_container_t *end_container; blf_log_container_t *current_container; gint start_container_index = -1; gint end_container_index = -1; gint current_container_index = -1; unsigned int copied = 0; unsigned int data_left; unsigned int start_in_buf; unsigned char *buf = (unsigned char *)target_buffer; if (!blf_find_logcontainer_for_address(params->blf_data, real_pos, &start_container, &start_container_index)) { ws_debug("blf_read_bytes_or_eof: cannot read data because start position cannot be mapped"); return FALSE; } if (!blf_find_logcontainer_for_address(params->blf_data, real_pos + count - 1, &end_container, &end_container_index)) { ws_debug("blf_read_bytes_or_eof: cannot read data because end position cannot be mapped"); return FALSE; } current_container_index = start_container_index; current_container = start_container; start_in_buf = (unsigned int)real_pos - (unsigned int)start_container->real_start_pos; switch (start_container->compression_method) { case BLF_COMPRESSION_NONE: while (current_container_index <= end_container_index) { if (!blf_get_logcontainer_by_index(params->blf_data, current_container_index, ¤t_container)) { ws_debug("blf_read_bytes_or_eof: cannot refresh container"); return FALSE; } data_left = (unsigned int)(current_container->real_length - start_in_buf); if (file_seek(params->fh, current_container->infile_data_start + start_in_buf, SEEK_SET, err) < 0) { ws_debug("blf_read_bytes_or_eof: cannot seek data"); return FALSE; } if (data_left < (count - copied)) { if (!wtap_read_bytes_or_eof(params->fh, buf + copied, data_left, err, err_info)) { ws_debug("blf_read_bytes_or_eof: cannot read data"); return FALSE; } copied += data_left; current_container_index++; start_in_buf = 0; } else { if (!wtap_read_bytes_or_eof(params->fh, buf + copied, count - copied, err, err_info)) { ws_debug("blf_read_bytes_or_eof: cannot read data"); return FALSE; } return TRUE; } } break; case BLF_COMPRESSION_ZLIB: while (current_container_index <= end_container_index) { if (!blf_pull_logcontainer_into_memory(params, current_container_index)) { ws_debug("blf_read_bytes_or_eof: cannot pull in container"); return FALSE; } if (!blf_get_logcontainer_by_index(params->blf_data, current_container_index, ¤t_container)) { ws_debug("blf_read_bytes_or_eof: cannot refresh container"); return FALSE; } if (current_container->real_data == NULL) { ws_debug("blf_read_bytes_or_eof: pulling in container failed hard"); return FALSE; } data_left = (unsigned int)(current_container->real_length - start_in_buf); if (data_left < (count - copied)) { memcpy(buf + copied, current_container->real_data + start_in_buf, (unsigned int)data_left); copied += data_left; current_container_index++; start_in_buf = 0; } else { memcpy(buf + copied, current_container->real_data + start_in_buf, count - copied); return TRUE; } } break; default: ws_debug("blf_read_bytes_or_eof: unknown compression method"); return FALSE; } return FALSE; } /* this is only called once on open to figure out the layout of the file */ gboolean blf_scan_file_for_logcontainers(blf_params_t *params) { blf_blockheader_t header; blf_logcontainerheader_t logcontainer_header; blf_log_container_t tmp; int err; gchar *err_info; guint64 current_start_pos; guint64 current_real_start = 0; while (1) { current_start_pos = file_tell(params->fh); /* Find Object */ while (1) { if (!wtap_read_bytes_or_eof(params->fh, &header, sizeof header, &err, &err_info)) { ws_debug("we found end of file"); /* lets ignore some bytes at the end since some implementations think it is ok to add a few zero bytes */ if (err == WTAP_ERR_SHORT_READ) { err = 0; } return TRUE; } fix_endianness_blf_blockheader(&header); if (memcmp(header.magic, blf_obj_magic, sizeof(blf_obj_magic))) { ws_debug("object magic is not LOBJ"); } else { break; } /* we are moving back and try again but 1 byte later */ /* TODO: better understand how this paddings works... */ current_start_pos++; if (file_seek(params->fh, current_start_pos, SEEK_SET, &err) < 0) { return FALSE; } } if (header.header_type != BLF_HEADER_TYPE_DEFAULT) { ws_debug("unknown header type, I know only BLF_HEADER_TYPE_DEFAULT (1)"); return FALSE; } switch (header.object_type) { case BLF_OBJTYPE_LOG_CONTAINER: /* skip unknown header part if needed */ if (header.header_length - sizeof(blf_blockheader_t) > 0) { /* seek over unknown header part */ if (file_seek(params->fh, current_start_pos + header.header_length, SEEK_SET, &err) < 0) { ws_debug("cannot seek file for skipping unknown header bytes in log container"); return FALSE; } } if (!wtap_read_bytes_or_eof(params->fh, &logcontainer_header, sizeof(blf_logcontainerheader_t), &err, &err_info)) { ws_debug("not enough bytes for log container header"); return FALSE; } //tmp = g_malloc(sizeof(blf_log_container_t)); blf_init_logcontainer(&tmp); tmp.infile_start_pos = current_start_pos; tmp.infile_data_start = file_tell(params->fh); tmp.infile_length = header.object_length; tmp.real_start_pos = current_real_start; tmp.real_length = logcontainer_header.uncompressed_size; tmp.compression_method = logcontainer_header.compression_method; /* set up next start position */ current_real_start += logcontainer_header.uncompressed_size; if (file_seek(params->fh, current_start_pos + header.object_length, SEEK_SET, &err) < 0) { ws_debug("cannot seek file for skipping log container bytes"); return FALSE; } blf_add_logcontainer(params->blf_data, tmp); break; default: ws_debug("we found a non BLF log container on top level. this is unexpected."); /* TODO: maybe create "fake Log Container" for this */ if (file_seek(params->fh, current_start_pos + header.object_length, SEEK_SET, &err) < 0) { return FALSE; } } } params->blf_data->current_real_seek_pos = 0; return TRUE; } void blf_init_rec(blf_params_t *params, guint64 object_timestamp, int pkt_encap, guint32 channel) { params->rec->rec_type = REC_TYPE_PACKET; params->rec->tsprec = WTAP_TSPREC_NSEC; /* there is no 10us, maybe we should update this*/ params->rec->ts.secs = object_timestamp / (1000 * 1000 * 1000); params->rec->ts.nsecs = object_timestamp % (1000 * 1000 * 1000); params->rec->rec_header.packet_header.pkt_encap = pkt_encap; params->rec->rec_header.packet_header.interface_id = channel; /* TODO: before we had to remove comments and verdict here to not leak memory but APIs have changed ... */ } gboolean blf_read_ethernetframe(blf_params_t *params, int *err, gchar **err_info, gint64 block_start, gint64 header2_start, gint64 data_start, gint64 object_length) { blf_logobjectheader_t logheader; blf_ethernetframeheader_t ethheader; guint8 tmpbuf[18]; if (data_start - header2_start < (gint64)sizeof(blf_logobjectheader_t)) { ws_debug("blf_read_ethernetframe: not enough bytes for timestamp header"); return FALSE; } if (!blf_read_bytes_or_eof(params, header2_start, &logheader, sizeof(logheader), err, err_info)) { ws_debug("blf_read_ethernetframe: not enough bytes for logheader"); return FALSE; } fix_endianness_blf_logobjectheader(&logheader); if (object_length < (data_start - block_start) + (int) sizeof(blf_ethernetframeheader_t)) { ws_debug("blf_read_ethernetframe: not enough bytes for ethernet frame header in object"); return FALSE; } if (!blf_read_bytes_or_eof(params, data_start, ðheader, sizeof(ethheader), err, err_info)) { ws_debug("blf_read_ethernetframe: not enough bytes for ethernet frame header in file"); return FALSE; } fix_endianness_blf_ethernetframeheader(ðheader); /* * BLF breaks up and reorders the Ethernet header and VLAN tag fields. * This is a really bad design and makes this format one of the worst. * If you want a fast format that keeps your data intact, avoid this format! * So, lets hope we can reconstruct the original packet successfully. */ tmpbuf[0] = ethheader.dst_addr[0]; tmpbuf[1] = ethheader.dst_addr[1]; tmpbuf[2] = ethheader.dst_addr[2]; tmpbuf[3] = ethheader.dst_addr[3]; tmpbuf[4] = ethheader.dst_addr[4]; tmpbuf[5] = ethheader.dst_addr[5]; tmpbuf[6] = ethheader.src_addr[0]; tmpbuf[7] = ethheader.src_addr[1]; tmpbuf[8] = ethheader.src_addr[2]; tmpbuf[9] = ethheader.src_addr[3]; tmpbuf[10] = ethheader.src_addr[4]; tmpbuf[11] = ethheader.src_addr[5]; if (ethheader.tpid != 0 && ethheader.tci != 0) { tmpbuf[12] = (ethheader.tpid & 0xff00) >> 8; tmpbuf[13] = (ethheader.tpid & 0x00ff); tmpbuf[14] = (ethheader.tci & 0xff00) >> 8; tmpbuf[15] = (ethheader.tci & 0x00ff); tmpbuf[16] = (ethheader.ethtype & 0xff00) >> 8; tmpbuf[17] = (ethheader.ethtype & 0x00ff); ws_buffer_assure_space(params->buf, (gsize)18 + ethheader.payloadlength); ws_buffer_append(params->buf, tmpbuf, (gsize)18); params->rec->rec_header.packet_header.caplen = ((guint32)18 + ethheader.payloadlength); params->rec->rec_header.packet_header.len = ((guint32)18 + ethheader.payloadlength); } else { tmpbuf[12] = (ethheader.ethtype & 0xff00) >> 8; tmpbuf[13] = (ethheader.ethtype & 0x00ff); ws_buffer_assure_space(params->buf, (gsize)14 + ethheader.payloadlength); ws_buffer_append(params->buf, tmpbuf, (gsize)14); params->rec->rec_header.packet_header.caplen = ((guint32)14 + ethheader.payloadlength); params->rec->rec_header.packet_header.len = ((guint32)14 + ethheader.payloadlength); } if (!blf_read_bytes_or_eof(params, data_start + sizeof(blf_ethernetframeheader_t), ws_buffer_end_ptr(params->buf), ethheader.payloadlength, err, err_info)) { ws_debug("blf_read_ethernetframe: copying ethernet frame failed"); return FALSE; } params->buf->first_free += ethheader.payloadlength; params->rec->presence_flags = WTAP_HAS_TS | WTAP_HAS_CAP_LEN | WTAP_HAS_INTERFACE_ID; blf_init_rec(params, logheader.object_timestamp, WTAP_ENCAP_ETHERNET, ethheader.channel); return TRUE; } gboolean blf_read_ethernetframe_ext(blf_params_t *params, int *err, gchar **err_info, gint64 block_start, gint64 header2_start, gint64 data_start, gint64 object_length) { blf_logobjectheader_t logheader; blf_ethernetframeheader_ex_t ethheader; if (data_start - header2_start < (gint64)sizeof(blf_logobjectheader_t)) { ws_debug("blf_read_ethernetframe_ex: not enough bytes for timestamp header"); return FALSE; } if (!blf_read_bytes_or_eof(params, header2_start, &logheader, sizeof(logheader), err, err_info)) { ws_debug("blf_read_ethernetframe_ex: not enough bytes for logheader"); return FALSE; } fix_endianness_blf_logobjectheader(&logheader); if (object_length < (data_start - block_start) + (int) sizeof(blf_ethernetframeheader_ex_t)) { ws_debug("blf_read_ethernetframe_ex: not enough bytes for ethernet frame header in object"); return FALSE; } if (!blf_read_bytes_or_eof(params, data_start, ðheader, sizeof(blf_ethernetframeheader_ex_t), err, err_info)) { ws_debug("blf_read_ethernetframe_ex: not enough bytes for ethernet frame header in file"); return FALSE; } fix_endianness_blf_ethernetframeheader_ex(ðheader); ws_buffer_assure_space(params->buf, ethheader.frame_length); if (object_length - (data_start - block_start) - sizeof(blf_ethernetframeheader_ex_t) < ethheader.frame_length) { ws_debug("blf_read_ethernetframe_ext: frame too short"); return FALSE; } if (!blf_read_bytes_or_eof(params, data_start + sizeof(blf_ethernetframeheader_ex_t), ws_buffer_start_ptr(params->buf), ethheader.frame_length, err, err_info)) { ws_debug("blf_read_ethernetframe_ex: copying ethernet frame failed"); return FALSE; } blf_init_rec(params, logheader.object_timestamp, WTAP_ENCAP_ETHERNET, ethheader.channel); params->rec->presence_flags = WTAP_HAS_TS | WTAP_HAS_CAP_LEN | WTAP_HAS_INTERFACE_ID; params->rec->block = wtap_block_create(WTAP_BLOCK_PACKET); wtap_block_add_uint32_option(params->rec->block, OPT_PKT_QUEUE, ethheader.hw_channel); params->rec->rec_header.packet_header.caplen = ethheader.frame_length; params->rec->rec_header.packet_header.len = ethheader.frame_length; return TRUE; } static guint8 can_dlc_to_length[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8 }; static guint8 canfd_dlc_to_length[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64 }; gboolean blf_can_fill_buf_and_rec(blf_params_t *params, int *err, gchar **err_info, guint32 canid, guint8 payload_length, guint8 payload_length_valid, guint64 start_position, guint64 object_timestamp, guint32 channel) { guint8 tmpbuf[8]; tmpbuf[0] = (canid & 0xff000000) >> 24; tmpbuf[1] = (canid & 0x00ff0000) >> 16; tmpbuf[2] = (canid & 0x0000ff00) >> 8; tmpbuf[3] = (canid & 0x000000ff); tmpbuf[4] = payload_length; tmpbuf[5] = 0; tmpbuf[6] = 0; tmpbuf[7] = 0; ws_buffer_assure_space(params->buf, sizeof(tmpbuf) + payload_length_valid); ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf)); params->rec->rec_header.packet_header.caplen = sizeof(tmpbuf) + payload_length_valid; params->rec->rec_header.packet_header.len = sizeof(tmpbuf) + payload_length; if (payload_length_valid > 0 && !blf_read_bytes_or_eof(params, start_position, ws_buffer_end_ptr(params->buf), payload_length_valid, err, err_info)) { ws_debug("blf_can_fill_buf: copying can payload failed"); return FALSE; } params->buf->first_free += payload_length_valid; blf_init_rec(params, object_timestamp, WTAP_ENCAP_SOCKETCAN, channel); params->rec->presence_flags = WTAP_HAS_TS | WTAP_HAS_CAP_LEN | WTAP_HAS_INTERFACE_ID; return TRUE; } gboolean blf_read_canmessage(blf_params_t *params, int *err, gchar **err_info, gint64 block_start, gint64 header2_start, gint64 data_start, gint64 object_length, gboolean can_message2) { blf_logobjectheader_t logheader; blf_canmessage_t canheader; blf_canmessage2_trailer_t can2trailer; guint32 canid; guint8 payload_length; guint8 payload_length_valid; if (data_start - header2_start < (gint64)sizeof(blf_logobjectheader_t)) { ws_debug("blf_read_canmessage: not enough bytes for timestamp header"); return FALSE; } if (!blf_read_bytes_or_eof(params, header2_start, &logheader, sizeof(logheader), err, err_info)) { ws_debug("blf_read_canmessage: not enough bytes for logheader"); return FALSE; } fix_endianness_blf_logobjectheader(&logheader); if (object_length < (data_start - block_start) + (int) sizeof(canheader)) { ws_debug("blf_read_canmessage: not enough bytes for canfd header in object"); return FALSE; } if (!blf_read_bytes_or_eof(params, data_start, &canheader, sizeof(canheader), err, err_info)) { ws_debug("blf_read_canmessage: not enough bytes for can header in file"); return FALSE; } fix_endianness_blf_canmessage(&canheader); if (canheader.dlc > 15) { canheader.dlc = 15; } payload_length = canheader.dlc; if (payload_length > 8) { ws_debug("blf_read_canmessage: regular CAN tries more than 8 bytes? Cutting to 8!"); payload_length = 8; } payload_length_valid = payload_length; if (payload_length_valid > object_length - (data_start - block_start)) { ws_debug("blf_read_canmessage: shortening CAN payload because buffer is too short!"); payload_length_valid = (guint8)(object_length - (data_start - block_start)); } canid = canheader.id; if ((canheader.flags & BLF_CANMESSAGE_FLAG_RTR) == BLF_CANMESSAGE_FLAG_RTR) { canid |= CAN_RTR_FLAG; payload_length_valid = 0; } if (!blf_can_fill_buf_and_rec(params, err, err_info, canid, payload_length, payload_length_valid, data_start + sizeof(canheader), logheader.object_timestamp, canheader.channel)) { return FALSE; } /* actually, we do not really need the data, right now.... */ if (can_message2) { if (object_length < (data_start - block_start) + (int) sizeof(canheader) + payload_length_valid + (int) sizeof(can2trailer)) { ws_debug("blf_read_canmessage2: not enough bytes for can message 2 trailer"); return FALSE; } if (!blf_read_bytes_or_eof(params, data_start + sizeof(canheader) + payload_length_valid, &can2trailer, sizeof(can2trailer), err, err_info)) { ws_debug("blf_read_canmessage2: not enough bytes for can message 2 trailer in file"); return FALSE; } fix_endianness_blf_canmessage2_trailer(&can2trailer); } return TRUE; } gboolean blf_read_canfdmessage(blf_params_t *params, int *err, gchar **err_info, gint64 block_start, gint64 header2_start, gint64 data_start, gint64 object_length) { blf_logobjectheader_t logheader; blf_canfdmessage_t canheader; gboolean canfd; guint32 canid; guint8 payload_length; guint8 payload_length_valid; if (data_start - header2_start < (gint64)sizeof(blf_logobjectheader_t)) { ws_debug("blf_read_canfdmessage64: not enough bytes for timestamp header"); return FALSE; } if (!blf_read_bytes_or_eof(params, header2_start, &logheader, sizeof(logheader), err, err_info)) { ws_debug("blf_read_canfdmessage64: not enough bytes for logheader"); return FALSE; } fix_endianness_blf_logobjectheader(&logheader); if (object_length < (data_start - block_start) + (int) sizeof(canheader)) { ws_debug("blf_read_canfdmessage64: not enough bytes for canfd header in object"); return FALSE; } if (!blf_read_bytes_or_eof(params, data_start, &canheader, sizeof(canheader), err, err_info)) { ws_debug("blf_read_canfdmessage64: not enough bytes for canfd header in file"); return FALSE; } fix_endianness_blf_canfdmessage(&canheader); if (canheader.dlc > 15) { canheader.dlc = 15; } canfd = (canheader.canfdflags & BLF_CANFDMESSAGE_CANFDFLAG_EDL) == BLF_CANFDMESSAGE_CANFDFLAG_EDL; if (canfd) { payload_length = canfd_dlc_to_length[canheader.dlc]; } else { if (canheader.dlc > 8) { ws_debug("blf_read_canfdmessage64: regular CAN tries more than 8 bytes?"); } payload_length = can_dlc_to_length[canheader.dlc]; } payload_length_valid = payload_length; if (payload_length_valid > canheader.validDataBytes) { ws_debug("blf_read_canfdmessage: shortening canfd payload because valid data bytes shorter!"); payload_length_valid = canheader.validDataBytes; } if (payload_length_valid > object_length - (data_start - block_start) + sizeof(canheader)) { ws_debug("blf_read_canfdmessage: shortening can payload because buffer is too short!"); payload_length_valid = (guint8)(object_length - (data_start - block_start)); } canid = canheader.id; if ((canheader.flags & BLF_CANMESSAGE_FLAG_RTR) == BLF_CANMESSAGE_FLAG_RTR) { canid |= CAN_RTR_FLAG; payload_length_valid = 0; } if (!blf_can_fill_buf_and_rec(params, err, err_info, canid, payload_length, payload_length_valid, data_start + sizeof(canheader), logheader.object_timestamp, canheader.channel)) { return FALSE; } return TRUE; } gboolean blf_read_canfdmessage64(blf_params_t *params, int *err, gchar **err_info, gint64 block_start, gint64 header2_start, gint64 data_start, gint64 object_length) { blf_logobjectheader_t logheader; blf_canfdmessage64_t canheader; gboolean canfd; guint32 canid; guint8 payload_length; guint8 payload_length_valid; if (data_start - header2_start < (gint64)sizeof(blf_logobjectheader_t)) { ws_debug("blf_read_canfdmessage64: not enough bytes for timestamp header"); return FALSE; } if (!blf_read_bytes_or_eof(params, header2_start, &logheader, sizeof(logheader), err, err_info)) { ws_debug("blf_read_canfdmessage64: not enough bytes for logheader"); return FALSE; } fix_endianness_blf_logobjectheader(&logheader); if (object_length < (data_start - block_start) + (int) sizeof(canheader)) { ws_debug("blf_read_canfdmessage64: not enough bytes for canfd header in object"); return FALSE; } if (!blf_read_bytes_or_eof(params, data_start, &canheader, sizeof(canheader), err, err_info)) { ws_debug("blf_read_canfdmessage64: not enough bytes for canfd header in file"); return FALSE; } fix_endianness_blf_canfdmessage64(&canheader); if (canheader.dlc > 15) { canheader.dlc = 15; } canfd = (canheader.flags & BLF_CANFDMESSAGE64_FLAG_EDL) == BLF_CANFDMESSAGE64_FLAG_EDL; if (canfd) { payload_length = canfd_dlc_to_length[canheader.dlc]; } else { if (canheader.dlc > 8) { ws_debug("blf_read_canfdmessage64: regular CAN tries more than 8 bytes?"); } payload_length = can_dlc_to_length[canheader.dlc]; } payload_length_valid = payload_length; if (payload_length_valid > canheader.validDataBytes) { ws_debug("blf_read_canfdmessage64: shortening canfd payload because valid data bytes shorter!"); payload_length_valid = canheader.validDataBytes; } if (payload_length_valid > object_length - (data_start - block_start)) { ws_debug("blf_read_canfdmessage64: shortening can payload because buffer is too short!"); payload_length_valid = (guint8)(object_length - (data_start - block_start)); } canid = canheader.id; if ((canid & CAN_EFF_FLAG) == CAN_EFF_FLAG) { if ((canheader.flags & BLF_CANFDMESSAGE64_FLAG_SRR) == BLF_CANFDMESSAGE64_FLAG_SRR) { canid |= CAN_RTR_FLAG; payload_length_valid = 0; } } else { if ((canheader.flags & BLF_CANFDMESSAGE64_FLAG_REMOTE_FRAME) == BLF_CANFDMESSAGE64_FLAG_REMOTE_FRAME) { canid |= CAN_RTR_FLAG; payload_length_valid = 0; } } if (!blf_can_fill_buf_and_rec(params, err, err_info, canid, payload_length, payload_length_valid, data_start + sizeof(canheader), logheader.object_timestamp, canheader.channel)) { return FALSE; } return TRUE; } gboolean blf_read_flexraydata(blf_params_t *params, int *err, gchar **err_info, gint64 block_start, gint64 header2_start, gint64 data_start, gint64 object_length) { blf_logobjectheader_t logheader; blf_flexraydata_t frheader; guint8 payload_length; guint8 payload_length_valid; guint8 tmpbuf[7]; if (data_start - header2_start < (gint64)sizeof(blf_logobjectheader_t)) { ws_debug("blf_read_flexraydata: not enough bytes for timestamp header"); return FALSE; } if (!blf_read_bytes_or_eof(params, header2_start, &logheader, sizeof(logheader), err, err_info)) { ws_debug("blf_read_flexraydata: not enough bytes for logheader"); return FALSE; } fix_endianness_blf_logobjectheader(&logheader); if (object_length < (data_start - block_start) + (int) sizeof(frheader)) { ws_debug("blf_read_flexraydata: not enough bytes for flexrayheader in object"); return FALSE; } if (!blf_read_bytes_or_eof(params, data_start, &frheader, sizeof(frheader), err, err_info)) { ws_debug("blf_read_flexraydata: not enough bytes for flexrayheader header in file"); return FALSE; } fix_endianness_blf_flexraydata(&frheader); payload_length = frheader.len; payload_length_valid = payload_length; if ((frheader.len & 0x01) == 0x01) { ws_debug("blf_read_flexraydata: reading odd length in FlexRay!?"); } if (payload_length_valid > object_length - (data_start - block_start) - sizeof(frheader)) { ws_debug("blf_read_flexraydata: shortening FlexRay payload because buffer is too short!"); payload_length_valid = (guint8)(object_length - (data_start - block_start) - sizeof(frheader)); } if (frheader.channel != 0 && frheader.channel != 1) { ws_debug("blf_read_flexraydata: FlexRay supports only two channels."); } /* Measurement Header */ if (frheader.channel == 0) { tmpbuf[0] = BLF_FLEXRAYDATA_FRAME; } else { tmpbuf[0] = BLF_FLEXRAYDATA_FRAME | BLF_FLEXRAYDATA_CHANNEL_B; } /* Error Flags */ tmpbuf[1] = 0; /* Frame Header */ tmpbuf[2] = 0x20 | ((0x0700 & frheader.messageId) >> 8); tmpbuf[3] = 0x00ff & frheader.messageId; tmpbuf[4] = (0xfe & frheader.len) | ((frheader.crc & 0x0400) >> 10); tmpbuf[5] = (0x03fc & frheader.crc) >> 2; tmpbuf[6] = ((0x0003 & frheader.crc) << 6) | (0x3f & frheader.mux); ws_buffer_assure_space(params->buf, sizeof(tmpbuf) + payload_length_valid); ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf)); params->rec->rec_header.packet_header.caplen = sizeof(tmpbuf) + payload_length_valid; params->rec->rec_header.packet_header.len = sizeof(tmpbuf) + payload_length; if (payload_length_valid > 0 && !blf_read_bytes_or_eof(params, data_start + sizeof(frheader), ws_buffer_end_ptr(params->buf), payload_length_valid, err, err_info)) { ws_debug("blf_read_flexraydata: copying can payload failed"); return FALSE; } params->buf->first_free += payload_length_valid; blf_init_rec(params, logheader.object_timestamp, WTAP_ENCAP_FLEXRAY, frheader.channel); params->rec->presence_flags = WTAP_HAS_TS | WTAP_HAS_CAP_LEN | WTAP_HAS_INTERFACE_ID; return TRUE; } gboolean blf_read_flexraymessage(blf_params_t *params, int *err, gchar **err_info, gint64 block_start, gint64 header2_start, gint64 data_start, gint64 object_length) { blf_logobjectheader_t logheader; blf_flexraymessage_t frheader; guint8 payload_length; guint8 payload_length_valid; guint8 tmpbuf[7]; if (data_start - header2_start < (gint64)sizeof(blf_logobjectheader_t)) { ws_debug("blf_read_flexraymessage: not enough bytes for timestamp header"); return FALSE; } if (!blf_read_bytes_or_eof(params, header2_start, &logheader, sizeof(logheader), err, err_info)) { ws_debug("blf_read_flexraymessage: not enough bytes for logheader"); return FALSE; } fix_endianness_blf_logobjectheader(&logheader); if (object_length < (data_start - block_start) + (int) sizeof(frheader)) { ws_debug("blf_read_flexraymessage: not enough bytes for flexrayheader in object"); return FALSE; } if (!blf_read_bytes_or_eof(params, data_start, &frheader, sizeof(frheader), err, err_info)) { ws_debug("blf_read_flexraymessage: not enough bytes for flexrayheader header in file"); return FALSE; } fix_endianness_blf_flexraymessage(&frheader); payload_length = frheader.length; payload_length_valid = payload_length; if ((frheader.length & 0x01) == 0x01) { ws_debug("blf_read_flexraymessage: reading odd length in FlexRay!?"); } if (payload_length_valid > object_length - (data_start - block_start) - sizeof(frheader)) { ws_debug("blf_read_flexraymessage: shortening FlexRay payload because buffer is too short!"); payload_length_valid = (guint8)(object_length - (data_start - block_start) - sizeof(frheader)); } if (frheader.channel != 0 && frheader.channel != 1) { ws_debug("blf_read_flexraymessage: FlexRay supports only two channels."); } /* Measurement Header */ if (frheader.channel == 0) { tmpbuf[0] = BLF_FLEXRAYDATA_FRAME; } else { tmpbuf[0] = BLF_FLEXRAYDATA_FRAME | BLF_FLEXRAYDATA_CHANNEL_B; } /* Error Flags */ tmpbuf[1] = 0; /* Frame Header */ tmpbuf[2] = ((0x0700 & frheader.frameId) >> 8); if ((frheader.frameState & BLF_FLEXRAYMESSAGE_STATE_PPI) == BLF_FLEXRAYMESSAGE_STATE_PPI) { tmpbuf[2] |= BLF_DLT_FLEXRAY_PPI; } if ((frheader.frameState & BLF_FLEXRAYMESSAGE_STATE_SFI) == BLF_FLEXRAYMESSAGE_STATE_SFI) { tmpbuf[2] |= BLF_DLT_FLEXRAY_SFI; } if ((frheader.frameState & BLF_FLEXRAYMESSAGE_STATE_NFI) != BLF_FLEXRAYMESSAGE_STATE_NFI) { /* NFI needs to be inversed !? */ tmpbuf[2] |= BLF_DLT_FLEXRAY_NFI; } if ((frheader.frameState & BLF_FLEXRAYMESSAGE_STATE_STFI) == BLF_FLEXRAYMESSAGE_STATE_STFI) { tmpbuf[2] |= BLF_DLT_FLEXRAY_STFI; } tmpbuf[3] = 0x00ff & frheader.frameId; tmpbuf[4] = (0xfe & frheader.length) | ((frheader.headerCrc & 0x0400) >> 10); tmpbuf[5] = (0x03fc & frheader.headerCrc) >> 2; tmpbuf[6] = ((0x0003 & frheader.headerCrc) << 6) | (0x3f & frheader.cycle); ws_buffer_assure_space(params->buf, sizeof(tmpbuf) + payload_length_valid); ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf)); params->rec->rec_header.packet_header.caplen = sizeof(tmpbuf) + payload_length_valid; params->rec->rec_header.packet_header.len = sizeof(tmpbuf) + payload_length; if (payload_length_valid > 0 && !blf_read_bytes_or_eof(params, data_start + sizeof(frheader), ws_buffer_end_ptr(params->buf), payload_length_valid, err, err_info)) { ws_debug("blf_read_flexraymessage: copying can payload failed"); return FALSE; } params->buf->first_free += payload_length_valid; blf_init_rec(params, logheader.object_timestamp, WTAP_ENCAP_FLEXRAY, frheader.channel); params->rec->presence_flags = WTAP_HAS_TS | WTAP_HAS_CAP_LEN | WTAP_HAS_INTERFACE_ID; return TRUE; } gboolean blf_read_flexrayrcvmessageex(blf_params_t *params, int *err, gchar **err_info, gint64 block_start, gint64 header2_start, gint64 data_start, gint64 object_length, gboolean ext) { blf_logobjectheader_t logheader; blf_flexrayrcvmessage_t frheader; guint16 payload_length; guint16 payload_length_valid; guint8 tmpbuf[7]; gint frheadersize = sizeof(frheader); if (ext) { frheadersize += 40; } if (data_start - header2_start < (gint64)sizeof(blf_logobjectheader_t)) { ws_debug("blf_read_flexraymessage: not enough bytes for timestamp header"); return FALSE; } if (!blf_read_bytes_or_eof(params, header2_start, &logheader, sizeof(logheader), err, err_info)) { ws_debug("blf_read_flexraymessage: not enough bytes for logheader"); return FALSE; } fix_endianness_blf_logobjectheader(&logheader); if ((gint64)object_length < (data_start - block_start) + frheadersize) { ws_debug("blf_read_flexraymessage: not enough bytes for flexrayheader in object"); return FALSE; } if (!blf_read_bytes_or_eof(params, data_start, &frheader, sizeof(frheader), err, err_info)) { ws_debug("blf_read_flexraymessage: not enough bytes for flexrayheader header in file"); return FALSE; } fix_endianness_blf_flexrayrcvmessage(&frheader); if (!ext) { frheader.dir &= 0xff; frheader.cycle &= 0xff; } payload_length = frheader.payloadLength; payload_length_valid = frheader.payloadLengthValid; if ((frheader.payloadLength & 0x01) == 0x01) { ws_debug("blf_read_flexraymessage: reading odd length in FlexRay!?"); } if (payload_length_valid > object_length - (data_start - block_start) - frheadersize) { ws_debug("blf_read_flexraymessage: shortening FlexRay payload because buffer is too short!"); payload_length_valid = (guint8)(object_length - (data_start - block_start) - frheadersize); } /* Measurement Header */ /* TODO: It seems that this format support both channels at the same time!? */ if (frheader.channelMask == BLF_FLEXRAYRCVMSG_CHANNELMASK_A) { tmpbuf[0] = BLF_FLEXRAYDATA_FRAME; } else { tmpbuf[0] = BLF_FLEXRAYDATA_FRAME | BLF_FLEXRAYDATA_CHANNEL_B; } /* Error Flags */ tmpbuf[1] = 0; /* Frame Header */ tmpbuf[2] = ((0x0700 & frheader.frameId) >> 8); if ((frheader.data & BLF_FLEXRAYRCVMSG_DATA_FLAG_PAYLOAD_PREAM) == BLF_FLEXRAYRCVMSG_DATA_FLAG_PAYLOAD_PREAM) { tmpbuf[2] |= BLF_DLT_FLEXRAY_PPI; } if ((frheader.data & BLF_FLEXRAYRCVMSG_DATA_FLAG_SYNC) == BLF_FLEXRAYRCVMSG_DATA_FLAG_SYNC) { tmpbuf[2] |= BLF_DLT_FLEXRAY_SFI; } if ((frheader.data & BLF_FLEXRAYRCVMSG_DATA_FLAG_NULL_FRAME) != BLF_FLEXRAYRCVMSG_DATA_FLAG_NULL_FRAME) { /* NFI needs to be inversed !? */ tmpbuf[2] |= BLF_DLT_FLEXRAY_NFI; } if ((frheader.data & BLF_FLEXRAYRCVMSG_DATA_FLAG_STARTUP) == BLF_FLEXRAYRCVMSG_DATA_FLAG_STARTUP) { tmpbuf[2] |= BLF_DLT_FLEXRAY_STFI; } tmpbuf[3] = 0x00ff & frheader.frameId; tmpbuf[4] = (0xfe & frheader.payloadLength) | ((frheader.headerCrc1 & 0x0400) >> 10); tmpbuf[5] = (0x03fc & frheader.headerCrc1) >> 2; tmpbuf[6] = ((0x0003 & frheader.headerCrc1) << 6) | (0x3f & frheader.cycle); ws_buffer_assure_space(params->buf, sizeof(tmpbuf) + payload_length_valid); ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf)); params->rec->rec_header.packet_header.caplen = sizeof(tmpbuf) + payload_length_valid; params->rec->rec_header.packet_header.len = sizeof(tmpbuf) + payload_length; if (payload_length_valid > 0 && !blf_read_bytes_or_eof(params, data_start + frheadersize, ws_buffer_end_ptr(params->buf), payload_length_valid, err, err_info)) { ws_debug("blf_read_flexraymessage: copying can payload failed"); return FALSE; } params->buf->first_free += payload_length_valid; blf_init_rec(params, logheader.object_timestamp, WTAP_ENCAP_FLEXRAY, frheader.channelMask); params->rec->presence_flags = WTAP_HAS_TS | WTAP_HAS_CAP_LEN | WTAP_HAS_INTERFACE_ID; return TRUE; } gboolean blf_read_block(blf_params_t *params, gint64 start_pos, int *err, gchar **err_info) { blf_blockheader_t header; //gint64 infile_block_start = blf_translate_pos(params->blf_data, start_pos); while (1) { /* Find Object */ /* Resetting buffer */ params->buf->first_free = params->buf->start; while (1) { if (!blf_read_bytes_or_eof(params, start_pos, &header, sizeof header, err, err_info)) { ws_debug("blf_read_block: not enough bytes for block header or unsupported file"); if (*err == WTAP_ERR_SHORT_READ) { /* we have found the end that is not a short read therefore. */ *err = 0; g_free(*err_info); } return FALSE; } fix_endianness_blf_blockheader(&header); if (memcmp(header.magic, blf_obj_magic, sizeof(blf_obj_magic))) { ws_debug("object magic is not LOBJ"); } else { break; } /* we are moving back and try again but 1 byte later */ /* TODO: better understand how this paddings works... */ start_pos++; } params->blf_data->start_of_last_obj = start_pos; if (header.header_type != BLF_HEADER_TYPE_DEFAULT) { ws_debug("unknown header type"); return FALSE; } /* already making sure that we start after this object next time. */ params->blf_data->current_real_seek_pos = start_pos + header.object_length; switch (header.object_type) { case BLF_OBJTYPE_LOG_CONTAINER: ws_debug("blf_read_block: log container in log container not supported"); return FALSE; break; case BLF_OBJTYPE_ETHERNET_FRAME: return blf_read_ethernetframe(params, err, err_info, start_pos, start_pos + sizeof(blf_blockheader_t), start_pos + header.header_length, header.object_length); break; case BLF_OBJTYPE_ETHERNET_FRAME_EX: return blf_read_ethernetframe_ext(params, err, err_info, start_pos, start_pos + sizeof(blf_blockheader_t), start_pos + header.header_length, header.object_length); break; case BLF_OBJTYPE_CAN_MESSAGE: return blf_read_canmessage(params, err, err_info, start_pos, start_pos + sizeof(blf_blockheader_t), start_pos + header.header_length, header.object_length, FALSE); break; case BLF_OBJTYPE_CAN_MESSAGE2: return blf_read_canmessage(params, err, err_info, start_pos, start_pos + sizeof(blf_blockheader_t), start_pos + header.header_length, header.object_length, TRUE); break; case BLF_OBJTYPE_CAN_FD_MESSAGE: return blf_read_canfdmessage(params, err, err_info, start_pos, start_pos + sizeof(blf_blockheader_t), start_pos + header.header_length, header.object_length); break; case BLF_OBJTYPE_CAN_FD_MESSAGE_64: return blf_read_canfdmessage64(params, err, err_info, start_pos, start_pos + sizeof(blf_blockheader_t), start_pos + header.header_length, header.object_length); break; case BLF_OBJTYPE_FLEXRAY_DATA: return blf_read_flexraydata(params, err, err_info, start_pos, start_pos + sizeof(blf_blockheader_t), start_pos + header.header_length, header.object_length); break; case BLF_OBJTYPE_FLEXRAY_MESSAGE: return blf_read_flexraymessage(params, err, err_info, start_pos, start_pos + sizeof(blf_blockheader_t), start_pos + header.header_length, header.object_length); break; case BLF_OBJTYPE_FLEXRAY_RCVMESSAGE: return blf_read_flexrayrcvmessageex(params, err, err_info, start_pos, start_pos + sizeof(blf_blockheader_t), start_pos + header.header_length, header.object_length, FALSE); break; case BLF_OBJTYPE_FLEXRAY_RCVMESSAGE_EX: return blf_read_flexrayrcvmessageex(params, err, err_info, start_pos, start_pos + sizeof(blf_blockheader_t), start_pos + header.header_length, header.object_length, TRUE); break; default: ws_debug("blf_read_block: unknown object type"); start_pos += header.object_length; } } return TRUE; } static gboolean blf_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err, gchar **err_info, gint64 *data_offset) { blf_params_t blf_tmp; blf_tmp.wth = wth; blf_tmp.fh = wth->fh; blf_tmp.rec = rec; blf_tmp.buf = buf; blf_tmp.blf_data = (blf_t *)wth->priv; if (!blf_read_block(&blf_tmp, blf_tmp.blf_data->current_real_seek_pos, err, err_info)) { ws_debug("data_offset is %" G_GINT64_MODIFIER "d", *data_offset); return FALSE; } *data_offset = blf_tmp.blf_data->start_of_last_obj; return TRUE; } static gboolean blf_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec, Buffer *buf, int *err, gchar **err_info) { blf_params_t blf_tmp; blf_tmp.wth = wth; blf_tmp.fh = wth->random_fh; blf_tmp.rec = rec; blf_tmp.buf = buf; blf_tmp.blf_data = (blf_t *)wth->priv; if (!blf_read_block(&blf_tmp, seek_off, err, err_info)) { ws_debug("couldn't read packet block (err=%d).", *err); return FALSE; } return TRUE; } static void blf_close(wtap *wth) { blf_t *blf = (blf_t *)wth->priv; if (blf != NULL && blf->log_containers != NULL) { for (guint i = 0; i < blf->log_containers->len; i++) { blf_log_container_t *log_container = &g_array_index(blf->log_containers, blf_log_container_t, i); if (log_container->real_data != NULL) { g_free(log_container->real_data); } } g_array_free(blf->log_containers, TRUE); blf->log_containers = NULL; } return; } wtap_open_return_val blf_open(wtap *wth, int *err, gchar **err_info) { blf_fileheader_t header; blf_t *blf; blf_params_t params; ws_debug("opening file"); if (!wtap_read_bytes_or_eof(wth->fh, &header, sizeof header, err, err_info)) { ws_debug("wtap_read_bytes_or_eof() failed, err = %d.", *err); if (*err == 0 || *err == WTAP_ERR_SHORT_READ) { /* * Short read or EOF. * * We're reading this as part of an open, so * the file is too short to be a blf file. */ *err = 0; g_free(*err_info); *err_info = NULL; return WTAP_OPEN_NOT_MINE; } return WTAP_OPEN_ERROR; } fix_endianness_blf_fileheader(&header); if (memcmp(header.magic, blf_magic, sizeof(blf_magic))) { return WTAP_OPEN_NOT_MINE; } /* This seems to be an BLF! */ /* skip unknown part of header */ file_seek(wth->fh, header.header_length, SEEK_SET, err); /* Prepare our private context. */ blf = g_new(blf_t, 1); blf->log_containers = NULL; blf->current_log_container = 0; blf->current_real_seek_pos = 0; /* embed in params */ params.blf_data = blf; params.buf = NULL; params.fh = wth->fh; params.rec = NULL; params.wth = wth; params.blf_data->current_real_seek_pos = 0; /* lets check out the layout of all log containers */ blf_scan_file_for_logcontainers(¶ms); wth->priv = (void *)blf; wth->file_encap = WTAP_ENCAP_UNKNOWN; wth->snapshot_length = 0; wth->file_tsprec = WTAP_TSPREC_UNKNOWN; wth->subtype_read = blf_read; wth->subtype_seek_read = blf_seek_read; wth->subtype_close = blf_close; wth->file_type_subtype = blf_file_type_subtype; return WTAP_OPEN_MINE; } static const struct supported_block_type blf_blocks_supported[] = { { WTAP_BLOCK_PACKET, ONE_BLOCK_SUPPORTED, NO_OPTIONS_SUPPORTED } }; static const struct file_type_subtype_info blf_info = { "BLF Logfile", "blf", "blf", NULL, FALSE, BLOCKS_SUPPORTED(blf_blocks_supported), NULL, NULL, NULL }; void register_blf(void) { blf_file_type_subtype = wtap_register_file_type_subtype(&blf_info); /* * Register name for backwards compatibility with the * wtap_filetypes table in Lua. */ wtap_register_backwards_compatibility_lua_name("BLF", blf_file_type_subtype); } /* * Editor modelines - https://www.wireshark.org/tools/modelines.html * * 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: */