TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags
[wireshark-sm.git] / wiretap / blf.c
blob5a87f3112db0e7207eb1dead3a628b1c68fde9c3
1 /* blf.c
3 * Wiretap Library
4 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
6 * File format support for the Binary Log File (BLF) file format from
7 * Vector Informatik decoder
8 * Copyright (c) 2021-2024 by Dr. Lars Voelker <lars.voelker@technica-engineering.de>
10 * SPDX-License-Identifier: GPL-2.0-or-later
14 * The following was used as a reference for the file format:
15 * https://bitbucket.org/tobylorenz/vector_blf
16 * The repo above includes multiple examples files as well.
19 #include <config.h>
20 #define WS_LOG_DOMAIN LOG_DOMAIN_WIRETAP
22 #include "blf.h"
24 #include <epan/dissectors/packet-socketcan.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <epan/value_string.h>
28 #include <wsutil/wslog.h>
29 #include <wsutil/exported_pdu_tlvs.h>
30 #include <wsutil/report_message.h>
31 #include <wsutil/strtoi.h>
32 #include "file_wrappers.h"
33 #include "wtap-int.h"
35 #ifdef HAVE_ZLIBNG
36 #include <zlib-ng.h>
37 #define ZLIB_PREFIX(x) zng_ ## x
38 typedef zng_stream zlib_stream;
39 #else
40 #ifdef HAVE_ZLIB
41 #define ZLIB_PREFIX(x) x
42 #include <zlib.h>
43 typedef z_stream zlib_stream;
44 #endif /* HAVE_ZLIB */
45 #endif
47 static const uint8_t blf_magic[] = { 'L', 'O', 'G', 'G' };
48 static const uint8_t blf_obj_magic[] = { 'L', 'O', 'B', 'J' };
50 static int blf_file_type_subtype = -1;
52 void register_blf(void);
54 static bool blf_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err, char **err_info, int64_t *data_offset);
55 static bool blf_seek_read(wtap *wth, int64_t seek_off, wtap_rec* rec, Buffer *buf, int *err, char **err_info);
56 static void blf_close(wtap *wth);
59 * The virtual buffer looks like this (skips all headers):
60 * uncompressed log container data
61 * uncompressed log container data
62 * ...
64 * The "real" positions, length, etc. reference this layout and not the file.
66 typedef struct blf_log_container {
67 int64_t infile_start_pos; /* start position of log container in file */
68 uint64_t infile_length; /* length of log container in file */
69 uint64_t infile_data_start; /* start position of data in log container in file */
71 uint64_t real_start_pos; /* decompressed (virtual) start position including header */
72 uint64_t real_length; /* decompressed length */
74 uint16_t compression_method; /* 0: uncompressed, 2: zlib */
76 unsigned char *real_data; /* cache for decompressed data */
77 } blf_log_container_t;
79 typedef struct blf_data {
80 int64_t start_of_last_obj;
81 int64_t current_real_seek_pos;
82 uint64_t start_offset_ns;
84 GArray *log_containers;
86 GHashTable *channel_to_iface_ht;
87 GHashTable *channel_to_name_ht;
88 uint32_t next_interface_id;
89 } blf_t;
91 typedef struct blf_params {
92 wtap *wth;
93 wtap_rec *rec;
94 Buffer *buf;
95 FILE_T fh;
96 bool random;
97 bool pipe;
99 blf_t *blf_data;
100 } blf_params_t;
102 typedef struct blf_channel_to_iface_entry {
103 int pkt_encap;
104 uint16_t channel;
105 uint16_t hwchannel;
106 uint32_t interface_id;
107 } blf_channel_to_iface_entry_t;
109 static void
110 blf_free_key(void *key) {
111 g_free(key);
114 static void
115 blf_free_channel_to_iface_entry(void *data) {
116 g_free(data);
119 static void
120 blf_free_channel_to_name_entry(void *data) {
121 g_free(data);
124 static int64_t
125 blf_calc_key_value(int pkt_encap, uint16_t channel, uint16_t hwchannel) {
126 return (int64_t)(((uint64_t)pkt_encap << 32) | ((uint64_t)hwchannel << 16) | (uint64_t)channel);
129 /** Return the Epoch ns time of the capture start
131 * This is not intended to fully validate the date and time,
132 * but just to check if the values are plausible.
134 static uint64_t
135 blf_get_start_offset_ns(const blf_date_t* start_date) {
136 struct tm timestamp;
137 time_t start_offset_s;
139 if (start_date != NULL &&
140 (start_date->month >= 1 && start_date->month <= 12) &&
141 (start_date->day >= 1 && start_date->day <= 31) &&
142 (start_date->hour <= 23) && (start_date->mins <= 59) &&
143 (start_date->sec <= 61) /* Apparently can be up to 61 on certain systems */
144 ) { /* Not checking if milliseconds are actually less than 1000 */
145 timestamp.tm_year = (start_date->year > 1970) ? start_date->year - 1900 : 70;
146 timestamp.tm_mon = start_date->month - 1;
147 timestamp.tm_mday = start_date->day;
148 timestamp.tm_hour = start_date->hour;
149 timestamp.tm_min = start_date->mins;
150 timestamp.tm_sec = start_date->sec;
151 timestamp.tm_isdst = -1;
152 start_offset_s = mktime(&timestamp);
153 if (start_offset_s >= 0) {
154 return (1000 * 1000 * (start_date->ms + (1000 * (uint64_t)start_offset_s)));
158 return 0;
161 static void add_interface_name(wtap_block_t int_data, int pkt_encap, uint16_t channel, uint16_t hwchannel, char *name) {
162 if (name != NULL) {
163 wtap_block_add_string_option_format(int_data, OPT_IDB_NAME, "%s", name);
164 } else {
165 switch (pkt_encap) {
166 case WTAP_ENCAP_ETHERNET:
167 /* we use UINT16_MAX to encode no hwchannel */
168 if (hwchannel == UINT16_MAX) {
169 wtap_block_add_string_option_format(int_data, OPT_IDB_NAME, "ETH-%u", channel);
170 } else {
171 wtap_block_add_string_option_format(int_data, OPT_IDB_NAME, "ETH-%u-%u", channel, hwchannel);
173 break;
174 case WTAP_ENCAP_IEEE_802_11:
175 wtap_block_add_string_option_format(int_data, OPT_IDB_NAME, "WLAN-%u", channel);
176 break;
177 case WTAP_ENCAP_FLEXRAY:
178 wtap_block_add_string_option_format(int_data, OPT_IDB_NAME, "FR-%u", channel);
179 break;
180 case WTAP_ENCAP_LIN:
181 wtap_block_add_string_option_format(int_data, OPT_IDB_NAME, "LIN-%u", channel);
182 break;
183 case WTAP_ENCAP_SOCKETCAN:
184 wtap_block_add_string_option_format(int_data, OPT_IDB_NAME, "CAN-%u", channel);
185 break;
186 default:
187 wtap_block_add_string_option_format(int_data, OPT_IDB_NAME, "ENCAP_%d-%u", pkt_encap, channel);
192 static uint32_t
193 blf_add_interface(blf_params_t *params, int pkt_encap, uint32_t channel, uint16_t hwchannel, char *name) {
194 wtap_block_t int_data = wtap_block_create(WTAP_BLOCK_IF_ID_AND_INFO);
195 wtapng_if_descr_mandatory_t *if_descr_mand = (wtapng_if_descr_mandatory_t*)wtap_block_get_mandatory_data(int_data);
196 blf_channel_to_iface_entry_t *item = NULL;
198 if_descr_mand->wtap_encap = pkt_encap;
199 add_interface_name(int_data, pkt_encap, channel, hwchannel, name);
201 * The time stamp resolution in these files can be per-record;
202 * the maximum resolution is nanoseconds, so we specify that
203 * as the interface's resolution.
205 * We set the resolution for a record on a per-record basis,
206 * based on what the record specifies.
208 if_descr_mand->time_units_per_second = 1000 * 1000 * 1000;
209 if_descr_mand->tsprecision = WTAP_TSPREC_NSEC;
210 wtap_block_add_uint8_option(int_data, OPT_IDB_TSRESOL, 9);
211 if_descr_mand->snap_len = WTAP_MAX_PACKET_SIZE_STANDARD;
212 if_descr_mand->num_stat_entries = 0;
213 if_descr_mand->interface_statistics = NULL;
214 wtap_add_idb(params->wth, int_data);
216 if (params->wth->file_encap == WTAP_ENCAP_NONE) {
217 params->wth->file_encap = if_descr_mand->wtap_encap;
218 } else {
219 if (params->wth->file_encap != if_descr_mand->wtap_encap) {
220 params->wth->file_encap = WTAP_ENCAP_PER_PACKET;
224 int64_t *key = NULL;
225 key = g_new(int64_t, 1);
226 *key = blf_calc_key_value(pkt_encap, channel, hwchannel);
228 item = g_new(blf_channel_to_iface_entry_t, 1);
229 item->channel = channel;
230 item->hwchannel = hwchannel;
231 item->pkt_encap = pkt_encap;
232 item->interface_id = params->blf_data->next_interface_id++;
233 g_hash_table_insert(params->blf_data->channel_to_iface_ht, key, item);
235 return item->interface_id;
238 /** This is used to save the interface name without creating it.
240 * This approach allows up to update the name of the interface
241 * up until the first captured packet.
243 static bool
244 // NOLINTNEXTLINE(misc-no-recursion)
245 blf_prepare_interface_name(blf_params_t* params, int pkt_encap, uint16_t channel, uint16_t hwchannel, const char* name, bool force_new_name) {
246 int64_t key = blf_calc_key_value(pkt_encap, channel, hwchannel);
247 char* old_name;
248 char* new_name;
249 char* iface_name;
250 int64_t* new_key;
251 bool ret;
253 if (params->blf_data->channel_to_name_ht == NULL) {
254 return false;
257 old_name = (char *)g_hash_table_lookup(params->blf_data->channel_to_name_ht, &key);
259 if (old_name != NULL && force_new_name) {
260 if (!g_hash_table_remove(params->blf_data->channel_to_name_ht, &key)) {
261 return false;
264 old_name = NULL;
267 if (old_name == NULL && name != NULL) {
268 new_key = g_new(int64_t, 1);
269 *new_key = key;
270 new_name = ws_strdup(name);
271 if (!g_hash_table_insert(params->blf_data->channel_to_name_ht, new_key, new_name)) {
272 return false;
275 else {
276 new_name = old_name;
279 if (pkt_encap == WTAP_ENCAP_ETHERNET) {
280 /* Just for Ethernet, prepare the equivalent STATUS interface */
281 iface_name = new_name != NULL ? ws_strdup_printf("STATUS-%s", new_name) : NULL;
283 // We recurse here once.
284 ret = blf_prepare_interface_name(params, WTAP_ENCAP_WIRESHARK_UPPER_PDU, channel, hwchannel, iface_name, force_new_name);
285 if (iface_name) {
286 g_free(iface_name);
288 if (!ret) {
289 return false;
293 return true;
296 static uint32_t
297 blf_lookup_interface(blf_params_t *params, int pkt_encap, uint16_t channel, uint16_t hwchannel, char *name) {
298 int64_t key = blf_calc_key_value(pkt_encap, channel, hwchannel);
299 blf_channel_to_iface_entry_t* item;
300 char* saved_name;
301 uint32_t ret;
303 if (params->blf_data->channel_to_iface_ht == NULL) {
304 return 0;
307 item = (blf_channel_to_iface_entry_t *)g_hash_table_lookup(params->blf_data->channel_to_iface_ht, &key);
309 if (item != NULL) {
310 return item->interface_id;
312 else {
313 saved_name = (char*)g_hash_table_lookup(params->blf_data->channel_to_name_ht, &key);
315 if (saved_name != NULL) {
316 ret = blf_add_interface(params, pkt_encap, channel, hwchannel, saved_name);
317 g_hash_table_remove(params->blf_data->channel_to_name_ht, &key);
319 return ret;
321 else {
322 return blf_add_interface(params, pkt_encap, channel, hwchannel, name);
327 static void
328 fix_endianness_blf_date(blf_date_t *date) {
329 date->year = GUINT16_FROM_LE(date->year);
330 date->month = GUINT16_FROM_LE(date->month);
331 date->dayofweek = GUINT16_FROM_LE(date->dayofweek);
332 date->day = GUINT16_FROM_LE(date->day);
333 date->hour = GUINT16_FROM_LE(date->hour);
334 date->mins = GUINT16_FROM_LE(date->mins);
335 date->sec = GUINT16_FROM_LE(date->sec);
336 date->ms = GUINT16_FROM_LE(date->ms);
339 static void
340 fix_endianness_blf_fileheader(blf_fileheader_t *header) {
341 header->header_length = GUINT32_FROM_LE(header->header_length);
342 header->api_version = GUINT32_FROM_LE(header->api_version);
343 header->len_compressed = GUINT64_FROM_LE(header->len_compressed);
344 header->len_uncompressed = GUINT64_FROM_LE(header->len_uncompressed);
345 header->obj_count = GUINT32_FROM_LE(header->obj_count);
346 header->application_build = GUINT32_FROM_LE(header->application_build);
347 fix_endianness_blf_date(&(header->start_date));
348 fix_endianness_blf_date(&(header->end_date));
349 header->restore_point_offset = GUINT32_FROM_LE(header->restore_point_offset);
352 static void
353 fix_endianness_blf_blockheader(blf_blockheader_t *header) {
354 header->header_length = GUINT16_FROM_LE(header->header_length);
355 header->header_type = GUINT16_FROM_LE(header->header_type);
356 header->object_length = GUINT32_FROM_LE(header->object_length);
357 header->object_type = GUINT32_FROM_LE(header->object_type);
360 static void
361 fix_endianness_blf_logcontainerheader(blf_logcontainerheader_t *header) {
362 header->compression_method = GUINT16_FROM_LE(header->compression_method);
363 header->res1 = GUINT16_FROM_LE(header->res1);
364 header->res2 = GUINT32_FROM_LE(header->res2);
365 header->uncompressed_size = GUINT32_FROM_LE(header->uncompressed_size);
366 header->res4 = GUINT32_FROM_LE(header->res4);
369 static void
370 fix_endianness_blf_logobjectheader(blf_logobjectheader_t *header) {
371 header->flags = GUINT32_FROM_LE(header->flags);
372 header->client_index = GUINT16_FROM_LE(header->client_index);
373 header->object_version = GUINT16_FROM_LE(header->object_version);
374 header->object_timestamp = GUINT64_FROM_LE(header->object_timestamp);
377 static void
378 fix_endianness_blf_logobjectheader2(blf_logobjectheader2_t *header) {
379 header->flags = GUINT32_FROM_LE(header->flags);
380 header->object_version = GUINT16_FROM_LE(header->object_version);
381 header->object_timestamp = GUINT64_FROM_LE(header->object_timestamp);
382 header->original_timestamp = GUINT64_FROM_LE(header->object_timestamp);
385 static void
386 fix_endianness_blf_logobjectheader3(blf_logobjectheader3_t *header) {
387 header->flags = GUINT32_FROM_LE(header->flags);
388 header->static_size = GUINT16_FROM_LE(header->static_size);
389 header->object_version = GUINT16_FROM_LE(header->object_version);
390 header->object_timestamp = GUINT64_FROM_LE(header->object_timestamp);
393 static void
394 fix_endianness_blf_ethernetframeheader(blf_ethernetframeheader_t *header) {
395 header->channel = GUINT16_FROM_LE(header->channel);
396 header->direction = GUINT16_FROM_LE(header->direction);
397 header->ethtype = GUINT16_FROM_LE(header->ethtype);
398 header->tpid = GUINT16_FROM_LE(header->tpid);
399 header->tci = GUINT16_FROM_LE(header->tci);
400 header->payloadlength = GUINT16_FROM_LE(header->payloadlength);
403 static void
404 fix_endianness_blf_ethernetframeheader_ex(blf_ethernetframeheader_ex_t *header) {
405 header->struct_length = GUINT16_FROM_LE(header->struct_length);
406 header->flags = GUINT16_FROM_LE(header->flags);
407 header->channel = GUINT16_FROM_LE(header->channel);
408 header->hw_channel = GUINT16_FROM_LE(header->hw_channel);
409 header->frame_duration = GUINT64_FROM_LE(header->frame_duration);
410 header->frame_checksum = GUINT32_FROM_LE(header->frame_checksum);
411 header->direction = GUINT16_FROM_LE(header->direction);
412 header->frame_length = GUINT16_FROM_LE(header->frame_length);
413 header->frame_handle = GUINT32_FROM_LE(header->frame_handle);
414 header->error = GUINT32_FROM_LE(header->error);
417 static void
418 fix_endianness_blf_ethernet_rxerror(blf_ethernet_rxerror_t* header) {
419 header->struct_length = GUINT16_FROM_LE(header->struct_length);
420 header->channel = GUINT16_FROM_LE(header->channel);
421 header->direction = GUINT16_FROM_LE(header->direction);
422 header->hw_channel = GUINT16_FROM_LE(header->hw_channel);
423 header->frame_checksum = GUINT32_FROM_LE(header->frame_checksum);
424 header->frame_length = GUINT16_FROM_LE(header->frame_length);
425 header->error = GUINT32_FROM_LE(header->error);
428 static void
429 fix_endianness_blf_wlanframeheader(blf_wlanframeheader_t* header) {
430 header->channel = GUINT16_FROM_LE(header->channel);
431 header->flags = GUINT16_FROM_LE(header->flags);
432 header->signal_strength = GUINT16_FROM_LE(header->signal_strength);
433 header->signal_quality = GUINT16_FROM_LE(header->signal_quality);
434 header->frame_length = GUINT16_FROM_LE(header->frame_length);
437 static void
438 fix_endianness_blf_canmessage(blf_canmessage_t *header) {
439 header->channel = GUINT16_FROM_LE(header->channel);
440 header->id = GUINT32_FROM_LE(header->id);
443 static void
444 fix_endianness_blf_canmessage2_trailer(blf_canmessage2_trailer_t *header) {
445 header->frameLength_in_ns = GUINT32_FROM_LE(header->frameLength_in_ns);
446 header->reserved2 = GUINT16_FROM_LE(header->reserved1);
449 static void
450 fix_endianness_blf_canfdmessage(blf_canfdmessage_t *header) {
451 header->channel = GUINT16_FROM_LE(header->channel);
452 header->id = GUINT32_FROM_LE(header->id);
453 header->frameLength_in_ns = GUINT32_FROM_LE(header->frameLength_in_ns);
454 header->reservedCanFdMessage2 = GUINT32_FROM_LE(header->reservedCanFdMessage2);
457 static void
458 fix_endianness_blf_canfdmessage64(blf_canfdmessage64_t *header) {
459 header->id = GUINT32_FROM_LE(header->id);
460 header->frameLength_in_ns = GUINT32_FROM_LE(header->frameLength_in_ns);
461 header->flags = GUINT32_FROM_LE(header->flags);
462 header->btrCfgArb = GUINT32_FROM_LE(header->btrCfgArb);
463 header->btrCfgData = GUINT32_FROM_LE(header->btrCfgData);
464 header->timeOffsetBrsNs = GUINT32_FROM_LE(header->timeOffsetBrsNs);
465 header->timeOffsetCrcDelNs = GUINT32_FROM_LE(header->timeOffsetCrcDelNs);
466 header->bitCount = GUINT16_FROM_LE(header->bitCount);
467 header->crc = GUINT32_FROM_LE(header->crc);
470 static void
471 fix_endianness_blf_canerror(blf_canerror_t *header) {
472 header->channel = GUINT16_FROM_LE(header->channel);
473 header->length = GUINT16_FROM_LE(header->length);
476 static void
477 fix_endianness_blf_canerrorext(blf_canerrorext_t *header) {
478 header->channel = GUINT16_FROM_LE(header->channel);
479 header->length = GUINT16_FROM_LE(header->length);
480 header->flags = GUINT32_FROM_LE(header->flags);
481 header->frameLength_in_ns = GUINT32_FROM_LE(header->frameLength_in_ns);
482 header->id = GUINT32_FROM_LE(header->id);
483 header->errorCodeExt = GUINT16_FROM_LE(header->errorCodeExt);
486 static void
487 fix_endianness_blf_canfderror64(blf_canfderror64_t *header) {
488 header->flags = GUINT16_FROM_LE(header->flags);
489 header->errorCodeExt = GUINT16_FROM_LE(header->errorCodeExt);
490 header->extFlags = GUINT16_FROM_LE(header->extFlags);
491 header->id = GUINT32_FROM_LE(header->id);
492 header->frameLength_in_ns = GUINT32_FROM_LE(header->frameLength_in_ns);
493 header->btrCfgArb = GUINT32_FROM_LE(header->btrCfgArb);
494 header->btrCfgData = GUINT32_FROM_LE(header->btrCfgData);
495 header->timeOffsetBrsNs = GUINT32_FROM_LE(header->timeOffsetBrsNs);
496 header->timeOffsetCrcDelNs = GUINT32_FROM_LE(header->timeOffsetCrcDelNs);
497 header->crc = GUINT32_FROM_LE(header->crc);
498 header->errorPosition = GUINT16_FROM_LE(header->errorPosition);
501 static void
502 fix_endianness_blf_flexraydata(blf_flexraydata_t *header) {
503 header->channel = GUINT16_FROM_LE(header->channel);
504 header->messageId = GUINT16_FROM_LE(header->messageId);
505 header->crc = GUINT16_FROM_LE(header->crc);
506 header->reservedFlexRayData2 = GUINT16_FROM_LE(header->reservedFlexRayData2);
509 static void
510 fix_endianness_blf_flexraymessage(blf_flexraymessage_t *header) {
511 header->channel = GUINT16_FROM_LE(header->channel);
512 header->fpgaTick = GUINT32_FROM_LE(header->fpgaTick);
513 header->fpgaTickOverflow = GUINT32_FROM_LE(header->fpgaTickOverflow);
514 header->clientIndexFlexRayV6Message = GUINT32_FROM_LE(header->clientIndexFlexRayV6Message);
515 header->clusterTime = GUINT32_FROM_LE(header->clusterTime);
516 header->frameId = GUINT16_FROM_LE(header->frameId);
517 header->headerCrc = GUINT16_FROM_LE(header->headerCrc);
518 header->frameState = GUINT16_FROM_LE(header->frameState);
519 header->reservedFlexRayV6Message2 = GUINT16_FROM_LE(header->reservedFlexRayV6Message2);
522 static void
523 fix_endianness_blf_flexrayrcvmessage(blf_flexrayrcvmessage_t *header) {
524 header->channel = GUINT16_FROM_LE(header->channel);
525 header->version = GUINT16_FROM_LE(header->version);
526 header->channelMask = GUINT16_FROM_LE(header->channelMask);
527 header->dir = GUINT16_FROM_LE(header->dir);
528 header->clientIndex = GUINT32_FROM_LE(header->clientIndex);
529 header->clusterNo = GUINT32_FROM_LE(header->clusterNo);
530 header->frameId = GUINT16_FROM_LE(header->frameId);
531 header->headerCrc1 = GUINT16_FROM_LE(header->headerCrc1);
532 header->headerCrc2 = GUINT16_FROM_LE(header->headerCrc2);
533 header->payloadLength = GUINT16_FROM_LE(header->payloadLength);
534 header->payloadLengthValid = GUINT16_FROM_LE(header->payloadLengthValid);
535 header->cycle = GUINT16_FROM_LE(header->cycle);
536 header->tag = GUINT32_FROM_LE(header->tag);
537 header->data = GUINT32_FROM_LE(header->data);
538 header->frameFlags = GUINT32_FROM_LE(header->frameFlags);
539 header->appParameter = GUINT32_FROM_LE(header->appParameter);
540 /* this would be extra for ext format:
541 header->frameCRC = GUINT32_FROM_LE(header->frameCRC);
542 header->frameLengthInNs = GUINT32_FROM_LE(header->frameLengthInNs);
543 header->frameId1 = GUINT16_FROM_LE(header->frameId1);
544 header->pduOffset = GUINT16_FROM_LE(header->pduOffset);
545 header->blfLogMask = GUINT16_FROM_LE(header->blfLogMask);
549 static void
550 fix_endianness_blf_linmessage(blf_linmessage_t* message) {
551 message->channel = GUINT16_FROM_LE(message->channel);
552 message->crc = GUINT16_FROM_LE(message->crc);
553 /* skip the optional part
554 message->res2 = GUINT32_FROM_LE(message->res2);
558 static void
559 fix_endianness_blf_linbusevent(blf_linbusevent_t* linbusevent) {
560 linbusevent->sof = GUINT64_FROM_LE(linbusevent->sof);
561 linbusevent->eventBaudrate = GUINT32_FROM_LE(linbusevent->eventBaudrate);
562 linbusevent->channel = GUINT16_FROM_LE(linbusevent->channel);
565 static void
566 fix_endianness_blf_linsynchfieldevent(blf_linsynchfieldevent_t* linsynchfieldevent) {
567 fix_endianness_blf_linbusevent(&linsynchfieldevent->linBusEvent);
568 linsynchfieldevent->synchBreakLength = GUINT64_FROM_LE(linsynchfieldevent->synchBreakLength);
569 linsynchfieldevent->synchDelLength = GUINT64_FROM_LE(linsynchfieldevent->synchDelLength);
572 static void
573 fix_endianness_blf_linmessagedescriptor(blf_linmessagedescriptor_t* linmessagedescriptor) {
574 fix_endianness_blf_linsynchfieldevent(&linmessagedescriptor->linSynchFieldEvent);
575 linmessagedescriptor->supplierId = GUINT16_FROM_LE(linmessagedescriptor->supplierId);
576 linmessagedescriptor->messageId = GUINT16_FROM_LE(linmessagedescriptor->messageId);
579 static void
580 fix_endianness_blf_lindatabytetimestampevent(blf_lindatabytetimestampevent_t* lindatabytetimestampevent) {
581 int i;
582 fix_endianness_blf_linmessagedescriptor(&lindatabytetimestampevent->linMessageDescriptor);
583 for (i = 0; i < 9; i++) {
584 lindatabytetimestampevent->databyteTimestamps[i] = GUINT64_FROM_LE(lindatabytetimestampevent->databyteTimestamps[i]);
588 static void
589 fix_endianness_blf_linmessage2(blf_linmessage2_t* message) {
590 fix_endianness_blf_lindatabytetimestampevent(&message->linDataByteTimestampEvent);
591 message->crc = GUINT16_FROM_LE(message->crc);
592 /* skip the optional part
593 message->respBaudrate = GUINT32_FROM_LE(message->respBaudrate);
594 message->exactHeaderBaudrate = GUINT64_FROM_LE(message->exactHeaderBaudrate);
595 message->earlyStopBitOffset = GUINT32_FROM_LE(message->earlyStopBitOffset);
596 message->earlyStopBitOffsetResponse = GUINT32_FROM_LE(message->earlyStopBitOffsetResponse);
600 static void
601 fix_endianness_blf_lincrcerror2(blf_lincrcerror2_t* message) {
602 fix_endianness_blf_lindatabytetimestampevent(&message->linDataByteTimestampEvent);
603 message->crc = GUINT16_FROM_LE(message->crc);
604 /* skip the optional part
605 message->respBaudrate = GUINT32_FROM_LE(message->respBaudrate);
606 message->exactHeaderBaudrate = GUINT64_FROM_LE(message->exactHeaderBaudrate);
607 message->earlyStopBitOffset = GUINT32_FROM_LE(message->earlyStopBitOffset);
608 message->earlyStopBitOffsetResponse = GUINT32_FROM_LE(message->earlyStopBitOffsetResponse);
612 static void
613 fix_endianness_blf_linrcverror2(blf_linrcverror2_t* message) {
614 fix_endianness_blf_lindatabytetimestampevent(&message->linDataByteTimestampEvent);
615 /* skip the optional part
616 message->respBaudrate = GUINT32_FROM_LE(message->respBaudrate);
617 message->exactHeaderBaudrate = GUINT64_FROM_LE(message->exactHeaderBaudrate);
618 message->earlyStopBitOffset = GUINT32_FROM_LE(message->earlyStopBitOffset);
619 message->earlyStopBitOffsetResponse = GUINT32_FROM_LE(message->earlyStopBitOffsetResponse);
623 static void
624 fix_endianness_blf_linsenderror2(blf_linsenderror2_t* message) {
625 fix_endianness_blf_linmessagedescriptor(&message->linMessageDescriptor);
626 message->eoh = GUINT64_FROM_LE(message->eoh);
627 /* skip the optional part
628 message->exactHeaderBaudrate = GUINT64_FROM_LE(message->exactHeaderBaudrate);
629 message->earlyStopBitOffset = GUINT32_FROM_LE(message->earlyStopBitOffset);
633 static void
634 fix_endianness_blf_linwakeupevent2(blf_linwakeupevent2_t* message) {
635 fix_endianness_blf_linbusevent(&message->linBusEvent);
638 static void
639 fix_endianness_blf_apptext_header(blf_apptext_t *header) {
640 header->source = GUINT32_FROM_LE(header->source);
641 header->reservedAppText1 = GUINT32_FROM_LE(header->reservedAppText1);
642 header->textLength = GUINT32_FROM_LE(header->textLength);
643 header->reservedAppText2 = GUINT32_FROM_LE(header->reservedAppText2);
646 static void
647 fix_endianness_blf_ethernet_status_header(blf_ethernet_status_t* header) {
648 header->channel = GUINT16_FROM_LE(header->channel);
649 header->flags = GUINT16_FROM_LE(header->flags);
650 /*uint8_t linkStatus;*/
651 /*uint8_t ethernetPhy;*/
652 /*uint8_t duplex;*/
653 /*uint8_t mdi;*/
654 /*uint8_t connector;*/
655 /*uint8_t clockMode;*/
656 /*uint8_t pairs;*/
657 /*uint8_t hardwareChannel;*/
658 header->bitrate = GUINT32_FROM_LE(header->bitrate);
661 static void
662 fix_endianness_blf_ethernet_phystate_header(blf_ethernet_phystate_t* header) {
663 header->channel = GUINT16_FROM_LE(header->channel);
664 header->flags = GUINT16_FROM_LE(header->flags);
667 static void
668 blf_init_logcontainer(blf_log_container_t *tmp) {
669 tmp->infile_start_pos = 0;
670 tmp->infile_length = 0;
671 tmp->infile_data_start = 0;
672 tmp->real_start_pos = 0;
673 tmp->real_length = 0;
674 tmp->real_data = NULL;
675 tmp->compression_method = 0;
679 blf_logcontainers_cmp(const void *a, const void *b) {
680 const blf_log_container_t* container_a = (blf_log_container_t*)a;
681 const blf_log_container_t* container_b = (blf_log_container_t*)b;
683 if (container_a->real_start_pos < container_b->real_start_pos) {
684 return -1;
686 else if (container_a->real_start_pos > container_b->real_start_pos) {
687 return 1;
689 else {
690 return 0;
695 blf_logcontainers_search(const void *a, const void *b) {
696 const blf_log_container_t* container_a = (blf_log_container_t*)a;
697 uint64_t pos = *(uint64_t*)b;
699 if (container_a->real_start_pos > pos) {
700 return 1;
702 else if (pos >= container_a->real_start_pos + container_a->real_length) {
703 return -1;
705 else {
706 return 0;
710 /** Ensures the given log container is in memory
712 * If the log container already is not already in memory,
713 * it reads it from the current seek position, allocating a
714 * properly sized buffer.
715 * The file offset must be set to the start of the container
716 * data (container->infile_data_start) before calling this function.
718 static bool
719 blf_pull_logcontainer_into_memory(blf_params_t *params, blf_log_container_t *container, int *err, char **err_info) {
721 if (container == NULL) {
722 *err = WTAP_ERR_INTERNAL;
723 *err_info = ws_strdup("blf_pull_logcontainer_into_memory called with NULL container");
724 return false;
727 if (container->real_data != NULL) {
728 return true;
731 /* pull compressed data into buffer */
732 if (container->infile_start_pos < 0) {
734 * XXX - does this represent a bug (WTAP_ERR_INTERNAL) or a
735 * malformed file (WTAP_ERR_BAD_FILE)?
737 *err = WTAP_ERR_INTERNAL;
738 *err_info = ws_strdup_printf("blf_pull_logcontainer_into_memory: container.infile_start_pos (%" PRId64 ") < 0",
739 container->infile_start_pos);
740 return false;
742 if (container->infile_data_start < (uint64_t)container->infile_start_pos) {
744 * XXX - does this represent a bug (WTAP_ERR_INTERNAL) or a
745 * malformed file (WTAP_ERR_BAD_FILE)?
747 *err = WTAP_ERR_INTERNAL;
748 *err_info = ws_strdup_printf("blf_pull_logcontainer_into_memory: container.infile_data_start (%" PRIu64 ") < container.infile_start_pos (%" PRId64 ")",
749 container->infile_data_start, container->infile_start_pos);
750 return false;
752 if (container->infile_length < container->infile_data_start - (uint64_t)container->infile_start_pos) {
754 * XXX - does this represent a bug (WTAP_ERR_INTERNAL) or a
755 * malformed file (WTAP_ERR_BAD_FILE)?
757 *err = WTAP_ERR_INTERNAL;
758 *err_info = ws_strdup_printf("blf_pull_logcontainer_into_memory: container.infile_length (%" PRIu64 ") < (container.infile_data_start (%" PRIu64 ") - container.infile_start_pos (%" PRId64 ")) = %" PRIu64,
759 container->infile_length,
760 container->infile_data_start, container->infile_start_pos,
761 container->infile_data_start - (uint64_t)container->infile_start_pos);
762 return false;
764 uint64_t data_length = container->infile_length - (container->infile_data_start - (uint64_t)container->infile_start_pos);
765 if (data_length > UINT_MAX) {
767 * XXX - does this represent a bug (WTAP_ERR_INTERNAL) or a
768 * malformed file (WTAP_ERR_BAD_FILE)?
770 *err = WTAP_ERR_INTERNAL;
771 *err_info = ws_strdup_printf("blf_pull_logcontainer_into_memory: data_length (%" PRIu64 ") > UINT_MAX",
772 data_length);
773 return false;
776 if (container->real_length == 0) {
777 ws_info("blf_pull_logcontainer_into_memory: found container with 0 length");
778 /* Skip empty container */
779 if (!wtap_read_bytes_or_eof(params->fh, NULL, (unsigned int)data_length, err, err_info)) {
780 if (*err == WTAP_ERR_SHORT_READ) {
782 * XXX - our caller will turn this into an EOF.
783 * How *should* it be treated?
784 * For now, we turn it into Yet Another Internal Error,
785 * pending having better documentation of the file
786 * format.
788 *err = WTAP_ERR_INTERNAL;
789 *err_info = ws_strdup("blf_pull_logcontainer_into_memory: short read on 0-length container");
791 return false;
793 return true;
796 if (container->compression_method == BLF_COMPRESSION_NONE) {
797 unsigned char* buf = g_try_malloc((size_t)container->real_length);
798 if (buf == NULL) {
799 *err = WTAP_ERR_INTERNAL;
800 *err_info = ws_strdup("blf_pull_logcontainer_into_memory: cannot allocate memory");
801 return false;
803 if (!wtap_read_bytes_or_eof(params->fh, buf, (unsigned int)data_length, err, err_info)) {
804 g_free(buf);
805 if (*err == WTAP_ERR_SHORT_READ) {
807 * XXX - our caller will turn this into an EOF.
808 * How *should* it be treated?
809 * For now, we turn it into Yet Another Internal Error,
810 * pending having better documentation of the file
811 * format.
813 *err = WTAP_ERR_INTERNAL;
814 *err_info = ws_strdup("blf_pull_logcontainer_into_memory: short read on uncompressed data");
816 return false;
818 container->real_data = buf;
819 return true;
822 else if (container->compression_method == BLF_COMPRESSION_ZLIB) {
823 #if defined (HAVE_ZLIB) || defined (HAVE_ZLIBNG)
824 unsigned char *compressed_data = g_try_malloc((size_t)data_length);
825 if (compressed_data == NULL) {
826 *err = WTAP_ERR_INTERNAL;
827 *err_info = ws_strdup("blf_pull_logcontainer_into_memory: cannot allocate memory");
828 return false;
830 if (!wtap_read_bytes_or_eof(params->fh, compressed_data, (unsigned int)data_length, err, err_info)) {
831 g_free(compressed_data);
832 if (*err == WTAP_ERR_SHORT_READ) {
834 * XXX - our caller will turn this into an EOF.
835 * How *should* it be treated?
836 * For now, we turn it into Yet Another Internal Error,
837 * pending having better documentation of the file
838 * format.
840 *err = WTAP_ERR_INTERNAL;
841 *err_info = ws_strdup("blf_pull_logcontainer_into_memory: short read on compressed data");
843 return false;
846 unsigned char *buf = g_try_malloc((size_t)container->real_length);
847 if (buf == NULL) {
848 g_free(compressed_data);
849 *err = WTAP_ERR_INTERNAL;
850 *err_info = ws_strdup("blf_pull_logcontainer_into_memory: cannot allocate memory");
851 return false;
853 zlib_stream infstream = {0};
855 infstream.avail_in = (unsigned int)data_length;
856 infstream.next_in = compressed_data;
857 infstream.avail_out = (unsigned int)container->real_length;
858 infstream.next_out = buf;
860 /* the actual DE-compression work. */
861 if (Z_OK != ZLIB_PREFIX(inflateInit)(&infstream)) {
863 * XXX - check the error code and handle this appropriately.
865 g_free(buf);
866 g_free(compressed_data);
867 *err = WTAP_ERR_INTERNAL;
868 if (infstream.msg != NULL) {
869 *err_info = ws_strdup_printf("blf_pull_logcontainer_into_memory: inflateInit failed for LogContainer, message\"%s\"",
870 infstream.msg);
871 } else {
872 *err_info = ws_strdup("blf_pull_logcontainer_into_memory: inflateInit failed for LogContainer");
874 ws_debug("inflateInit failed for LogContainer");
875 if (infstream.msg != NULL) {
876 ws_debug("inflateInit returned: \"%s\"", infstream.msg);
878 return false;
881 int ret = ZLIB_PREFIX(inflate)(&infstream, Z_NO_FLUSH);
882 /* Z_OK should not happen here since we know how big the buffer should be */
883 if (Z_STREAM_END != ret) {
884 switch (ret) {
886 case Z_NEED_DICT:
887 *err = WTAP_ERR_DECOMPRESS;
888 *err_info = ws_strdup("preset dictionary needed");
889 break;
891 case Z_STREAM_ERROR:
892 *err = WTAP_ERR_INTERNAL;
893 *err_info = ws_strdup_printf("blf_pull_logcontainer_into_memory: Z_STREAM_ERROR from inflate(), message \"%s\"",
894 (infstream.msg != NULL) ? infstream.msg : "(none)");
895 break;
897 case Z_MEM_ERROR:
898 /* This means "not enough memory". */
899 *err = ENOMEM;
900 *err_info = NULL;
901 break;
903 case Z_DATA_ERROR:
904 /* This means "deflate stream invalid" */
905 *err = WTAP_ERR_DECOMPRESS;
906 *err_info = (infstream.msg != NULL) ? ws_strdup(infstream.msg) : NULL;
907 break;
909 case Z_BUF_ERROR:
910 /* XXX - this is recoverable; what should we do here? */
911 *err = WTAP_ERR_INTERNAL;
912 *err_info = ws_strdup_printf("blf_pull_logcontainer_into_memory: Z_BUF_ERROR from inflate(), message \"%s\"",
913 (infstream.msg != NULL) ? infstream.msg : "(none)");
914 break;
916 case Z_VERSION_ERROR:
917 *err = WTAP_ERR_INTERNAL;
918 *err_info = ws_strdup_printf("blf_pull_logcontainer_into_memory: Z_VERSION_ERROR from inflate(), message \"%s\"",
919 (infstream.msg != NULL) ? infstream.msg : "(none)");
920 break;
922 default:
923 *err = WTAP_ERR_INTERNAL;
924 *err_info = ws_strdup_printf("blf_pull_logcontainer_into_memory: unexpected error %d from inflate(), message \"%s\"",
925 ret,
926 (infstream.msg != NULL) ? infstream.msg : "(none)");
927 break;
929 g_free(buf);
930 g_free(compressed_data);
931 ws_debug("inflate failed (return code %d) for LogContainer", ret);
932 if (infstream.msg != NULL) {
933 ws_debug("inflate returned: \"%s\"", infstream.msg);
935 /* Free up any dynamically-allocated memory in infstream */
936 ZLIB_PREFIX(inflateEnd)(&infstream);
937 return false;
940 if (Z_OK != ZLIB_PREFIX(inflateEnd)(&infstream)) {
942 * The zlib manual says this only returns Z_OK on success
943 * and Z_STREAM_ERROR if the stream state was inconsistent.
945 * It's not clear what useful information can be reported
946 * for Z_STREAM_ERROR; a look at the 1.2.11 source indicates
947 * that no string is returned to indicate what the problem
948 * was.
950 * It's also not clear what to do about infstream if this
951 * fails.
953 *err = WTAP_ERR_INTERNAL;
954 *err_info = ws_strdup("blf_pull_logcontainer_into_memory: inflateEnd failed for LogContainer");
955 g_free(buf);
956 g_free(compressed_data);
957 ws_debug("inflateEnd failed for LogContainer");
958 if (infstream.msg != NULL) {
959 ws_debug("inflateEnd returned: \"%s\"", infstream.msg);
961 return false;
964 g_free(compressed_data);
965 container->real_data = buf;
966 return true;
967 #else
968 (void) params;
969 *err = WTAP_ERR_DECOMPRESSION_NOT_SUPPORTED;
970 *err_info = ws_strdup("blf_pull_logcontainer_into_memory: reading gzip-compressed containers isn't supported");
971 return false;
972 #endif
975 return false;
978 /** Finds the next log container starting at the current file offset
980 * Adds the container to the containers array for later access
982 static bool
983 blf_find_next_logcontainer(blf_params_t* params, int* err, char** err_info) {
984 blf_blockheader_t header;
985 blf_logcontainerheader_t logcontainer_header;
986 blf_log_container_t tmp;
987 unsigned char* header_ptr;
988 unsigned int i;
990 uint64_t current_real_start;
991 if (params->blf_data->log_containers->len == 0) {
992 current_real_start = 0;
994 else {
995 const blf_log_container_t* container = &g_array_index(params->blf_data->log_containers, blf_log_container_t, params->blf_data->log_containers->len - 1);
996 current_real_start = container->real_start_pos + container->real_length;
999 header_ptr = (unsigned char*)&header;
1000 i = 0;
1002 /** Find Object
1004 * We read one byte at a time so that we don't have to seek backward (allows us to do a linear read)
1006 while (i < sizeof(blf_obj_magic)) {
1007 if (!wtap_read_bytes_or_eof(params->fh, &header_ptr[i], 1, err, err_info)) {
1008 ws_debug("we found end of file");
1009 return false;
1011 if (header_ptr[i] != blf_obj_magic[i]) {
1012 if (params->pipe) {
1013 ws_debug("container object magic is not LOBJ");
1015 else {
1016 ws_debug("container object magic is not LOBJ (pos: 0x%" PRIx64 ")", file_tell(params->fh) - 1);
1018 if (i > 0) {
1019 int j = i;
1021 while (memcmp(&header_ptr[i - j + 1], blf_obj_magic, j)) {
1022 /* Check if the last j bytes match the first j bytes of the magic */
1023 j--;
1026 /* The last j bytes match, and the first j bytes are already in the buffer, since j<=i */
1027 i = j;
1030 else {
1031 /* Character matches */
1032 i++;
1036 if (!wtap_read_bytes_or_eof(params->fh, &header.header_length, sizeof(blf_blockheader_t) - sizeof(blf_obj_magic), err, err_info)) {
1037 ws_debug("we found end of file");
1038 return false;
1041 fix_endianness_blf_blockheader(&header);
1043 if (header.header_length < sizeof(blf_blockheader_t)) {
1044 *err = WTAP_ERR_BAD_FILE;
1045 *err_info = ws_strdup("blf: header length too short while looking for object");
1046 return false;
1049 if (header.header_type != BLF_HEADER_TYPE_DEFAULT) {
1050 *err = WTAP_ERR_UNSUPPORTED;
1051 *err_info = ws_strdup_printf("blf: unknown header type (%u), I know only BLF_HEADER_TYPE_DEFAULT (1)", header.header_type);
1052 return false;
1055 if (header.object_length < header.header_length) {
1056 *err = WTAP_ERR_BAD_FILE;
1057 *err_info = ws_strdup("blf: header object length less than header length while looking for objects");
1058 return false;
1061 if (header.object_type == BLF_OBJTYPE_LOG_CONTAINER) {
1062 /* skip unknown header part if needed */
1063 if (header.header_length > sizeof(blf_blockheader_t)) {
1064 /* seek over unknown header part */
1065 if (!wtap_read_bytes(params->fh, NULL, header.header_length - sizeof(blf_blockheader_t), err, err_info)) {
1066 ws_debug("error skipping unknown header bytes in log container");
1067 return false;
1071 /* Read the log container header */
1072 if (!wtap_read_bytes_or_eof(params->fh, &logcontainer_header, sizeof(blf_logcontainerheader_t), err, err_info)) {
1073 ws_debug("not enough bytes for log container header");
1074 return false;
1077 fix_endianness_blf_logcontainerheader(&logcontainer_header);
1079 blf_init_logcontainer(&tmp);
1081 if (params->pipe) {
1082 tmp.infile_start_pos = 0;
1083 tmp.infile_data_start = sizeof(blf_logcontainerheader_t) + header.header_length;
1085 else {
1086 tmp.infile_data_start = file_tell(params->fh);
1087 tmp.infile_start_pos = tmp.infile_data_start - sizeof(blf_logcontainerheader_t) - header.header_length;
1089 tmp.infile_length = header.object_length;
1091 tmp.real_start_pos = current_real_start;
1092 tmp.real_length = logcontainer_header.uncompressed_size;
1093 tmp.compression_method = logcontainer_header.compression_method;
1095 ws_debug("found log container with real_pos=0x%" PRIx64 ", real_length=0x%" PRIx64, tmp.real_start_pos, tmp.real_length);
1097 else {
1098 ws_debug("found BLF object without log container");
1100 /* Create a fake log container for the lone object.
1101 * In order to avoid seeking backwards, we need to pull the fake log container now.
1103 unsigned char* buf = g_try_malloc((size_t)header.object_length);
1104 if (buf == NULL) {
1106 * XXX - we need an "out of memory" error code here.
1108 *err = WTAP_ERR_INTERNAL;
1109 *err_info = ws_strdup("blf_find_next_logcontainer: cannot allocate memory");
1110 return false;
1113 memcpy(buf, &header, sizeof(blf_blockheader_t));
1115 if (header.object_length > sizeof(blf_blockheader_t)) {
1116 if (!wtap_read_bytes(params->fh, buf + sizeof(blf_blockheader_t), header.object_length - sizeof(blf_blockheader_t), err, err_info)) {
1117 g_free(buf);
1118 ws_debug("cannot pull object without log container");
1119 return false;
1123 blf_init_logcontainer(&tmp);
1125 tmp.infile_start_pos = params->pipe ? 0 : (file_tell(params->fh) - header.object_length);
1126 tmp.infile_data_start = tmp.infile_start_pos;
1127 tmp.infile_length = header.object_length;
1129 tmp.real_start_pos = current_real_start;
1130 tmp.real_length = header.object_length;
1131 tmp.compression_method = BLF_COMPRESSION_NONE;
1133 tmp.real_data = buf;
1135 ws_debug("found non-log-container object with real_pos=0x%" PRIx64 ", real_length=0x%" PRIx64, tmp.real_start_pos, tmp.real_length);
1138 g_array_append_val(params->blf_data->log_containers, tmp);
1140 return true;
1143 static bool
1144 // NOLINTNEXTLINE(misc-no-recursion)
1145 blf_pull_next_logcontainer(blf_params_t* params, int* err, char** err_info) {
1146 blf_log_container_t* container;
1148 if (!blf_find_next_logcontainer(params, err, err_info)) {
1149 return false;
1152 /* Is there a next log container to pull? */
1153 if (params->blf_data->log_containers->len == 0) {
1154 /* No. */
1155 return false;
1158 container = &g_array_index(params->blf_data->log_containers, blf_log_container_t, params->blf_data->log_containers->len - 1);
1159 if (!blf_pull_logcontainer_into_memory(params, container, err, err_info)) {
1160 if (*err == WTAP_ERR_DECOMPRESS) {
1161 report_warning("Error while decompressing BLF log container number %u (file pos. 0x%" PRIx64 "): %s",
1162 params->blf_data->log_containers->len - 1, container->infile_start_pos, *err_info ? *err_info : "(none)");
1163 *err = 0;
1164 g_free(*err_info);
1165 *err_info = NULL;
1167 /* Skip this log container and try to get the next one. */
1168 g_array_remove_index(params->blf_data->log_containers, params->blf_data->log_containers->len - 1);
1169 /* Calling blf_pull_logcontainer_into_memory advances the file pointer. Eventually we will reach the end of the file and stop recursing. */
1170 return blf_pull_next_logcontainer(params, err, err_info);
1173 return false;
1176 return true;
1179 static bool
1180 blf_read_bytes_or_eof(blf_params_t *params, uint64_t real_pos, void *target_buffer, uint64_t count, int *err, char **err_info) {
1181 blf_log_container_t* container;
1182 unsigned container_index;
1184 uint64_t end_pos = real_pos + count;
1186 uint64_t copied = 0;
1187 uint64_t data_left;
1188 uint64_t start_in_buf;
1190 unsigned char *buf = (unsigned char *)target_buffer;
1192 if (count == 0) {
1193 ws_debug("called blf_read_bytes_or_eof with 0 count");
1194 return false;
1197 if (count > UINT32_MAX) {
1198 ws_debug("trying to read too many bytes");
1199 return false;
1202 if (params->random) {
1204 * Do a binary search for the container in which real_pos
1205 * is included.
1207 if (!g_array_binary_search(params->blf_data->log_containers, &real_pos, blf_logcontainers_search, &container_index)) {
1209 * XXX - why is this treated as an EOF rather than an error?
1210 * *err appears to be 0, which means our caller treats it as an
1211 * EOF, at least when reading the log object header.
1213 ws_debug("cannot read data because start position cannot be mapped");
1214 return false;
1216 container = &g_array_index(params->blf_data->log_containers, blf_log_container_t, container_index);
1218 else {
1219 if (params->blf_data->log_containers->len == 0) {
1221 * This is the first (linear) pass, and we haven't yet
1222 * added any containers. Pull the next log container
1223 * into memory, so that the array isn't empty.
1225 if (!blf_pull_next_logcontainer(params, err, err_info)) {
1226 return false;
1231 * Search backwards in the array, from the last entry to the
1232 * first, to find the log container in which real_pos is
1233 * included.
1235 container_index = params->blf_data->log_containers->len;
1236 do {
1237 container = &g_array_index(params->blf_data->log_containers, blf_log_container_t, --container_index);
1238 } while (real_pos < container->real_start_pos && container_index > 0); /* For some reason we skipped past the correct container */
1241 while (real_pos < end_pos) {
1243 while (real_pos >= container->real_start_pos + container->real_length) {
1244 container_index++;
1245 if (!params->random) { /* First (linear) pass */
1246 if (!blf_pull_next_logcontainer(params, err, err_info)) {
1247 return false;
1250 if (container_index >= params->blf_data->log_containers->len) {
1251 ws_debug("cannot find real_pos in container");
1252 return false;
1254 container = &g_array_index(params->blf_data->log_containers, blf_log_container_t, container_index);
1255 if (real_pos < container->real_start_pos) {
1256 ws_debug("cannot find real_pos in container");
1257 return false;
1261 if (real_pos < container->real_start_pos) {
1262 ws_debug("cannot find real_pos in container");
1263 return false;
1266 start_in_buf = real_pos - container->real_start_pos;
1268 if (params->random) {
1269 if (file_seek(params->fh, container->infile_data_start, SEEK_SET, err) == -1) {
1270 return false;
1272 if (!blf_pull_logcontainer_into_memory(params, container, err, err_info)) {
1273 return false;
1277 data_left = container->real_length - start_in_buf;
1279 if (data_left < (count - copied)) {
1280 memcpy(buf + copied, container->real_data + start_in_buf, data_left);
1281 copied += data_left;
1282 real_pos += data_left;
1284 else {
1285 memcpy(buf + copied, container->real_data + start_in_buf, count - copied);
1286 return true;
1292 * XXX - does this represent a bug (WTAP_ERR_INTERNAL) or a
1293 * malformed file (WTAP_ERR_BAD_FILE)?
1295 *err = WTAP_ERR_INTERNAL;
1296 *err_info = ws_strdup("blf_read_bytes_or_eof: ran out of containers");
1297 return false;
1300 static bool
1301 blf_read_bytes(blf_params_t *params, uint64_t real_pos, void *target_buffer, uint64_t count, int *err, char **err_info) {
1302 if (!blf_read_bytes_or_eof(params, real_pos, target_buffer, count, err, err_info)) {
1303 if (*err == 0) {
1304 *err = WTAP_ERR_SHORT_READ;
1306 return false;
1308 return true;
1311 static void
1312 blf_init_rec(blf_params_t *params, uint32_t flags, uint64_t object_timestamp, int pkt_encap, uint16_t channel, uint16_t hwchannel, unsigned caplen, unsigned len) {
1313 params->rec->rec_type = REC_TYPE_PACKET;
1314 params->rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
1315 params->rec->presence_flags = WTAP_HAS_CAP_LEN | WTAP_HAS_INTERFACE_ID;
1316 params->rec->ts_rel_cap_valid = false;
1317 switch (flags) {
1318 case BLF_TIMESTAMP_RESOLUTION_10US:
1319 params->rec->presence_flags |= WTAP_HAS_TS;
1320 params->rec->tsprec = WTAP_TSPREC_10_USEC;
1321 object_timestamp *= 10000;
1322 object_timestamp += params->blf_data->start_offset_ns;
1323 params->rec->ts_rel_cap_valid = true;
1324 break;
1326 case BLF_TIMESTAMP_RESOLUTION_1NS:
1327 params->rec->presence_flags |= WTAP_HAS_TS;
1328 params->rec->tsprec = WTAP_TSPREC_NSEC;
1329 object_timestamp += params->blf_data->start_offset_ns;
1330 params->rec->ts_rel_cap_valid = true;
1331 break;
1333 default:
1334 /* Metadata objects have both flags and timestamp equal to zero, so that combination is not an error. */
1335 if (flags != 0 || object_timestamp != 0) {
1337 * XXX - report this as an error?
1339 * Or provide a mechanism to allow file readers to report
1340 * a warning (an error that the reader tries to work
1341 * around and that the caller should report)?
1343 ws_debug("Unknown combination of flags and timestamp (0x%x, %" PRIu64 ")", flags, object_timestamp);
1344 object_timestamp = 0;
1346 break;
1348 params->rec->ts.secs = object_timestamp / (1000 * 1000 * 1000);
1349 params->rec->ts.nsecs = object_timestamp % (1000 * 1000 * 1000);
1350 params->rec->rec_header.packet_header.caplen = caplen;
1351 params->rec->rec_header.packet_header.len = len;
1353 nstime_t tmp_ts;
1354 tmp_ts.secs = params->blf_data->start_offset_ns / (1000 * 1000 * 1000);
1355 tmp_ts.nsecs = params->blf_data->start_offset_ns % (1000 * 1000 * 1000);
1356 nstime_delta(&params->rec->ts_rel_cap, &params->rec->ts, &tmp_ts);
1358 params->rec->rec_header.packet_header.pkt_encap = pkt_encap;
1359 params->rec->rec_header.packet_header.interface_id = blf_lookup_interface(params, pkt_encap, channel, hwchannel, NULL);
1361 /* TODO: before we had to remove comments and verdict here to not leak memory but APIs have changed ... */
1364 static void
1365 blf_add_direction_option(blf_params_t *params, uint16_t direction) {
1366 uint32_t tmp = 0; /* dont care */
1368 switch (direction) {
1369 case BLF_DIR_RX:
1370 tmp = 1; /* inbound */
1371 break;
1372 case BLF_DIR_TX:
1373 case BLF_DIR_TX_RQ:
1374 tmp = 2; /* outbound */
1375 break;
1378 /* pcapng.c: #define OPT_EPB_FLAGS 0x0002 */
1379 wtap_block_add_uint32_option(params->rec->block, 0x0002, tmp);
1382 static bool
1383 blf_read_log_object_header(blf_params_t *params, int *err, char **err_info, int64_t header2_start, int64_t data_start, blf_logobjectheader_t *logheader) {
1384 if (data_start - header2_start < (int64_t)sizeof(blf_logobjectheader_t)) {
1385 *err = WTAP_ERR_BAD_FILE;
1386 *err_info = ws_strdup("blf: not enough bytes for log object header");
1387 ws_debug("not enough bytes for timestamp header");
1388 return false;
1391 if (!blf_read_bytes_or_eof(params, header2_start, logheader, sizeof(*logheader), err, err_info)) {
1392 ws_debug("not enough bytes for logheader");
1393 return false;
1395 fix_endianness_blf_logobjectheader(logheader);
1396 return true;
1399 static bool
1400 blf_read_log_object_header2(blf_params_t *params, int *err, char **err_info, int64_t header2_start, int64_t data_start, blf_logobjectheader2_t *logheader) {
1401 if (data_start - header2_start < (int64_t)sizeof(blf_logobjectheader2_t)) {
1402 *err = WTAP_ERR_BAD_FILE;
1403 *err_info = ws_strdup("blf: not enough bytes for log object header");
1404 ws_debug("not enough bytes for timestamp header");
1405 return false;
1408 if (!blf_read_bytes_or_eof(params, header2_start, logheader, sizeof(*logheader), err, err_info)) {
1409 ws_debug("not enough bytes for logheader");
1410 return false;
1412 fix_endianness_blf_logobjectheader2(logheader);
1413 return true;
1416 static bool
1417 blf_read_log_object_header3(blf_params_t *params, int *err, char **err_info, int64_t header2_start, int64_t data_start, blf_logobjectheader3_t *logheader) {
1418 if (data_start - header2_start < (int64_t)sizeof(blf_logobjectheader3_t)) {
1419 *err = WTAP_ERR_BAD_FILE;
1420 *err_info = ws_strdup("blf: not enough bytes for log object header");
1421 ws_debug("not enough bytes for timestamp header");
1422 return false;
1425 if (!blf_read_bytes_or_eof(params, header2_start, logheader, sizeof(*logheader), err, err_info)) {
1426 ws_debug("not enough bytes for logheader");
1427 return false;
1429 fix_endianness_blf_logobjectheader3(logheader);
1430 return true;
1433 static bool
1434 blf_read_ethernetframe(blf_params_t *params, int *err, char **err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp) {
1435 blf_ethernetframeheader_t ethheader;
1436 uint8_t tmpbuf[18];
1437 unsigned caplen, len;
1439 if (object_length < (data_start - block_start) + (int) sizeof(blf_ethernetframeheader_t)) {
1440 *err = WTAP_ERR_BAD_FILE;
1441 *err_info = ws_strdup("blf: ETHERNET_FRAME: not enough bytes for ethernet frame header in object");
1442 ws_debug("not enough bytes for ethernet frame header in object");
1443 return false;
1446 if (!blf_read_bytes(params, data_start, &ethheader, sizeof(ethheader), err, err_info)) {
1447 ws_debug("not enough bytes for ethernet frame header in file");
1448 return false;
1450 fix_endianness_blf_ethernetframeheader(&ethheader);
1453 * BLF breaks up and reorders the Ethernet header and VLAN tag fields.
1454 * This is a really bad design and makes this format one of the worst.
1455 * If you want a fast format that keeps your data intact, avoid this format!
1456 * So, lets hope we can reconstruct the original packet successfully.
1459 tmpbuf[0] = ethheader.dst_addr[0];
1460 tmpbuf[1] = ethheader.dst_addr[1];
1461 tmpbuf[2] = ethheader.dst_addr[2];
1462 tmpbuf[3] = ethheader.dst_addr[3];
1463 tmpbuf[4] = ethheader.dst_addr[4];
1464 tmpbuf[5] = ethheader.dst_addr[5];
1465 tmpbuf[6] = ethheader.src_addr[0];
1466 tmpbuf[7] = ethheader.src_addr[1];
1467 tmpbuf[8] = ethheader.src_addr[2];
1468 tmpbuf[9] = ethheader.src_addr[3];
1469 tmpbuf[10] = ethheader.src_addr[4];
1470 tmpbuf[11] = ethheader.src_addr[5];
1472 if (ethheader.tpid != 0 && ethheader.tci != 0) {
1473 tmpbuf[12] = (ethheader.tpid & 0xff00) >> 8;
1474 tmpbuf[13] = (ethheader.tpid & 0x00ff);
1475 tmpbuf[14] = (ethheader.tci & 0xff00) >> 8;
1476 tmpbuf[15] = (ethheader.tci & 0x00ff);
1477 tmpbuf[16] = (ethheader.ethtype & 0xff00) >> 8;
1478 tmpbuf[17] = (ethheader.ethtype & 0x00ff);
1479 ws_buffer_assure_space(params->buf, (size_t)18 + ethheader.payloadlength);
1480 ws_buffer_append(params->buf, tmpbuf, (size_t)18);
1481 caplen = ((uint32_t)18 + ethheader.payloadlength);
1482 len = ((uint32_t)18 + ethheader.payloadlength);
1483 } else {
1484 tmpbuf[12] = (ethheader.ethtype & 0xff00) >> 8;
1485 tmpbuf[13] = (ethheader.ethtype & 0x00ff);
1486 ws_buffer_assure_space(params->buf, (size_t)14 + ethheader.payloadlength);
1487 ws_buffer_append(params->buf, tmpbuf, (size_t)14);
1488 caplen = ((uint32_t)14 + ethheader.payloadlength);
1489 len = ((uint32_t)14 + ethheader.payloadlength);
1492 if (!blf_read_bytes(params, data_start + sizeof(blf_ethernetframeheader_t), ws_buffer_end_ptr(params->buf), ethheader.payloadlength, err, err_info)) {
1493 ws_debug("copying ethernet frame failed");
1494 return false;
1496 params->buf->first_free += ethheader.payloadlength;
1498 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_ETHERNET, ethheader.channel, UINT16_MAX, caplen, len);
1499 blf_add_direction_option(params, ethheader.direction);
1501 return true;
1504 static bool
1505 blf_read_ethernetframe_ext(blf_params_t *params, int *err, char **err_info, int64_t block_start,int64_t data_start,
1506 int64_t object_length, uint32_t flags, uint64_t object_timestamp, gboolean error) {
1507 blf_ethernetframeheader_ex_t ethheader;
1509 if (object_length < (data_start - block_start) + (int) sizeof(blf_ethernetframeheader_ex_t)) {
1510 *err = WTAP_ERR_BAD_FILE;
1511 *err_info = ws_strdup_printf("blf: %s: not enough bytes for ethernet frame header in object", error ? "ETHERNET_ERROR_EX" : "ETHERNET_FRAME_EX");
1512 ws_debug("not enough bytes for ethernet frame header in object");
1513 return false;
1516 if (!blf_read_bytes(params, data_start, &ethheader, sizeof(blf_ethernetframeheader_ex_t), err, err_info)) {
1517 ws_debug("not enough bytes for ethernet frame header in file");
1518 return false;
1520 fix_endianness_blf_ethernetframeheader_ex(&ethheader);
1522 ws_buffer_assure_space(params->buf, ethheader.frame_length);
1524 if (object_length - (data_start - block_start) - sizeof(blf_ethernetframeheader_ex_t) < ethheader.frame_length) {
1525 *err = WTAP_ERR_BAD_FILE;
1526 *err_info = ws_strdup_printf("blf: %s: frame too short", error ? "ETHERNET_ERROR_EX" : "ETHERNET_FRAME_EX");
1527 ws_debug("frame too short");
1528 return false;
1531 if (!blf_read_bytes(params, data_start + sizeof(blf_ethernetframeheader_ex_t), ws_buffer_start_ptr(params->buf), ethheader.frame_length, err, err_info)) {
1532 ws_debug("copying ethernet frame failed");
1533 return false;
1536 if (ethheader.flags & BLF_ETHERNET_EX_HARDWARECHANNEL) {
1537 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_ETHERNET, ethheader.channel, ethheader.hw_channel, ethheader.frame_length, ethheader.frame_length);
1538 wtap_block_add_uint32_option(params->rec->block, OPT_PKT_QUEUE, ethheader.hw_channel);
1540 else {
1541 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_ETHERNET, ethheader.channel, UINT16_MAX, ethheader.frame_length, ethheader.frame_length);
1544 blf_add_direction_option(params, ethheader.direction);
1546 return true;
1549 static bool
1550 blf_read_ethernet_rxerror(blf_params_t* params, int* err, char** err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp) {
1551 blf_ethernet_rxerror_t ethheader;
1553 if (object_length < (data_start - block_start) + (int)sizeof(blf_ethernet_rxerror_t)) {
1554 *err = WTAP_ERR_BAD_FILE;
1555 *err_info = ws_strdup("blf: ETHERNET_RXERROR: not enough bytes for ethernet frame header in object");
1556 ws_debug("not enough bytes for ethernet rx error header in object");
1557 return false;
1560 if (!blf_read_bytes(params, data_start, &ethheader, sizeof(blf_ethernet_rxerror_t), err, err_info)) {
1561 ws_debug("not enough bytes for ethernet rx error header in file");
1562 return false;
1564 fix_endianness_blf_ethernet_rxerror(&ethheader);
1566 ws_buffer_assure_space(params->buf, ethheader.frame_length);
1568 if (object_length - (data_start - block_start) < ethheader.frame_length) {
1569 *err = WTAP_ERR_BAD_FILE;
1570 *err_info = ws_strdup("blf: ETHERNET_RXERROR: frame too short");
1571 ws_debug("frame too short");
1572 return false;
1575 if (!blf_read_bytes(params, data_start + sizeof(blf_ethernet_rxerror_t), ws_buffer_start_ptr(params->buf), ethheader.frame_length, err, err_info)) {
1576 ws_debug("copying ethernet rx error failed");
1577 return false;
1580 if (ethheader.hw_channel != 0) { /* In this object type, a value of 0 is considered invalid. */
1581 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_ETHERNET, ethheader.channel, ethheader.hw_channel, ethheader.frame_length, ethheader.frame_length);
1582 wtap_block_add_uint32_option(params->rec->block, OPT_PKT_QUEUE, ethheader.hw_channel);
1584 else {
1585 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_ETHERNET, ethheader.channel, UINT16_MAX, ethheader.frame_length, ethheader.frame_length);
1587 blf_add_direction_option(params, ethheader.direction);
1589 return true;
1593 * XXX - provide radio information to our caller in the pseudo-header.
1595 static bool
1596 blf_read_wlanframe(blf_params_t* params, int* err, char** err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp) {
1597 blf_wlanframeheader_t wlanheader;
1599 if (object_length < (data_start - block_start) + (int)sizeof(blf_wlanframeheader_t)) {
1600 *err = WTAP_ERR_BAD_FILE;
1601 *err_info = ws_strdup("blf: WLAN_FRAME: not enough bytes for wlan frame header in object");
1602 ws_debug("not enough bytes for wlan frame header in object");
1603 return false;
1606 if (!blf_read_bytes(params, data_start, &wlanheader, sizeof(blf_wlanframeheader_t), err, err_info)) {
1607 ws_debug("not enough bytes for wlan frame header in file");
1608 return false;
1610 fix_endianness_blf_wlanframeheader(&wlanheader);
1612 ws_buffer_assure_space(params->buf, wlanheader.frame_length);
1614 if (object_length - (data_start - block_start) - sizeof(blf_wlanframeheader_t) < wlanheader.frame_length) {
1615 *err = WTAP_ERR_BAD_FILE;
1616 *err_info = ws_strdup("blf: WLAN_FRAME: frame too short");
1617 ws_debug("frame too short");
1618 return false;
1621 if (!blf_read_bytes(params, data_start + sizeof(blf_wlanframeheader_t), ws_buffer_start_ptr(params->buf), wlanheader.frame_length, err, err_info)) {
1622 ws_debug("copying wlan frame failed");
1623 return false;
1626 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_IEEE_802_11, wlanheader.channel, UINT16_MAX, wlanheader.frame_length, wlanheader.frame_length);
1627 blf_add_direction_option(params, wlanheader.direction);
1629 return true;
1632 static uint8_t can_dlc_to_length[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8 };
1633 static uint8_t canfd_dlc_to_length[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64 };
1635 static bool
1636 blf_can_fill_buf_and_rec(blf_params_t *params, int *err, char **err_info, uint32_t canid, uint8_t payload_length, uint8_t payload_length_valid, uint64_t start_position,
1637 uint32_t flags, uint64_t object_timestamp, uint16_t channel, uint8_t canfd_flags) {
1638 uint8_t tmpbuf[8];
1639 unsigned caplen, len;
1641 tmpbuf[0] = (canid & 0xff000000) >> 24;
1642 tmpbuf[1] = (canid & 0x00ff0000) >> 16;
1643 tmpbuf[2] = (canid & 0x0000ff00) >> 8;
1644 tmpbuf[3] = (canid & 0x000000ff);
1645 tmpbuf[4] = payload_length;
1646 tmpbuf[5] = canfd_flags;
1647 tmpbuf[6] = 0;
1648 tmpbuf[7] = 0;
1650 ws_buffer_assure_space(params->buf, sizeof(tmpbuf) + payload_length_valid);
1651 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
1652 caplen = sizeof(tmpbuf) + payload_length_valid;
1653 len = sizeof(tmpbuf) + payload_length;
1655 if (payload_length_valid > 0 && !blf_read_bytes(params, start_position, ws_buffer_end_ptr(params->buf), payload_length_valid, err, err_info)) {
1656 ws_debug("copying can payload failed");
1657 return false;
1659 params->buf->first_free += payload_length_valid;
1661 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_SOCKETCAN, channel, UINT16_MAX, caplen, len);
1663 return true;
1666 static bool
1667 blf_read_canmessage(blf_params_t *params, int *err, char **err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp, bool can_message2) {
1668 blf_canmessage_t canheader;
1669 blf_canmessage2_trailer_t can2trailer;
1671 uint32_t canid;
1672 uint8_t payload_length;
1674 if (object_length < (data_start - block_start) + (int) sizeof(canheader)) {
1675 *err = WTAP_ERR_BAD_FILE;
1676 *err_info = ws_strdup_printf("blf: %s: not enough bytes for can header in object",
1677 can_message2 ? "CAN_MESSAGE2" : "CAN_MESSAGE");
1678 ws_debug("not enough bytes for can header in object");
1679 return false;
1682 if (!blf_read_bytes(params, data_start, &canheader, sizeof(canheader), err, err_info)) {
1683 ws_debug("not enough bytes for can header in file");
1684 return false;
1686 fix_endianness_blf_canmessage(&canheader);
1688 canheader.dlc &= 0x0f;
1690 payload_length = canheader.dlc;
1691 if (payload_length > 8) {
1692 ws_debug("regular CAN tries more than 8 bytes? Cutting to 8!");
1693 payload_length = 8;
1696 canid = canheader.id;
1698 if ((canheader.flags & BLF_CANMESSAGE_FLAG_RTR) == BLF_CANMESSAGE_FLAG_RTR) {
1699 canid |= CAN_RTR_FLAG;
1700 payload_length = 0;
1703 if (!blf_can_fill_buf_and_rec(params, err, err_info, canid, payload_length, payload_length, data_start + sizeof(canheader), flags, object_timestamp, canheader.channel, 0)) {
1704 return false;
1707 /* actually, we do not really need the data, right now.... */
1708 if (can_message2) {
1709 if (object_length < (data_start - block_start) + (int) sizeof(canheader) + 8 + (int) sizeof(can2trailer)) {
1710 *err = WTAP_ERR_BAD_FILE;
1711 *err_info = ws_strdup("blf: CAN_MESSAGE2: not enough bytes for can message 2 trailer");
1712 ws_debug("not enough bytes for can message 2 trailer");
1713 return false;
1715 if (!blf_read_bytes(params, data_start + sizeof(canheader) + 8, &can2trailer, sizeof(can2trailer), err, err_info)) {
1716 ws_debug("not enough bytes for can message 2 trailer in file");
1717 return false;
1719 fix_endianness_blf_canmessage2_trailer(&can2trailer);
1722 blf_add_direction_option(params, (canheader.flags & BLF_CANMESSAGE_FLAG_TX) == BLF_CANMESSAGE_FLAG_TX ? BLF_DIR_TX: BLF_DIR_RX);
1724 return true;
1727 static bool
1728 blf_read_canfdmessage(blf_params_t *params, int *err, char **err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp) {
1729 blf_canfdmessage_t canheader;
1731 bool canfd;
1732 uint32_t canid;
1733 uint8_t payload_length;
1734 uint8_t payload_length_valid;
1735 uint8_t canfd_flags;
1737 if (object_length < (data_start - block_start) + (int) sizeof(canheader)) {
1738 *err = WTAP_ERR_BAD_FILE;
1739 *err_info = ws_strdup("blf: CAN_FD_MESSAGE: not enough bytes for canfd header in object");
1740 ws_debug("not enough bytes for canfd header in object");
1741 return false;
1744 if (!blf_read_bytes(params, data_start, &canheader, sizeof(canheader), err, err_info)) {
1745 ws_debug("not enough bytes for canfd header in file");
1746 return false;
1748 fix_endianness_blf_canfdmessage(&canheader);
1750 canheader.dlc &= 0x0f;
1752 canfd = (canheader.canfdflags & BLF_CANFDMESSAGE_CANFDFLAG_EDL) == BLF_CANFDMESSAGE_CANFDFLAG_EDL;
1753 if (canfd) {
1754 payload_length = canfd_dlc_to_length[canheader.dlc];
1755 canfd_flags = (canheader.canfdflags & BLF_CANFDMESSAGE_CANFDFLAG_EDL) << 2 | (canheader.canfdflags & BLF_CANFDMESSAGE_CANFDFLAG_ESI) >> 1 | (canheader.canfdflags & BLF_CANFDMESSAGE_CANFDFLAG_BRS) >> 1;
1756 } else {
1757 if (canheader.dlc > 8) {
1758 ws_debug("regular CAN tries more than 8 bytes?");
1760 payload_length = can_dlc_to_length[canheader.dlc];
1761 canfd_flags = 0;
1764 if (payload_length > canheader.validDataBytes) {
1765 ws_debug("shortening canfd payload because valid data bytes shorter!");
1766 payload_length = canheader.validDataBytes;
1769 canid = canheader.id;
1771 if (!canfd && (canheader.flags & BLF_CANMESSAGE_FLAG_RTR) == BLF_CANMESSAGE_FLAG_RTR) {
1772 canid |= CAN_RTR_FLAG;
1773 payload_length = 0; /* Should already be zero from validDataBytes */
1776 payload_length_valid = payload_length;
1778 if (payload_length_valid > object_length - (data_start - block_start) + sizeof(canheader)) {
1779 ws_debug("shortening can payload because buffer is too short!");
1780 payload_length_valid = (uint8_t)(object_length - (data_start - block_start));
1783 if (!blf_can_fill_buf_and_rec(params, err, err_info, canid, payload_length, payload_length_valid, data_start + sizeof(canheader), flags, object_timestamp, canheader.channel, canfd_flags)) {
1784 return false;
1787 blf_add_direction_option(params, (canheader.flags & BLF_CANMESSAGE_FLAG_TX) == BLF_CANMESSAGE_FLAG_TX ? BLF_DIR_TX : BLF_DIR_RX);
1789 return true;
1792 static bool
1793 blf_read_canfdmessage64(blf_params_t *params, int *err, char **err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp) {
1794 blf_canfdmessage64_t canheader;
1796 bool canfd;
1797 uint32_t canid;
1798 uint8_t payload_length;
1799 uint8_t payload_length_valid;
1800 uint8_t canfd_flags;
1802 if (object_length < (data_start - block_start) + (int) sizeof(canheader)) {
1803 *err = WTAP_ERR_BAD_FILE;
1804 *err_info = ws_strdup("blf: CAN_FD_MESSAGE_64: not enough bytes for canfd header in object");
1805 ws_debug("not enough bytes for canfd header in object");
1806 return false;
1809 if (!blf_read_bytes(params, data_start, &canheader, sizeof(canheader), err, err_info)) {
1810 ws_debug("not enough bytes for canfd header in file");
1811 return false;
1813 fix_endianness_blf_canfdmessage64(&canheader);
1815 canheader.dlc &= 0x0f;
1817 canfd = (canheader.flags & BLF_CANFDMESSAGE64_FLAG_EDL) == BLF_CANFDMESSAGE64_FLAG_EDL;
1818 if (canfd) {
1819 payload_length = canfd_dlc_to_length[canheader.dlc];
1820 canfd_flags = (canheader.flags & BLF_CANFDMESSAGE64_FLAG_EDL) >> 10 | (canheader.flags & BLF_CANFDMESSAGE64_FLAG_ESI) >> 13 | (canheader.flags & BLF_CANFDMESSAGE64_FLAG_BRS) >> 13;
1821 } else {
1822 if (canheader.dlc > 8) {
1823 ws_debug("regular CAN tries more than 8 bytes?");
1825 payload_length = can_dlc_to_length[canheader.dlc];
1826 canfd_flags = 0;
1829 if (payload_length > canheader.validDataBytes) {
1830 ws_debug("shortening canfd payload because valid data bytes shorter!");
1831 payload_length = canheader.validDataBytes;
1834 canid = canheader.id;
1836 if (!canfd && (canheader.flags & BLF_CANFDMESSAGE64_FLAG_REMOTE_FRAME) == BLF_CANFDMESSAGE64_FLAG_REMOTE_FRAME) {
1837 canid |= CAN_RTR_FLAG;
1838 payload_length = 0; /* Should already be zero from validDataBytes */
1841 payload_length_valid = payload_length;
1843 if (payload_length_valid > object_length - (data_start - block_start)) {
1844 ws_debug("shortening can payload because buffer is too short!");
1845 payload_length_valid = (uint8_t)(object_length - (data_start - block_start));
1848 if (!blf_can_fill_buf_and_rec(params, err, err_info, canid, payload_length, payload_length_valid, data_start + sizeof(canheader), flags, object_timestamp, canheader.channel, canfd_flags)) {
1849 return false;
1852 blf_add_direction_option(params, canheader.dir);
1854 return true;
1857 static bool
1858 blf_read_canerror(blf_params_t *params, int *err, char **err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp, bool overload) {
1859 blf_canerror_t canheader;
1860 uint32_t canid;
1861 uint8_t payload_length;
1862 uint8_t tmpbuf[16] = {0};
1864 if (object_length < (data_start - block_start) + (int) sizeof(canheader)) {
1865 *err = WTAP_ERR_BAD_FILE;
1866 *err_info = ws_strdup("blf: CAN_ERROR: not enough bytes for canerror header in object");
1867 ws_debug("not enough bytes for canerror header in object");
1868 return false;
1871 if (!blf_read_bytes(params, data_start, &canheader, sizeof(canheader), err, err_info)) {
1872 ws_debug("not enough bytes for canerror header in file");
1873 return false;
1875 fix_endianness_blf_canerror(&canheader);
1877 // Set CAN_ERR_FLAG in unused bits of Can ID to indicate error in socketcan
1878 canid = CAN_ERR_FLAG;
1880 // Fixed packet data length for socketcan error messages
1881 payload_length = CAN_ERR_DLC;
1883 if (overload) {
1884 tmpbuf[10] = CAN_ERR_PROT_OVERLOAD;
1885 canid |= CAN_ERR_PROT;
1888 tmpbuf[0] = (canid & 0xff000000) >> 24;
1889 tmpbuf[1] = (canid & 0x00ff0000) >> 16;
1890 tmpbuf[2] = (canid & 0x0000ff00) >> 8;
1891 tmpbuf[3] = (canid & 0x000000ff);
1892 tmpbuf[4] = payload_length;
1894 ws_buffer_assure_space(params->buf, sizeof(tmpbuf));
1895 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
1897 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_SOCKETCAN, canheader.channel, UINT16_MAX, sizeof(tmpbuf), sizeof(tmpbuf));
1898 return true;
1901 static bool
1902 blf_read_canerrorext(blf_params_t *params, int *err, char **err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp) {
1903 blf_canerrorext_t canheader;
1905 bool err_ack = false;
1906 bool err_prot = false;
1907 bool direction_tx;
1908 uint32_t canid;
1909 uint8_t payload_length;
1910 uint8_t tmpbuf[16] = {0};
1912 if (object_length < (data_start - block_start) + (int) sizeof(canheader)) {
1913 *err = WTAP_ERR_BAD_FILE;
1914 *err_info = ws_strdup("blf: CAN_ERROR_EXT: not enough bytes for canerrorext header in object");
1915 ws_debug("not enough bytes for canerrorext header in object");
1916 return false;
1919 if (!blf_read_bytes(params, data_start, &canheader, sizeof(canheader), err, err_info)) {
1920 ws_debug("not enough bytes for canerrorext header in file");
1921 return false;
1923 fix_endianness_blf_canerrorext(&canheader);
1925 if (canheader.flags & BLF_CANERROREXT_FLAG_CANCORE) {
1926 // Map Vector Can Core error codes to compareable socketcan errors
1927 switch ((canheader.errorCodeExt >> 6) & 0x3f) {
1928 case BLF_CANERROREXT_ECC_MEANING_BIT_ERROR:
1929 err_prot = true;
1930 tmpbuf[10] = CAN_ERR_PROT_BIT;
1931 break;
1932 case BLF_CANERROREXT_ECC_MEANING_FORM_ERROR:
1933 err_prot = true;
1934 tmpbuf[10] = CAN_ERR_PROT_FORM;
1935 break;
1936 case BLF_CANERROREXT_ECC_MEANING_STUFF_ERROR:
1937 err_prot = true;
1938 tmpbuf[10] = CAN_ERR_PROT_STUFF;
1939 break;
1940 case BLF_CANERROREXT_ECC_MEANING_CRC_ERROR:
1941 err_prot = true;
1942 tmpbuf[11] = CAN_ERR_PROT_LOC_CRC_SEQ;
1943 break;
1944 case BLF_CANERROREXT_ECC_MEANING_NACK_ERROR:
1945 err_ack = true;
1946 tmpbuf[11] = CAN_ERR_PROT_LOC_ACK;
1947 break;
1948 case BLF_CANERROREXT_ECC_MEANING_OVERLOAD:
1949 err_prot = true;
1950 tmpbuf[10] = CAN_ERR_PROT_OVERLOAD;
1951 break;
1952 default:
1953 err_prot = true;
1954 tmpbuf[10] = CAN_ERR_PROT_UNSPEC;
1955 break;
1957 err_ack = err_ack || (canheader.errorCodeExt & BLF_CANERROREXT_EXTECC_NOT_ACK) == 0x0;
1958 if (err_ack) {
1959 // Don't set protocol error on ack errors
1960 err_prot = false;
1964 // CanID contains error class in socketcan
1965 canid = CAN_ERR_FLAG;
1966 canid |= err_prot ? CAN_ERR_PROT : 0;
1967 canid |= err_ack ? CAN_ERR_ACK : 0;
1969 // Fixed packet data length for socketcan error messages
1970 payload_length = CAN_ERR_DLC;
1971 canheader.dlc = payload_length;
1973 tmpbuf[0] = (canid & 0xff000000) >> 24;
1974 tmpbuf[1] = (canid & 0x00ff0000) >> 16;
1975 tmpbuf[2] = (canid & 0x0000ff00) >> 8;
1976 tmpbuf[3] = (canid & 0x000000ff);
1977 tmpbuf[4] = payload_length;
1979 ws_buffer_assure_space(params->buf, sizeof(tmpbuf));
1980 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
1982 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_SOCKETCAN, canheader.channel, UINT16_MAX, sizeof(tmpbuf), sizeof(tmpbuf));
1983 if (canheader.flags & BLF_CANERROREXT_FLAG_CANCORE) {
1984 direction_tx = (canheader.errorCodeExt & BLF_CANERROREXT_EXTECC_TX) == BLF_CANERROREXT_EXTECC_TX;
1985 blf_add_direction_option(params, direction_tx ? BLF_DIR_TX: BLF_DIR_RX);
1987 return true;
1990 static bool
1991 blf_read_canfderror64(blf_params_t *params, int *err, char **err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp) {
1992 blf_canfderror64_t canheader;
1994 bool err_ack = false;
1995 bool err_prot = false;
1996 bool direction_tx;
1997 uint32_t canid;
1998 uint8_t payload_length;
1999 uint8_t tmpbuf[16] = {0};
2001 if (object_length < (data_start - block_start) + (int) sizeof(canheader)) {
2002 *err = WTAP_ERR_BAD_FILE;
2003 *err_info = ws_strdup("blf: CAN_FD_ERROR_64: not enough bytes for canfderror header in object");
2004 ws_debug("not enough bytes for canfderror header in object");
2005 return false;
2008 if (!blf_read_bytes(params, data_start, &canheader, sizeof(canheader), err, err_info)) {
2009 ws_debug("not enough bytes for canfderror header in file");
2010 return false;
2012 fix_endianness_blf_canfderror64(&canheader);
2014 if (canheader.flags & BLF_CANERROREXT_FLAG_CANCORE) {
2015 // Map Vector Can Core error codes to compareable socketcan errors
2016 switch ((canheader.errorCodeExt >> 6) & 0x3f) {
2017 case BLF_CANERROREXT_ECC_MEANING_BIT_ERROR:
2018 err_prot = true;
2019 tmpbuf[10] = CAN_ERR_PROT_BIT;
2020 break;
2021 case BLF_CANERROREXT_ECC_MEANING_FORM_ERROR:
2022 err_prot = true;
2023 tmpbuf[10] = CAN_ERR_PROT_FORM;
2024 break;
2025 case BLF_CANERROREXT_ECC_MEANING_STUFF_ERROR:
2026 err_prot = true;
2027 tmpbuf[10] = CAN_ERR_PROT_STUFF;
2028 break;
2029 case BLF_CANERROREXT_ECC_MEANING_CRC_ERROR:
2030 err_prot = true;
2031 tmpbuf[11] = CAN_ERR_PROT_LOC_CRC_SEQ;
2032 break;
2033 case BLF_CANERROREXT_ECC_MEANING_NACK_ERROR:
2034 err_ack = true;
2035 tmpbuf[11] = CAN_ERR_PROT_LOC_ACK;
2036 break;
2037 case BLF_CANERROREXT_ECC_MEANING_OVERLOAD:
2038 err_prot = true;
2039 tmpbuf[10] = CAN_ERR_PROT_OVERLOAD;
2040 break;
2041 default:
2042 err_prot = true;
2043 tmpbuf[10] = CAN_ERR_PROT_UNSPEC;
2044 break;
2046 err_ack = err_ack || (canheader.errorCodeExt & BLF_CANERROREXT_EXTECC_NOT_ACK) == 0x0;
2047 if (err_ack) {
2048 // Don't set protocol error on ack errors
2049 err_prot = false;
2053 // CanID contains error class in socketcan
2054 canid = CAN_ERR_FLAG;
2055 canid |= err_prot ? CAN_ERR_PROT : 0;
2056 canid |= err_ack ? CAN_ERR_ACK : 0;
2058 // Fixed packet data length for socketcan error messages
2059 payload_length = CAN_ERR_DLC;
2060 canheader.dlc = payload_length;
2062 tmpbuf[0] = (canid & 0xff000000) >> 24;
2063 tmpbuf[1] = (canid & 0x00ff0000) >> 16;
2064 tmpbuf[2] = (canid & 0x0000ff00) >> 8;
2065 tmpbuf[3] = (canid & 0x000000ff);
2066 tmpbuf[4] = payload_length;
2067 // Don't set FDF, ESI and BRS flags, since error messages are always encapsulated in Classic CAN frames
2069 ws_buffer_assure_space(params->buf, sizeof(tmpbuf));
2070 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2072 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_SOCKETCAN, canheader.channel, UINT16_MAX, sizeof(tmpbuf), sizeof(tmpbuf));
2073 if (canheader.flags & BLF_CANERROREXT_FLAG_CANCORE) {
2074 direction_tx = (canheader.errorCodeExt & BLF_CANERROREXT_EXTECC_TX) == BLF_CANERROREXT_EXTECC_TX;
2075 blf_add_direction_option(params, direction_tx ? BLF_DIR_TX: BLF_DIR_RX);
2077 return true;
2080 static bool
2081 blf_read_flexraydata(blf_params_t *params, int *err, char **err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp) {
2082 blf_flexraydata_t frheader;
2084 uint8_t payload_length;
2085 uint8_t payload_length_valid;
2086 uint8_t tmpbuf[7];
2087 unsigned caplen, len;
2089 if (object_length < (data_start - block_start) + (int) sizeof(frheader)) {
2090 *err = WTAP_ERR_BAD_FILE;
2091 *err_info = ws_strdup("blf: FLEXRAY_DATA: not enough bytes for flexrayheader in object");
2092 ws_debug("not enough bytes for flexrayheader in object");
2093 return false;
2096 if (!blf_read_bytes(params, data_start, &frheader, sizeof(frheader), err, err_info)) {
2097 ws_debug("not enough bytes for flexrayheader header in file");
2098 return false;
2100 fix_endianness_blf_flexraydata(&frheader);
2102 payload_length = frheader.len;
2103 payload_length_valid = payload_length;
2105 if ((frheader.len & 0x01) == 0x01) {
2106 ws_debug("reading odd length in FlexRay!?");
2109 if (payload_length_valid > object_length - (data_start - block_start) - sizeof(frheader)) {
2110 ws_debug("shortening FlexRay payload because buffer is too short!");
2111 payload_length_valid = (uint8_t)(object_length - (data_start - block_start) - sizeof(frheader));
2114 if (frheader.channel != 0 && frheader.channel != 1) {
2115 ws_debug("FlexRay supports only two channels.");
2118 /* Measurement Header */
2119 if (frheader.channel == 0) {
2120 tmpbuf[0] = BLF_FLEXRAYDATA_FRAME;
2121 } else {
2122 tmpbuf[0] = BLF_FLEXRAYDATA_FRAME | BLF_FLEXRAYDATA_CHANNEL_B;
2125 /* Error Flags */
2126 tmpbuf[1] = 0;
2128 /* Frame Header */
2129 tmpbuf[2] = 0x20 | ((0x0700 & frheader.messageId) >> 8);
2130 tmpbuf[3] = 0x00ff & frheader.messageId;
2131 tmpbuf[4] = (0xfe & frheader.len) | ((frheader.crc & 0x0400) >> 10);
2132 tmpbuf[5] = (0x03fc & frheader.crc) >> 2;
2133 tmpbuf[6] = ((0x0003 & frheader.crc) << 6) | (0x3f & frheader.mux);
2135 ws_buffer_assure_space(params->buf, sizeof(tmpbuf) + payload_length_valid);
2136 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2137 caplen = sizeof(tmpbuf) + payload_length_valid;
2138 len = sizeof(tmpbuf) + payload_length;
2140 if (payload_length_valid > 0 && !blf_read_bytes(params, data_start + sizeof(frheader), ws_buffer_end_ptr(params->buf), payload_length_valid, err, err_info)) {
2141 ws_debug("copying flexray payload failed");
2142 return false;
2144 params->buf->first_free += payload_length_valid;
2146 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_FLEXRAY, frheader.channel, UINT16_MAX, caplen, len);
2147 blf_add_direction_option(params, frheader.dir);
2149 return true;
2152 static bool
2153 blf_read_flexraymessage(blf_params_t *params, int *err, char **err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp) {
2154 blf_flexraymessage_t frheader;
2156 uint8_t payload_length;
2157 uint8_t payload_length_valid;
2158 uint8_t tmpbuf[7];
2159 unsigned caplen, len;
2161 if (object_length < (data_start - block_start) + (int) sizeof(frheader)) {
2162 *err = WTAP_ERR_BAD_FILE;
2163 *err_info = ws_strdup("blf: FLEXRAY_MESSAGE: not enough bytes for flexrayheader in object");
2164 ws_debug("not enough bytes for flexrayheader in object");
2165 return false;
2168 if (!blf_read_bytes(params, data_start, &frheader, sizeof(frheader), err, err_info)) {
2169 ws_debug("not enough bytes for flexrayheader header in file");
2170 return false;
2172 fix_endianness_blf_flexraymessage(&frheader);
2174 payload_length = frheader.length;
2175 payload_length_valid = payload_length;
2177 if ((frheader.length & 0x01) == 0x01) {
2178 ws_debug("reading odd length in FlexRay!?");
2181 if (payload_length_valid > object_length - (data_start - block_start) - sizeof(frheader)) {
2182 ws_debug("shortening FlexRay payload because buffer is too short!");
2183 payload_length_valid = (uint8_t)(object_length - (data_start - block_start) - sizeof(frheader));
2186 if (frheader.channel != 0 && frheader.channel != 1) {
2187 ws_debug("FlexRay supports only two channels.");
2190 /* Measurement Header */
2191 if (frheader.channel == 0) {
2192 tmpbuf[0] = BLF_FLEXRAYDATA_FRAME;
2193 } else {
2194 tmpbuf[0] = BLF_FLEXRAYDATA_FRAME | BLF_FLEXRAYDATA_CHANNEL_B;
2197 /* Error Flags */
2198 tmpbuf[1] = 0;
2200 /* Frame Header */
2201 tmpbuf[2] = ((0x0700 & frheader.frameId) >> 8);
2202 if ((frheader.frameState & BLF_FLEXRAYMESSAGE_STATE_PPI) == BLF_FLEXRAYMESSAGE_STATE_PPI) {
2203 tmpbuf[2] |= BLF_DLT_FLEXRAY_PPI;
2206 if ((frheader.frameState & BLF_FLEXRAYMESSAGE_STATE_SFI) == BLF_FLEXRAYMESSAGE_STATE_SFI) {
2207 tmpbuf[2] |= BLF_DLT_FLEXRAY_SFI;
2210 if ((frheader.frameState & BLF_FLEXRAYMESSAGE_STATE_NFI) != BLF_FLEXRAYMESSAGE_STATE_NFI) {
2211 /* NFI needs to be inversed !? */
2212 tmpbuf[2] |= BLF_DLT_FLEXRAY_NFI;
2215 if ((frheader.frameState & BLF_FLEXRAYMESSAGE_STATE_STFI) == BLF_FLEXRAYMESSAGE_STATE_STFI) {
2216 tmpbuf[2] |= BLF_DLT_FLEXRAY_STFI;
2219 tmpbuf[3] = 0x00ff & frheader.frameId;
2220 tmpbuf[4] = (0xfe & frheader.length) | ((frheader.headerCrc & 0x0400) >> 10);
2221 tmpbuf[5] = (0x03fc & frheader.headerCrc) >> 2;
2222 tmpbuf[6] = ((0x0003 & frheader.headerCrc) << 6) | (0x3f & frheader.cycle);
2224 ws_buffer_assure_space(params->buf, sizeof(tmpbuf) + payload_length_valid);
2225 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2226 caplen = sizeof(tmpbuf) + payload_length_valid;
2227 len = sizeof(tmpbuf) + payload_length;
2229 if (payload_length_valid > 0 && !blf_read_bytes(params, data_start + sizeof(frheader), ws_buffer_end_ptr(params->buf), payload_length_valid, err, err_info)) {
2230 ws_debug("copying flexray payload failed");
2231 return false;
2233 params->buf->first_free += payload_length_valid;
2235 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_FLEXRAY, frheader.channel, UINT16_MAX, caplen, len);
2236 blf_add_direction_option(params, frheader.dir);
2238 return true;
2241 static bool
2242 blf_read_flexrayrcvmessageex(blf_params_t *params, int *err, char **err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp, bool ext) {
2243 blf_flexrayrcvmessage_t frheader;
2245 uint16_t payload_length;
2246 uint16_t payload_length_valid;
2247 uint8_t tmpbuf[7];
2248 int frheadersize = sizeof(frheader);
2249 unsigned caplen, len;
2251 if (ext) {
2252 frheadersize += 40;
2255 if ((int64_t)object_length < (data_start - block_start) + frheadersize) {
2256 *err = WTAP_ERR_BAD_FILE;
2257 *err_info = ws_strdup_printf("blf: %s: not enough bytes for flexrayheader in object",
2258 ext ? "FLEXRAY_RCVMESSAGE_EX" : "FLEXRAY_RCVMESSAGE");
2259 ws_debug("not enough bytes for flexrayheader in object");
2260 return false;
2263 if (!blf_read_bytes(params, data_start, &frheader, sizeof(frheader), err, err_info)) {
2264 ws_debug("not enough bytes for flexrayheader header in file");
2265 return false;
2267 fix_endianness_blf_flexrayrcvmessage(&frheader);
2269 if (!ext) {
2270 frheader.dir &= 0xff;
2271 frheader.cycle &= 0xff;
2274 payload_length = frheader.payloadLength;
2275 payload_length_valid = frheader.payloadLengthValid;
2277 if ((frheader.payloadLength & 0x01) == 0x01) {
2278 ws_debug("reading odd length in FlexRay!?");
2281 if (payload_length_valid > object_length - (data_start - block_start) - frheadersize) {
2282 ws_debug("shortening FlexRay payload because buffer is too short!");
2283 payload_length_valid = (uint8_t)(object_length - (data_start - block_start) - frheadersize);
2286 /* Measurement Header */
2287 /* TODO: It seems that this format support both channels at the same time!? */
2288 if (frheader.channelMask == BLF_FLEXRAYRCVMSG_CHANNELMASK_A) {
2289 tmpbuf[0] = BLF_FLEXRAYDATA_FRAME;
2290 } else {
2291 tmpbuf[0] = BLF_FLEXRAYDATA_FRAME | BLF_FLEXRAYDATA_CHANNEL_B;
2294 /* Error Flags */
2295 tmpbuf[1] = 0;
2297 /* Frame Header */
2298 tmpbuf[2] = ((0x0700 & frheader.frameId) >> 8);
2299 if ((frheader.frameFlags & BLF_FLEXRAYRCVMSG_FRAME_FLAG_PAYLOAD_PREAM) == BLF_FLEXRAYRCVMSG_FRAME_FLAG_PAYLOAD_PREAM) {
2300 tmpbuf[2] |= BLF_DLT_FLEXRAY_PPI;
2303 if ((frheader.frameFlags & BLF_FLEXRAYRCVMSG_FRAME_FLAG_SYNC) == BLF_FLEXRAYRCVMSG_FRAME_FLAG_SYNC) {
2304 tmpbuf[2] |= BLF_DLT_FLEXRAY_SFI;
2307 if ((frheader.frameFlags & BLF_FLEXRAYRCVMSG_FRAME_FLAG_NULL_FRAME) != BLF_FLEXRAYRCVMSG_FRAME_FLAG_NULL_FRAME) {
2308 /* NFI needs to be inversed !? */
2309 tmpbuf[2] |= BLF_DLT_FLEXRAY_NFI;
2312 if ((frheader.frameFlags & BLF_FLEXRAYRCVMSG_FRAME_FLAG_STARTUP) == BLF_FLEXRAYRCVMSG_FRAME_FLAG_STARTUP) {
2313 tmpbuf[2] |= BLF_DLT_FLEXRAY_STFI;
2316 tmpbuf[3] = 0x00ff & frheader.frameId;
2317 tmpbuf[4] = (0xfe & frheader.payloadLength) | ((frheader.headerCrc1 & 0x0400) >> 10);
2318 tmpbuf[5] = (0x03fc & frheader.headerCrc1) >> 2;
2319 tmpbuf[6] = ((0x0003 & frheader.headerCrc1) << 6) | (0x3f & frheader.cycle);
2321 ws_buffer_assure_space(params->buf, sizeof(tmpbuf) + payload_length_valid);
2322 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2323 caplen = sizeof(tmpbuf) + payload_length_valid;
2324 len = sizeof(tmpbuf) + payload_length;
2326 if (payload_length_valid > 0 && !blf_read_bytes(params, data_start + frheadersize, ws_buffer_end_ptr(params->buf), payload_length_valid, err, err_info)) {
2327 ws_debug("copying flexray payload failed");
2328 return false;
2330 params->buf->first_free += payload_length_valid;
2332 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_FLEXRAY, frheader.channelMask, UINT16_MAX, caplen, len);
2333 blf_add_direction_option(params, frheader.dir);
2335 return true;
2338 static bool
2339 blf_read_linmessage(blf_params_t* params, int* err, char** err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp, bool crc_error) {
2340 blf_linmessage_t linmessage;
2342 uint8_t payload_length;
2343 unsigned len;
2345 if (object_length < (data_start - block_start) + (int)sizeof(linmessage)) {
2346 *err = WTAP_ERR_BAD_FILE;
2347 *err_info = ws_strdup_printf("blf: %s: not enough bytes for %s in object", crc_error ? "LIN_CRC_ERROR" : "LIN_MESSAGE", crc_error ? "lincrcerror" : "linmessage");
2348 ws_debug("not enough bytes for %s in object", crc_error ? "lincrcerror" : "linmessage");
2349 return false;
2352 if (!blf_read_bytes(params, data_start, &linmessage, sizeof(linmessage), err, err_info)) {
2353 ws_debug("not enough bytes for %s in file", crc_error ? "lincrcerror" : "linmessage");
2354 return false;
2356 fix_endianness_blf_linmessage(&linmessage);
2358 linmessage.dlc &= 0x0f;
2359 linmessage.id &= 0x3f;
2361 payload_length = MIN(linmessage.dlc, 8);
2363 uint8_t tmpbuf[8];
2364 tmpbuf[0] = 1; /* message format rev = 1 */
2365 tmpbuf[1] = 0; /* reserved */
2366 tmpbuf[2] = 0; /* reserved */
2367 tmpbuf[3] = 0; /* reserved */
2368 tmpbuf[4] = linmessage.dlc << 4; /* dlc (4bit) | type (2bit) | checksum type (2bit) */
2369 tmpbuf[5] = linmessage.id; /* parity (2bit) | id (6bit) */
2370 tmpbuf[6] = (uint8_t)(linmessage.crc & 0xff); /* checksum */
2371 tmpbuf[7] = 0; /* errors */
2373 if (crc_error) {
2374 tmpbuf[7] |= 0x08;
2377 ws_buffer_assure_space(params->buf, sizeof(tmpbuf) + payload_length);
2378 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2379 ws_buffer_append(params->buf, linmessage.data, payload_length);
2380 len = sizeof(tmpbuf) + payload_length;
2382 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_LIN, linmessage.channel, UINT16_MAX, len, len);
2383 blf_add_direction_option(params, linmessage.dir);
2385 return true;
2388 static bool
2389 blf_read_linrcverror(blf_params_t* params, int* err, char** err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp) {
2390 blf_linrcverror_t linmessage;
2392 if (object_length < (data_start - block_start) + (int)sizeof(linmessage)) {
2393 *err = WTAP_ERR_BAD_FILE;
2394 *err_info = ws_strdup("blf: LIN_RCV_ERROR: not enough bytes for linrcverror in object");
2395 ws_debug("not enough bytes for linrcverror in object");
2396 return false;
2399 if (!blf_read_bytes(params, data_start, &linmessage, sizeof(linmessage), err, err_info)) {
2400 ws_debug("not enough bytes for linrcverror in file");
2401 return false;
2403 linmessage.channel = GUINT16_FROM_LE(linmessage.channel);
2405 linmessage.dlc &= 0x0f;
2406 linmessage.id &= 0x3f;
2408 uint8_t tmpbuf[8];
2409 tmpbuf[0] = 1; /* message format rev = 1 */
2410 tmpbuf[1] = 0; /* reserved */
2411 tmpbuf[2] = 0; /* reserved */
2412 tmpbuf[3] = 0; /* reserved */
2413 tmpbuf[4] = linmessage.dlc << 4; /* dlc (4bit) | type (2bit) | checksum type (2bit) */
2414 tmpbuf[5] = linmessage.id; /* parity (2bit) | id (6bit) */
2415 tmpbuf[6] = 0; /* checksum */
2416 /* XXX - This object can represent many different error types.
2417 * For now we always treat it as framing error,
2418 * but in the future we should expand it. */
2419 tmpbuf[7] = 0x02; /* errors */
2421 ws_buffer_assure_space(params->buf, sizeof(tmpbuf));
2422 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2424 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_LIN, linmessage.channel, UINT16_MAX, sizeof(tmpbuf), sizeof(tmpbuf));
2426 return true;
2429 static bool
2430 blf_read_linsenderror(blf_params_t* params, int* err, char** err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp) {
2431 blf_linsenderror_t linmessage;
2433 if (object_length < (data_start - block_start) + (int)sizeof(linmessage)) {
2434 *err = WTAP_ERR_BAD_FILE;
2435 *err_info = ws_strdup("blf: LIN_SND_ERROR: not enough bytes for linsenderror in object");
2436 ws_debug("not enough bytes for linsenderror in object");
2437 return false;
2440 if (!blf_read_bytes(params, data_start, &linmessage, sizeof(linmessage), err, err_info)) {
2441 ws_debug("not enough bytes for linsenderror in file");
2442 return false;
2444 linmessage.channel = GUINT16_FROM_LE(linmessage.channel);
2446 linmessage.dlc &= 0x0f;
2447 linmessage.id &= 0x3f;
2449 uint8_t tmpbuf[8];
2450 tmpbuf[0] = 1; /* message format rev = 1 */
2451 tmpbuf[1] = 0; /* reserved */
2452 tmpbuf[2] = 0; /* reserved */
2453 tmpbuf[3] = 0; /* reserved */
2454 tmpbuf[4] = linmessage.dlc << 4; /* dlc (4bit) | type (2bit) | checksum type (2bit) */
2455 tmpbuf[5] = linmessage.id; /* parity (2bit) | id (6bit) */
2456 tmpbuf[6] = 0; /* checksum */
2457 tmpbuf[7] = 0x01; /* errors */
2459 ws_buffer_assure_space(params->buf, sizeof(tmpbuf));
2460 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2462 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_LIN, linmessage.channel, UINT16_MAX, sizeof(tmpbuf), sizeof(tmpbuf));
2464 return true;
2467 static bool
2468 blf_read_linwakeupevent(blf_params_t* params, int* err, char** err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp) {
2469 blf_linwakeupevent_t linevent;
2471 if (object_length < (data_start - block_start) + (int)sizeof(linevent)) {
2472 *err = WTAP_ERR_BAD_FILE;
2473 *err_info = ws_strdup("blf: LIN_WAKEUP: not enough bytes for linwakeup in object");
2474 ws_debug("not enough bytes for linwakeup in object");
2475 return false;
2478 if (!blf_read_bytes(params, data_start, &linevent, sizeof(linevent), err, err_info)) {
2479 ws_debug("not enough bytes for linwakeup in file");
2480 return false;
2482 linevent.channel = GUINT16_FROM_LE(linevent.channel);
2484 uint8_t tmpbuf[12]; /* LIN events have a fixed length of 12 bytes */
2485 tmpbuf[0] = 1; /* message format rev = 1 */
2486 tmpbuf[1] = 0; /* reserved */
2487 tmpbuf[2] = 0; /* reserved */
2488 tmpbuf[3] = 0; /* reserved */
2489 tmpbuf[4] = 3 << 2; /* dlc (4bit) | type (2bit) | checksum type (2bit) */
2490 tmpbuf[5] = 0; /* parity (2bit) | id (6bit) */
2491 tmpbuf[6] = 0; /* checksum */
2492 tmpbuf[7] = 0; /* errors */
2494 /* Wake-up event */
2495 tmpbuf[8] = 0xB0;
2496 tmpbuf[9] = 0xB0;
2497 tmpbuf[10] = 0x00;
2498 tmpbuf[11] = 0x04;
2500 ws_buffer_assure_space(params->buf, sizeof(tmpbuf));
2501 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2503 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_LIN, linevent.channel, UINT16_MAX, sizeof(tmpbuf), sizeof(tmpbuf));
2505 return true;
2508 static bool
2509 blf_read_linmessage2(blf_params_t* params, int* err, char** err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp, uint16_t object_version) {
2510 blf_linmessage2_t linmessage;
2512 uint8_t payload_length;
2513 unsigned len;
2515 if (object_length < (data_start - block_start) + (int)sizeof(linmessage)) {
2516 *err = WTAP_ERR_BAD_FILE;
2517 *err_info = ws_strdup("blf: LIN_MESSAGE2: not enough bytes for linmessage2 in object");
2518 ws_debug("not enough bytes for linmessage2 in object");
2519 return false;
2522 if (!blf_read_bytes(params, data_start, &linmessage, sizeof(linmessage), err, err_info)) {
2523 ws_debug("not enough bytes for linmessage2 in file");
2524 return false;
2526 fix_endianness_blf_linmessage2(&linmessage);
2528 linmessage.linDataByteTimestampEvent.linMessageDescriptor.dlc &= 0x0f;
2529 linmessage.linDataByteTimestampEvent.linMessageDescriptor.id &= 0x3f;
2531 payload_length = MIN(linmessage.linDataByteTimestampEvent.linMessageDescriptor.dlc, 8);
2533 uint8_t tmpbuf[8];
2534 tmpbuf[0] = 1; /* message format rev = 1 */
2535 tmpbuf[1] = 0; /* reserved */
2536 tmpbuf[2] = 0; /* reserved */
2537 tmpbuf[3] = 0; /* reserved */
2538 tmpbuf[4] = linmessage.linDataByteTimestampEvent.linMessageDescriptor.dlc << 4; /* dlc (4bit) | type (2bit) | checksum type (2bit) */
2539 if (object_version >= 1) { /* The 'checksumModel' field is valid only if objectVersion >= 1 */
2540 switch (linmessage.linDataByteTimestampEvent.linMessageDescriptor.checksumModel) {
2541 case 0:
2542 tmpbuf[4] |= 1; /* Classic */
2543 break;
2544 case 1:
2545 tmpbuf[4] |= 2; /* Enhanced */
2546 break;
2547 default:
2548 break;
2551 tmpbuf[5] = linmessage.linDataByteTimestampEvent.linMessageDescriptor.id; /* parity (2bit) | id (6bit) */
2552 tmpbuf[6] = (uint8_t)(linmessage.crc & 0xff); /* checksum */
2553 tmpbuf[7] = 0; /* errors */
2555 ws_buffer_assure_space(params->buf, sizeof(tmpbuf) + payload_length);
2556 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2557 ws_buffer_append(params->buf, linmessage.data, payload_length);
2558 len = sizeof(tmpbuf) + payload_length;
2560 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_LIN, linmessage.linDataByteTimestampEvent.linMessageDescriptor.linSynchFieldEvent.linBusEvent.channel, UINT16_MAX, len, len);
2561 blf_add_direction_option(params, linmessage.dir);
2563 return true;
2566 static bool
2567 blf_read_lincrcerror2(blf_params_t* params, int* err, char** err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp, uint16_t object_version) {
2568 blf_lincrcerror2_t linmessage;
2570 uint8_t payload_length;
2571 unsigned len;
2573 if (object_length < (data_start - block_start) + (int)sizeof(linmessage)) {
2574 *err = WTAP_ERR_BAD_FILE;
2575 *err_info = ws_strdup("blf: LIN_CRC_ERROR2: not enough bytes for lincrcerror2 in object");
2576 ws_debug("not enough bytes for lincrcerror2 in object");
2577 return false;
2580 if (!blf_read_bytes(params, data_start, &linmessage, sizeof(linmessage), err, err_info)) {
2581 ws_debug("not enough bytes for lincrcerror2 in file");
2582 return false;
2584 fix_endianness_blf_lincrcerror2(&linmessage);
2586 linmessage.linDataByteTimestampEvent.linMessageDescriptor.dlc &= 0x0f;
2587 linmessage.linDataByteTimestampEvent.linMessageDescriptor.id &= 0x3f;
2589 payload_length = MIN(linmessage.linDataByteTimestampEvent.linMessageDescriptor.dlc, 8);
2591 uint8_t tmpbuf[8];
2592 tmpbuf[0] = 1; /* message format rev = 1 */
2593 tmpbuf[1] = 0; /* reserved */
2594 tmpbuf[2] = 0; /* reserved */
2595 tmpbuf[3] = 0; /* reserved */
2596 tmpbuf[4] = linmessage.linDataByteTimestampEvent.linMessageDescriptor.dlc << 4; /* dlc (4bit) | type (2bit) | checksum type (2bit) */
2597 if (object_version >= 1) { /* The 'checksumModel' field is valid only if objectVersion >= 1 */
2598 switch (linmessage.linDataByteTimestampEvent.linMessageDescriptor.checksumModel) {
2599 case 0:
2600 tmpbuf[4] |= 1; /* Classic */
2601 break;
2602 case 1:
2603 tmpbuf[4] |= 2; /* Enhanced */
2604 break;
2605 default:
2606 break;
2609 tmpbuf[5] = linmessage.linDataByteTimestampEvent.linMessageDescriptor.id; /* parity (2bit) | id (6bit) */
2610 tmpbuf[6] = (uint8_t)(linmessage.crc & 0xff); /* checksum */
2611 tmpbuf[7] = 0x08; /* errors */
2613 ws_buffer_assure_space(params->buf, sizeof(tmpbuf) + payload_length);
2614 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2615 ws_buffer_append(params->buf, linmessage.data, payload_length);
2616 len = sizeof(tmpbuf) + payload_length;
2618 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_LIN, linmessage.linDataByteTimestampEvent.linMessageDescriptor.linSynchFieldEvent.linBusEvent.channel, UINT16_MAX, len, len);
2619 blf_add_direction_option(params, linmessage.dir);
2621 return true;
2624 static bool
2625 blf_read_linrcverror2(blf_params_t* params, int* err, char** err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp, uint16_t object_version) {
2626 blf_linrcverror2_t linmessage;
2628 uint8_t payload_length;
2629 unsigned len;
2631 if (object_length < (data_start - block_start) + (int)sizeof(linmessage)) {
2632 *err = WTAP_ERR_BAD_FILE;
2633 *err_info = ws_strdup("blf: LIN_RCV_ERROR2: not enough bytes for linrcverror2 in object");
2634 ws_debug("not enough bytes for linrcverror2 in object");
2635 return false;
2638 if (!blf_read_bytes(params, data_start, &linmessage, sizeof(linmessage), err, err_info)) {
2639 ws_debug("not enough bytes for linrcverror2 in file");
2640 return false;
2642 fix_endianness_blf_linrcverror2(&linmessage);
2644 linmessage.linDataByteTimestampEvent.linMessageDescriptor.dlc &= 0x0f;
2645 linmessage.linDataByteTimestampEvent.linMessageDescriptor.id &= 0x3f;
2647 if (linmessage.hasDataBytes) {
2648 payload_length = MIN(linmessage.linDataByteTimestampEvent.linMessageDescriptor.dlc, 8);
2650 else {
2651 payload_length = 0;
2654 uint8_t tmpbuf[8];
2655 tmpbuf[0] = 1; /* message format rev = 1 */
2656 tmpbuf[1] = 0; /* reserved */
2657 tmpbuf[2] = 0; /* reserved */
2658 tmpbuf[3] = 0; /* reserved */
2659 tmpbuf[4] = linmessage.linDataByteTimestampEvent.linMessageDescriptor.dlc << 4; /* dlc (4bit) | type (2bit) | checksum type (2bit) */
2660 if (object_version >= 1) { /* The 'checksumModel' field is valid only if objectVersion >= 1 */
2661 switch (linmessage.linDataByteTimestampEvent.linMessageDescriptor.checksumModel) {
2662 case 0:
2663 tmpbuf[4] |= 1; /* Classic */
2664 break;
2665 case 1:
2666 tmpbuf[4] |= 2; /* Enhanced */
2667 break;
2668 default:
2669 break;
2672 tmpbuf[5] = linmessage.linDataByteTimestampEvent.linMessageDescriptor.id; /* parity (2bit) | id (6bit) */
2673 tmpbuf[6] = 0; /* checksum */
2674 /* XXX - This object can represent many different error types.
2675 * For now we always treat it as framing error,
2676 * but in the future we should expand it. */
2677 tmpbuf[7] = 0x02; /* errors */
2679 ws_buffer_assure_space(params->buf, sizeof(tmpbuf) + payload_length);
2680 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2681 if (payload_length > 0) {
2682 ws_buffer_append(params->buf, linmessage.data, payload_length);
2684 len = sizeof(tmpbuf) + payload_length;
2686 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_LIN, linmessage.linDataByteTimestampEvent.linMessageDescriptor.linSynchFieldEvent.linBusEvent.channel, UINT16_MAX, len, len);
2688 return true;
2691 static bool
2692 blf_read_linsenderror2(blf_params_t* params, int* err, char** err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp, uint16_t object_version) {
2693 blf_linsenderror2_t linmessage;
2695 if (object_length < (data_start - block_start) + (int)sizeof(linmessage)) {
2696 *err = WTAP_ERR_BAD_FILE;
2697 *err_info = ws_strdup("blf: LIN_SND_ERROR2: not enough bytes for linsenderror2 in object");
2698 ws_debug("not enough bytes for linsenderror2 in object");
2699 return false;
2702 if (!blf_read_bytes(params, data_start, &linmessage, sizeof(linmessage), err, err_info)) {
2703 ws_debug("not enough bytes for linsenderror2 in file");
2704 return false;
2706 fix_endianness_blf_linsenderror2(&linmessage);
2708 linmessage.linMessageDescriptor.dlc &= 0x0f;
2709 linmessage.linMessageDescriptor.id &= 0x3f;
2711 uint8_t tmpbuf[8];
2712 tmpbuf[0] = 1; /* message format rev = 1 */
2713 tmpbuf[1] = 0; /* reserved */
2714 tmpbuf[2] = 0; /* reserved */
2715 tmpbuf[3] = 0; /* reserved */
2716 tmpbuf[4] = linmessage.linMessageDescriptor.dlc << 4; /* dlc (4bit) | type (2bit) | checksum type (2bit) */
2717 if (object_version >= 1) { /* The 'checksumModel' field is valid only if objectVersion >= 1 */
2718 switch (linmessage.linMessageDescriptor.checksumModel) {
2719 case 0:
2720 tmpbuf[4] |= 1; /* Classic */
2721 break;
2722 case 1:
2723 tmpbuf[4] |= 2; /* Enhanced */
2724 break;
2725 default:
2726 break;
2729 tmpbuf[5] = linmessage.linMessageDescriptor.id; /* parity (2bit) | id (6bit) */
2730 tmpbuf[6] = 0; /* checksum */
2731 tmpbuf[7] = 0x01; /* errors */
2733 ws_buffer_assure_space(params->buf, sizeof(tmpbuf));
2734 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2736 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_LIN, linmessage.linMessageDescriptor.linSynchFieldEvent.linBusEvent.channel, UINT16_MAX, sizeof(tmpbuf), sizeof(tmpbuf));
2738 return true;
2741 static bool
2742 blf_read_linwakeupevent2(blf_params_t* params, int* err, char** err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp) {
2743 blf_linwakeupevent2_t linevent;
2745 if (object_length < (data_start - block_start) + (int)sizeof(linevent)) {
2746 *err = WTAP_ERR_BAD_FILE;
2747 *err_info = ws_strdup("blf: LIN_WAKEUP2: not enough bytes for linwakeup2 in object");
2748 ws_debug("not enough bytes for linwakeup2 in object");
2749 return false;
2752 if (!blf_read_bytes(params, data_start, &linevent, sizeof(linevent), err, err_info)) {
2753 ws_debug("not enough bytes for linwakeup2 in file");
2754 return false;
2756 fix_endianness_blf_linwakeupevent2(&linevent);
2758 uint8_t tmpbuf[12]; /* LIN events have a fixed length of 12 bytes */
2759 tmpbuf[0] = 1; /* message format rev = 1 */
2760 tmpbuf[1] = 0; /* reserved */
2761 tmpbuf[2] = 0; /* reserved */
2762 tmpbuf[3] = 0; /* reserved */
2763 tmpbuf[4] = 3 << 2; /* dlc (4bit) | type (2bit) | checksum type (2bit) */
2764 tmpbuf[5] = 0; /* parity (2bit) | id (6bit) */
2765 tmpbuf[6] = 0; /* checksum */
2766 tmpbuf[7] = 0; /* errors */
2768 /* Wake-up event */
2769 tmpbuf[8] = 0xB0;
2770 tmpbuf[9] = 0xB0;
2771 tmpbuf[10] = 0x00;
2772 tmpbuf[11] = 0x04;
2774 ws_buffer_assure_space(params->buf, sizeof(tmpbuf));
2775 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2777 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_LIN, linevent.linBusEvent.channel, UINT16_MAX, sizeof(tmpbuf), sizeof(tmpbuf));
2779 return true;
2782 static bool
2783 blf_read_linsleepmodeevent(blf_params_t* params, int* err, char** err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp) {
2784 blf_linsleepmodeevent_t linevent;
2786 if (object_length < (data_start - block_start) + (int)sizeof(linevent)) {
2787 *err = WTAP_ERR_BAD_FILE;
2788 *err_info = ws_strdup("blf: LIN_SLEEP: not enough bytes for linsleep in object");
2789 ws_debug("not enough bytes for linsleep in object");
2790 return false;
2793 if (!blf_read_bytes(params, data_start, &linevent, sizeof(linevent), err, err_info)) {
2794 ws_debug("not enough bytes for linsleep in file");
2795 return false;
2797 linevent.channel = GUINT16_FROM_LE(linevent.channel);
2799 uint8_t tmpbuf[12]; /* LIN events have a fixed length of 12 bytes */
2800 tmpbuf[0] = 1; /* message format rev = 1 */
2801 tmpbuf[1] = 0; /* reserved */
2802 tmpbuf[2] = 0; /* reserved */
2803 tmpbuf[3] = 0; /* reserved */
2804 tmpbuf[4] = 3 << 2; /* dlc (4bit) | type (2bit) | checksum type (2bit) */
2805 tmpbuf[5] = 0; /* parity (2bit) | id (6bit) */
2806 tmpbuf[6] = 0; /* checksum */
2807 tmpbuf[7] = 0; /* errors */
2809 switch (linevent.reason) {
2810 case BLF_LIN_SLEEP_REASON_GO_TO_SLEEP_FRAME:
2811 /* Go-to-Sleep event by Go-to-Sleep frame */
2812 tmpbuf[8] = 0xB0;
2813 tmpbuf[9] = 0xB0;
2814 tmpbuf[10] = 0x00;
2815 tmpbuf[11] = 0x01;
2816 break;
2817 case BLF_LIN_SLEEP_REASON_BUS_IDLE_TIMEOUT:
2818 case BLF_LIN_SLEEP_REASON_SILENT_SLEEPMODE_CMD:
2819 /* Go-to-Sleep event by Inactivity for more than 4s */
2820 tmpbuf[8] = 0xB0;
2821 tmpbuf[9] = 0xB0;
2822 tmpbuf[10] = 0x00;
2823 tmpbuf[11] = 0x02;
2824 break;
2825 case BLF_LIN_WU_REASON_EXTERNAL_WAKEUP_SIG:
2826 case BLF_LIN_WU_REASON_INTERNAL_WAKEUP_SIG:
2827 case BLF_LIN_WU_REASON_BUS_TRAFFIC: /* There's no "wake-up by bus traffic" event in the LIN packet. */
2828 /* Wake-up event by Wake-up signal */
2829 tmpbuf[8] = 0xB0;
2830 tmpbuf[9] = 0xB0;
2831 tmpbuf[10] = 0x00;
2832 tmpbuf[11] = 0x04;
2833 break;
2834 case BLF_LIN_WU_SLEEP_REASON_START_STATE:
2835 case BLF_LIN_NO_SLEEP_REASON_BUS_TRAFFIC:
2836 /* If we're just reporting on the initial state,
2837 * or the interface doesn't want to go to sleep,
2838 * report the current state as "event". */
2839 if (linevent.flags & 0x2) {
2840 /* Wake-up event by Wake-up signal */
2841 tmpbuf[8] = 0xB0;
2842 tmpbuf[9] = 0xB0;
2843 tmpbuf[10] = 0x00;
2844 tmpbuf[11] = 0x04;
2846 else {
2847 /* Go-to-Sleep event by Inactivity for more than 4s */
2848 tmpbuf[8] = 0xB0;
2849 tmpbuf[9] = 0xB0;
2850 tmpbuf[10] = 0x00;
2851 tmpbuf[11] = 0x02;
2853 break;
2854 default:
2855 tmpbuf[8] = 0x00;
2856 tmpbuf[9] = 0x00;
2857 tmpbuf[10] = 0x00;
2858 tmpbuf[11] = 0x00;
2859 break;
2862 ws_buffer_assure_space(params->buf, sizeof(tmpbuf));
2863 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2865 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_LIN, linevent.channel, UINT16_MAX, sizeof(tmpbuf), sizeof(tmpbuf));
2867 return true;
2870 uint16_t blf_get_xml_channel_number(const char* start, const char* end) {
2871 char* text;
2872 size_t len;
2873 uint16_t res;
2875 if (start == NULL || end == NULL || end <= start) {
2876 return UINT16_MAX;
2879 len = (size_t)(end - start);
2880 text = g_try_malloc(len + 1); /* Accommodate '\0' */
2881 if (text == NULL) {
2882 ws_debug("cannot allocate memory");
2883 return UINT16_MAX;
2885 memcpy(text, start, len);
2886 text[len] = '\0';
2888 if (!ws_strtou16(text, NULL, &res)) {
2889 res = UINT16_MAX;
2892 g_free(text);
2893 return res;
2896 char* blf_get_xml_channel_name(const char* start, const char* end) {
2897 char* text;
2898 size_t len;
2900 if (start == NULL || end == NULL || end <= start) {
2901 return NULL;
2904 len = (size_t)(end - start);
2905 text = g_try_malloc(len + 1); /* Accommodate '\0' */
2906 if (text == NULL) {
2907 ws_debug("cannot allocate memory");
2908 return NULL;
2910 memcpy(text, start, len);
2911 text[len] = '\0';
2913 return text;
2916 bool blf_parse_xml_port(const char* start, const char* end, char** name, uint16_t* hwchannel, bool* simulated) {
2917 static const char name_magic[] = "name=";
2918 static const char hwchannel_magic[] = "hwchannel=";
2919 static const char simulated_magic[] = "simulated=";
2921 char* text;
2922 size_t len;
2923 char** tokens;
2924 const char* token;
2926 if (start == NULL || end == NULL || name == NULL || end <= start) {
2927 return false;
2930 len = (size_t)(end - start);
2931 text = g_try_malloc(len + 1); /* Accommodate '\0' */
2932 if (text == NULL) {
2933 ws_debug("cannot allocate memory");
2934 return false;
2936 memcpy(text, start, len);
2937 text[len] = '\0';
2939 tokens = g_strsplit_set(text, ";", -1);
2940 g_free(text);
2941 if (tokens == NULL) {
2942 ws_debug("cannot split XML port data");
2943 return false;
2946 *name = NULL;
2947 *hwchannel = UINT16_MAX;
2948 *simulated = false;
2950 for (int i = 0; tokens[i] != NULL; i++) {
2951 token = tokens[i];
2952 if (strncmp(token, name_magic, strlen(name_magic)) == 0) {
2953 if (*name == NULL) { /* Avoid memory leak in case of malformed string */
2954 *name = ws_strdup(token + strlen(name_magic));
2957 else if (strncmp(token, hwchannel_magic, strlen(hwchannel_magic)) == 0) {
2958 if (!ws_strtou16(token + strlen(hwchannel_magic), NULL, hwchannel)) {
2959 *hwchannel = UINT16_MAX;
2962 else if (strncmp(token, simulated_magic, strlen(simulated_magic)) == 0) {
2963 if (strlen(token) > strlen(simulated_magic) && token[strlen(simulated_magic)] != '0') {
2964 *simulated = true; /* TODO: Find a way to use this information */
2969 g_strfreev(tokens);
2971 return true;
2974 int blf_get_xml_pkt_encap(const char* start, const char* end) {
2975 size_t len;
2977 if (start == NULL || end == NULL || end <= start) {
2978 return 0;
2981 len = (size_t)(end - start);
2983 if (strncmp(start, "CAN", len) == 0) {
2984 return WTAP_ENCAP_SOCKETCAN;
2986 if (strncmp(start, "FlexRay", len) == 0) {
2987 return WTAP_ENCAP_FLEXRAY;
2989 if (strncmp(start, "LIN", len) == 0) {
2990 return WTAP_ENCAP_LIN;
2992 if (strncmp(start, "Ethernet", len) == 0) {
2993 return WTAP_ENCAP_ETHERNET;
2995 if (strncmp(start, "WLAN", len) == 0) { /* Not confirmed with a real capture */
2996 return WTAP_ENCAP_IEEE_802_11;
2999 return 0xffffffff;
3002 /** Finds a NULL-terminated string in a block of memory.
3004 * 'start' points to the first byte of the block of memory.
3005 * 'end' points to the first byte after the end of the block of memory,
3006 * so that the size of the block is end-start.
3007 * 'str' is a NULL-terminated string.
3009 const char* blf_strmem(const char* start, const char* end, const char* str) {
3010 if (start == NULL || end == NULL || str == NULL || end <= start) {
3011 return NULL;
3014 return ws_memmem(start, end - start, str, strlen(str));
3017 /** Extracts the channel and port names from a channels XML.
3019 * A sample channels XML looks like this:
3021 * <?xml version="1.0" encoding="UTF-8"?>
3022 * <channels version="1">
3023 * <channel number="1" type="CAN" network="CAN01">
3024 * <databases>
3025 * <database file="DB.arxml" path="C:\...\" cluster="CAN01" />
3026 * <database file="DB.dbc" path="C:\...\" cluster="General" />
3027 * </databases>
3028 * </channel>
3029 * <channel number="1" type="LIN" network="LIN01">
3030 * <databases>
3031 * <database file="DB.dbc" path="C:\...\" cluster="General" />
3032 * <database file="DB.ldf" path="C:\...\" cluster="LIN01" />
3033 * </databases>
3034 * </channel>
3035 * <channel number="1" type="Ethernet" network="ETH01">
3036 * <databases>
3037 * <database file="DB.dbc" path="C:\...\" cluster="General" />
3038 * </databases>
3039 * <channel_properties>
3040 * <elist name="ports">
3041 * <eli name="port">name=Port1;hwchannel=11;simulated=1</eli>
3042 * <eli name="port">name=Port2;hwchannel=12;simulated=0</eli>
3043 * </elist>
3044 * </channel_properties>
3045 * </channel>
3046 * </channels>
3048 static bool
3049 blf_set_xml_channels(blf_params_t* params, const char* text, size_t len) {
3050 static const char xml_magic[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
3051 static const char channels_start_magic[] = "<channels ";
3052 static const char channels_end_magic[] = "</channels>";
3053 static const char channel_start_magic[] = "<channel ";
3054 static const char channel_end_magic[] = "</channel>";
3055 static const char number_start_magic[] = "number=\"";
3056 static const char number_end_magic[] = "\"";
3057 static const char type_start_magic[] = "type=\"";
3058 static const char type_end_magic[] = "\"";
3059 static const char network_start_magic[] = "network=\"";
3060 static const char network_end_magic[] = "\"";
3061 static const char ports_start_magic[] = "<elist name=\"ports\">";
3062 static const char ports_end_magic[] = "</elist>";
3063 static const char port_start_magic[] = "<eli name=\"port\">";
3064 static const char port_end_magic[] = "</eli>";
3066 const char* xml_start;
3067 const char* channels_start;
3068 const char* channels_end;
3069 const char* channel_start;
3070 const char* channel_end;
3071 const char* number_start;
3072 const char* number_end;
3073 const char* type_start;
3074 const char* type_end;
3075 const char* network_start;
3076 const char* network_end;
3077 const char* ports_start;
3078 const char* ports_end;
3079 const char* port_start;
3080 const char* port_end;
3082 const char* search_start;
3083 bool res;
3085 int pkt_encap;
3086 uint16_t channel;
3087 uint16_t hwchannel = UINT16_MAX;
3088 char* channel_name = NULL;
3089 char* port_name = NULL;
3090 bool simulated = false;
3091 char* iface_name = NULL;
3093 if (text == NULL || len < strlen(xml_magic)) {
3094 return false;
3097 xml_start = blf_strmem(text, text + len, xml_magic);
3098 if (xml_start == NULL) {
3099 ws_debug("no valid xml magic found");
3100 return false;
3102 search_start = xml_start + strlen(xml_magic);
3104 channels_start = blf_strmem(search_start, text + len, channels_start_magic);
3105 channels_end = blf_strmem(search_start, text + len, channels_end_magic);
3106 if (channels_start == NULL || channels_end == NULL || channels_end <= channels_start + strlen(channels_start_magic)) {
3107 ws_debug("no channels tag found in xml");
3108 return false;
3110 search_start = channels_start + strlen(channels_start_magic);
3112 while (search_start < channels_end) {
3113 channel_start = blf_strmem(search_start, channels_end, channel_start_magic);
3114 search_start = search_start + strlen(channel_start_magic);
3115 channel_end = blf_strmem(search_start, channels_end, channel_end_magic);
3116 if (channel_start == NULL || channel_end == NULL || channel_end <= channel_start + strlen(channel_start_magic)) {
3117 ws_debug("found end of channel list");
3118 return true;
3121 number_start = blf_strmem(channel_start, channel_end, number_start_magic);
3122 if (number_start == NULL) {
3123 ws_debug("channel without number found in xml");
3124 search_start = channel_end + strlen(channel_end_magic);
3125 continue;
3128 number_end = blf_strmem(number_start + strlen(number_start_magic), channel_end, number_end_magic);
3129 if (number_end == NULL) {
3130 ws_debug("channel with malformed number attribute found in xml");
3131 search_start = channel_end + strlen(channel_end_magic);
3132 continue;
3135 channel = blf_get_xml_channel_number(number_start + strlen(number_start_magic), number_end);
3136 if (channel == UINT16_MAX) {
3137 ws_debug("invalid channel number found in xml");
3138 search_start = channel_end + strlen(channel_end_magic);
3139 continue;
3142 type_start = blf_strmem(channel_start, channel_end, type_start_magic);
3143 if (type_start == NULL) {
3144 ws_debug("channel without type found in xml");
3145 search_start = channel_end + strlen(channel_end_magic);
3146 continue;
3149 type_end = blf_strmem(type_start + strlen(type_start_magic), channel_end, type_end_magic);
3150 if (type_end == NULL) {
3151 ws_debug("channel with malformed type attribute found in xml");
3152 search_start = channel_end + strlen(channel_end_magic);
3153 continue;
3156 pkt_encap = blf_get_xml_pkt_encap(type_start + strlen(type_start_magic), type_end);
3158 network_start = blf_strmem(channel_start, channel_end, network_start_magic);
3159 if (network_start == NULL) {
3160 ws_debug("channel without name found in xml");
3161 search_start = channel_end + strlen(channel_end_magic);
3162 continue;
3165 network_end = blf_strmem(network_start + strlen(network_start_magic), channel_end, network_end_magic);
3166 if (network_end == NULL) {
3167 ws_debug("channel with malformed network attribute found in xml");
3168 search_start = channel_end + strlen(channel_end_magic);
3169 continue;
3172 channel_name = blf_get_xml_channel_name(network_start + strlen(network_start_magic), network_end);
3173 if (channel_name == NULL || strlen(channel_name) == 0) {
3174 ws_debug("channel with empty name found in xml");
3175 if (channel_name) {
3176 g_free(channel_name);
3177 channel_name = NULL;
3179 search_start = channel_end + strlen(channel_end_magic);
3180 continue;
3183 ws_debug("Found channel in XML: PKT_ENCAP: %d, ID: %u, name: %s", pkt_encap, channel, channel_name);
3184 blf_prepare_interface_name(params, pkt_encap, channel, UINT16_MAX, channel_name, true);
3186 search_start = MAX(MAX(number_end + strlen(number_end_magic), type_end + strlen(type_end_magic)), network_end + strlen(network_end_magic));
3188 ports_start = blf_strmem(search_start, channel_end, ports_start_magic);
3189 if (ports_start == NULL) {
3190 /* Not an error, channel has no ports */
3191 g_free(channel_name);
3192 channel_name = NULL;
3193 search_start = channel_end + strlen(channel_end_magic);
3194 continue;
3197 search_start = ports_start + strlen(ports_start_magic);
3199 ports_end = blf_strmem(search_start, channel_end, ports_end_magic);
3200 if (ports_end == NULL) {
3201 ws_debug("channel with malformed ports tag found in xml");
3202 g_free(channel_name);
3203 channel_name = NULL;
3204 search_start = channel_end + strlen(channel_end_magic);
3205 continue;
3208 while (search_start < ports_end) {
3209 port_start = blf_strmem(search_start, ports_end, port_start_magic);
3210 port_end = blf_strmem(search_start + strlen(port_start_magic), ports_end, port_end_magic);
3211 if (port_start == NULL || port_end == NULL || port_end <= port_start + strlen(port_start_magic)) {
3212 ws_debug("found end of ports list");
3213 search_start = ports_end + strlen(ports_end_magic);
3214 continue;
3217 res = blf_parse_xml_port(port_start + strlen(port_start_magic), port_end, &port_name, &hwchannel, &simulated);
3218 if (!res || port_name == NULL || hwchannel == UINT16_MAX) {
3219 if (port_name) {
3220 g_free(port_name);
3221 port_name = NULL;
3223 ws_debug("port with missing or malformed info found in xml");
3224 search_start = port_end + strlen(port_end_magic);
3225 continue;
3228 iface_name = ws_strdup_printf("%s::%s", channel_name, port_name);
3229 ws_debug("Found channel in XML: PKT_ENCAP: %d, ID: %u, HW ID: %u, name: %s", pkt_encap, channel, hwchannel, iface_name);
3230 blf_prepare_interface_name(params, pkt_encap, channel, hwchannel, iface_name, true);
3231 g_free(iface_name);
3233 if (port_name) {
3234 g_free(port_name);
3235 port_name = NULL;
3238 search_start = port_end + strlen(port_end_magic);
3241 g_free(channel_name);
3242 channel_name = NULL;
3244 search_start = channel_end + strlen(channel_end_magic);
3247 return true;
3250 static int
3251 blf_read_apptextmessage(blf_params_t *params, int *err, char **err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp, size_t metadata_cont) {
3252 blf_apptext_t apptextheader;
3254 if (object_length < (data_start - block_start) + (int)sizeof(apptextheader)) {
3255 *err = WTAP_ERR_BAD_FILE;
3256 *err_info = ws_strdup("blf: APP_TEXT: not enough bytes for apptext header in object");
3257 ws_debug("not enough bytes for apptext header in object");
3258 return BLF_APPTEXT_FAILED;
3261 if (!blf_read_bytes(params, data_start, &apptextheader, sizeof(apptextheader), err, err_info)) {
3262 ws_debug("not enough bytes for apptext header in file");
3263 return BLF_APPTEXT_FAILED;
3265 fix_endianness_blf_apptext_header(&apptextheader);
3267 if (metadata_cont && apptextheader.source != BLF_APPTEXT_METADATA) {
3268 /* If we're in the middle of a sequence of metadata objects,
3269 * but we get an AppText object from another source,
3270 * skip the previously incomplete object and start fresh.
3272 metadata_cont = 0;
3275 /* Add an extra byte for a terminating '\0' */
3276 char* text = g_try_malloc((size_t)apptextheader.textLength + 1);
3277 if (text == NULL) {
3278 ws_debug("cannot allocate memory");
3279 return BLF_APPTEXT_FAILED;
3282 if (!blf_read_bytes(params, data_start + sizeof(apptextheader), text, apptextheader.textLength, err, err_info)) {
3283 ws_debug("not enough bytes for apptext text in file");
3284 g_free(text);
3285 return BLF_APPTEXT_FAILED;
3287 text[apptextheader.textLength] = '\0'; /* Here's the '\0' */
3289 switch (apptextheader.source) {
3290 case BLF_APPTEXT_CHANNEL:
3293 /* returns a NULL terminated array of NULL terminates strings */
3294 char** tokens = g_strsplit_set(text, ";", -1);
3296 if (tokens == NULL || tokens[0] == NULL || tokens[1] == NULL) {
3297 if (tokens != NULL) {
3298 g_strfreev(tokens);
3300 g_free(text);
3301 return BLF_APPTEXT_CHANNEL;
3304 uint16_t channel = (apptextheader.reservedAppText1 >> 8) & 0xff;
3305 int pkt_encap;
3307 switch ((apptextheader.reservedAppText1 >> 16) & 0xff) {
3308 case BLF_BUSTYPE_CAN:
3309 pkt_encap = WTAP_ENCAP_SOCKETCAN;
3310 break;
3312 case BLF_BUSTYPE_FLEXRAY:
3313 pkt_encap = WTAP_ENCAP_FLEXRAY;
3314 break;
3316 case BLF_BUSTYPE_LIN:
3317 pkt_encap = WTAP_ENCAP_LIN;
3318 break;
3320 case BLF_BUSTYPE_ETHERNET:
3321 pkt_encap = WTAP_ENCAP_ETHERNET;
3322 break;
3324 case BLF_BUSTYPE_WLAN:
3325 pkt_encap = WTAP_ENCAP_IEEE_802_11;
3326 break;
3328 default:
3329 pkt_encap = 0xffffffff;
3330 break;
3333 /* we use lookup to create interface, if not existing yet */
3334 blf_prepare_interface_name(params, pkt_encap, channel, UINT16_MAX, tokens[1], false);
3336 g_strfreev(tokens);
3337 g_free(text);
3338 return BLF_APPTEXT_CHANNEL;
3340 case BLF_APPTEXT_METADATA:
3341 if (metadata_cont) {
3342 /* Set the buffer pointer to the end of the previous object */
3343 params->buf->first_free = metadata_cont;
3345 else {
3346 /* First object of a sequence of one or more */
3347 wtap_buffer_append_epdu_string(params->buf, EXP_PDU_TAG_DISSECTOR_NAME, "data-text-lines");
3348 wtap_buffer_append_epdu_string(params->buf, EXP_PDU_TAG_COL_PROT_TEXT, "BLF App text");
3349 wtap_buffer_append_epdu_string(params->buf, EXP_PDU_TAG_COL_INFO_TEXT, "Metadata");
3350 wtap_buffer_append_epdu_end(params->buf);
3353 ws_buffer_assure_space(params->buf, apptextheader.textLength);
3354 ws_buffer_append(params->buf, text, apptextheader.textLength);
3355 g_free(text);
3357 if ((apptextheader.reservedAppText1 & 0x00ffffff) > apptextheader.textLength) {
3358 /* Continues in the next object */
3359 return BLF_APPTEXT_CONT;
3362 if (((apptextheader.reservedAppText1 >> 24) & 0xff) == BLF_APPTEXT_XML_CHANNELS) {
3363 blf_set_xml_channels(params, params->buf->data, ws_buffer_length(params->buf));
3366 /* Override the timestamp with 0 for metadata objects. Thay can only occur at the beginning of the file, and they usually already have a timestamp of 0. */
3367 blf_init_rec(params, 0, 0, WTAP_ENCAP_WIRESHARK_UPPER_PDU, 0, UINT16_MAX, (uint32_t)ws_buffer_length(params->buf), (uint32_t)ws_buffer_length(params->buf));
3368 return BLF_APPTEXT_METADATA;
3369 case BLF_APPTEXT_COMMENT:
3370 case BLF_APPTEXT_ATTACHMENT:
3371 case BLF_APPTEXT_TRACELINE:
3373 wtap_buffer_append_epdu_string(params->buf, EXP_PDU_TAG_DISSECTOR_NAME, "data-text-lines");
3374 wtap_buffer_append_epdu_string(params->buf, EXP_PDU_TAG_COL_PROT_TEXT, "BLF App text");
3376 char* info_line = NULL;
3377 switch (apptextheader.source) {
3378 case BLF_APPTEXT_COMMENT:
3379 info_line = ws_strdup_printf("Comment: %s", text);
3380 break;
3381 case BLF_APPTEXT_ATTACHMENT:
3382 info_line = ws_strdup_printf("Attachment: %s", text);
3383 break;
3384 case BLF_APPTEXT_TRACELINE:
3385 info_line = ws_strdup_printf("Trace line%s: %s", (apptextheader.reservedAppText1 & 0x00000010) ? "" : " (hidden)", text);
3386 break;
3387 default:
3388 break;
3391 wtap_buffer_append_epdu_string(params->buf, EXP_PDU_TAG_COL_INFO_TEXT, info_line);
3392 wtap_buffer_append_epdu_end(params->buf);
3394 size_t text_length = strlen(text); /* The string can contain '\0' before textLength bytes */
3395 ws_buffer_assure_space(params->buf, text_length); /* The dissector doesn't need NULL-terminated strings */
3396 ws_buffer_append(params->buf, text, text_length);
3398 /* We'll write this as a WS UPPER PDU packet with a text blob */
3399 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_WIRESHARK_UPPER_PDU, 0, UINT16_MAX, (uint32_t)ws_buffer_length(params->buf), (uint32_t)ws_buffer_length(params->buf));
3400 g_free(text);
3401 if (info_line) {
3402 g_free(info_line);
3404 return apptextheader.source;
3406 default:
3407 g_free(text);
3408 return BLF_APPTEXT_CHANNEL; /* Cheat - no block to write */;
3410 return BLF_APPTEXT_CHANNEL; /* Cheat - no block to write */
3413 static bool
3414 blf_read_ethernet_status(blf_params_t* params, int* err, char** err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp, uint16_t object_version) {
3415 blf_ethernet_status_t ethernet_status_header;
3416 uint8_t tmpbuf[24];
3417 uint64_t linkUpDuration;
3419 if (object_length < (data_start - block_start) + (int)sizeof(ethernet_status_header) + (int)(object_version >= 1 ? 8 : 0)) {
3420 *err = WTAP_ERR_BAD_FILE;
3421 *err_info = ws_strdup("blf: ETHERNET_STATUS: not enough bytes for ethernet status header in object");
3422 ws_debug("not enough bytes for ethernet status header in object");
3423 return false;
3426 if (!blf_read_bytes(params, data_start, &ethernet_status_header, sizeof(ethernet_status_header), err, err_info)) {
3427 ws_debug("not enough bytes for ethernet_status_header header in file");
3428 return false;
3431 if (object_version >= 1) {
3432 if (!blf_read_bytes(params, data_start + sizeof(ethernet_status_header), &linkUpDuration, 8, err, err_info)) {
3433 ws_debug("not enough bytes for ethernet_status_header header in file");
3434 return false;
3436 linkUpDuration = GUINT64_FROM_LE(linkUpDuration);
3439 fix_endianness_blf_ethernet_status_header(&ethernet_status_header);
3441 tmpbuf[0] = (ethernet_status_header.channel & 0xff00) >> 8;
3442 tmpbuf[1] = (ethernet_status_header.channel & 0x00ff);
3443 tmpbuf[2] = (ethernet_status_header.flags & 0xff00) >> 8;
3444 tmpbuf[3] = (ethernet_status_header.flags & 0x00ff);
3445 tmpbuf[4] = (ethernet_status_header.linkStatus);
3446 tmpbuf[5] = (ethernet_status_header.ethernetPhy);
3447 tmpbuf[6] = (ethernet_status_header.duplex);
3448 tmpbuf[7] = (ethernet_status_header.mdi);
3449 tmpbuf[8] = (ethernet_status_header.connector);
3450 tmpbuf[9] = (ethernet_status_header.clockMode);
3451 tmpbuf[10] = (ethernet_status_header.pairs);
3452 tmpbuf[11] = (ethernet_status_header.hardwareChannel);
3453 tmpbuf[12] = (ethernet_status_header.bitrate & 0xff000000) >> 24;
3454 tmpbuf[13] = (ethernet_status_header.bitrate & 0x00ff0000) >> 16;
3455 tmpbuf[14] = (ethernet_status_header.bitrate & 0x0000ff00) >> 8;
3456 tmpbuf[15] = (ethernet_status_header.bitrate & 0x000000ff);
3458 if (object_version >= 1) {
3459 tmpbuf[16] = (uint8_t)((linkUpDuration & UINT64_C(0xff00000000000000)) >> 56);
3460 tmpbuf[17] = (uint8_t)((linkUpDuration & UINT64_C(0x00ff000000000000)) >> 48);
3461 tmpbuf[18] = (uint8_t)((linkUpDuration & UINT64_C(0x0000ff0000000000)) >> 40);
3462 tmpbuf[19] = (uint8_t)((linkUpDuration & UINT64_C(0x000000ff00000000)) >> 32);
3463 tmpbuf[20] = (uint8_t)((linkUpDuration & UINT64_C(0x00000000ff000000)) >> 24);
3464 tmpbuf[21] = (uint8_t)((linkUpDuration & UINT64_C(0x0000000000ff0000)) >> 16);
3465 tmpbuf[22] = (uint8_t)((linkUpDuration & UINT64_C(0x000000000000ff00)) >> 8);
3466 tmpbuf[23] = (uint8_t)((linkUpDuration & UINT64_C(0x00000000000000ff)));
3469 wtap_buffer_append_epdu_string(params->buf, EXP_PDU_TAG_DISSECTOR_NAME, "blf-ethernetstatus-obj");
3470 wtap_buffer_append_epdu_end(params->buf);
3472 ws_buffer_assure_space(params->buf, sizeof(ethernet_status_header));
3473 ws_buffer_append(params->buf, tmpbuf, (size_t)(object_version >= 1 ? 24 : 16));
3475 /* We'll write this as a WS UPPER PDU packet with a data blob */
3476 /* This will create an interface with the "name" of the matching
3477 * WTAP_ENCAP_ETHERNET interface with the same channel and hardware
3478 * channel prefixed with "STATUS" and with a different interface ID,
3479 * because IDBs in pcapng can only have one linktype.
3480 * The other option would be to write everything as UPPER_PDU, including
3481 * the Ethernet data (with one of the "eth_" dissectors.)
3483 char* iface_name = ws_strdup_printf("STATUS-ETH-%u-%u", ethernet_status_header.channel, ethernet_status_header.hardwareChannel);
3484 blf_lookup_interface(params, WTAP_ENCAP_WIRESHARK_UPPER_PDU, ethernet_status_header.channel, ethernet_status_header.hardwareChannel, iface_name);
3485 g_free(iface_name);
3486 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_WIRESHARK_UPPER_PDU, ethernet_status_header.channel, ethernet_status_header.hardwareChannel, (uint32_t)ws_buffer_length(params->buf), (uint32_t)ws_buffer_length(params->buf));
3488 if ((ethernet_status_header.flags & BLF_ETH_STATUS_HARDWARECHANNEL) == BLF_ETH_STATUS_HARDWARECHANNEL) {
3489 /* If HW channel valid */
3490 wtap_block_add_uint32_option(params->rec->block, OPT_PKT_QUEUE, ethernet_status_header.hardwareChannel);
3493 return true;
3496 static bool
3497 blf_read_ethernet_phystate(blf_params_t* params, int* err, char** err_info, int64_t block_start, int64_t data_start, int64_t object_length, uint32_t flags, uint64_t object_timestamp) {
3498 blf_ethernet_phystate_t ethernet_phystate_header;
3499 uint8_t tmpbuf[8];
3501 if (object_length < (data_start - block_start) + (int)sizeof(ethernet_phystate_header)) {
3502 *err = WTAP_ERR_BAD_FILE;
3503 *err_info = ws_strdup("blf: ETHERNET_PHY_STATE: not enough bytes for ethernet phystate header in object");
3504 ws_debug("not enough bytes for ethernet phystate header in object");
3505 return false;
3508 if (!blf_read_bytes(params, data_start, &ethernet_phystate_header, sizeof(ethernet_phystate_header), err, err_info)) {
3509 ws_debug("not enough bytes for ethernet phystate header in file");
3510 return false;
3513 fix_endianness_blf_ethernet_phystate_header(&ethernet_phystate_header);
3515 tmpbuf[0] = (ethernet_phystate_header.channel & 0xff00) >> 8;
3516 tmpbuf[1] = (ethernet_phystate_header.channel & 0x00ff);
3517 tmpbuf[2] = (ethernet_phystate_header.flags & 0xff00) >> 8;
3518 tmpbuf[3] = (ethernet_phystate_header.flags & 0x00ff);
3519 tmpbuf[4] = (ethernet_phystate_header.phyState);
3520 tmpbuf[5] = (ethernet_phystate_header.phyEvent);
3521 tmpbuf[6] = (ethernet_phystate_header.hardwareChannel);
3522 tmpbuf[7] = (ethernet_phystate_header.res1);
3524 wtap_buffer_append_epdu_string(params->buf, EXP_PDU_TAG_DISSECTOR_NAME, "blf-ethernetphystate-obj");
3525 wtap_buffer_append_epdu_end(params->buf);
3527 ws_buffer_assure_space(params->buf, sizeof(ethernet_phystate_header));
3528 ws_buffer_append(params->buf, tmpbuf, sizeof(ethernet_phystate_header));
3530 /* We'll write this as a WS UPPER PDU packet with a data blob */
3531 /* This will create an interface with the "name" of the matching
3532 * WTAP_ENCAP_ETHERNET interface with the same channel and hardware
3533 * channel prefixed with "STATUS" and with a different interface ID,
3534 * because IDBs in pcapng can only have one linktype.
3535 * The other option would be to write everything as UPPER_PDU, including
3536 * the Ethernet data (with one of the "eth_" dissectors.)
3538 char* iface_name = ws_strdup_printf("STATUS-ETH-%u-%u", ethernet_phystate_header.channel, ethernet_phystate_header.hardwareChannel);
3539 blf_lookup_interface(params, WTAP_ENCAP_WIRESHARK_UPPER_PDU, ethernet_phystate_header.channel, ethernet_phystate_header.hardwareChannel, iface_name);
3540 g_free(iface_name);
3541 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_WIRESHARK_UPPER_PDU, ethernet_phystate_header.channel, ethernet_phystate_header.hardwareChannel, (uint32_t)ws_buffer_length(params->buf), (uint32_t)ws_buffer_length(params->buf));
3543 if ((ethernet_phystate_header.flags & BLF_PHY_STATE_HARDWARECHANNEL) == BLF_PHY_STATE_HARDWARECHANNEL) {
3544 /* If HW channel valid */
3545 wtap_block_add_uint32_option(params->rec->block, OPT_PKT_QUEUE, ethernet_phystate_header.hardwareChannel);
3548 return true;
3551 static bool
3552 blf_read_block(blf_params_t *params, int64_t start_pos, int *err, char **err_info) {
3553 blf_blockheader_t header;
3554 blf_logobjectheader_t logheader;
3555 blf_logobjectheader2_t logheader2;
3556 blf_logobjectheader3_t logheader3;
3557 uint32_t flags;
3558 uint64_t object_timestamp;
3559 uint16_t object_version;
3560 int64_t last_metadata_start = 0;
3561 size_t metadata_cont = 0;
3563 while (1) {
3564 /* Find Object */
3566 /* Resetting buffer */
3567 params->buf->first_free = params->buf->start;
3569 while (1) {
3570 if (!blf_read_bytes_or_eof(params, start_pos, &header, sizeof header, err, err_info)) {
3571 ws_debug("not enough bytes for block header or unsupported file");
3572 if (*err == WTAP_ERR_SHORT_READ) {
3573 /* we have found the end that is not a short read therefore. */
3574 *err = 0;
3575 g_free(*err_info);
3576 *err_info = NULL;
3578 return false;
3581 fix_endianness_blf_blockheader(&header);
3583 if (memcmp(header.magic, blf_obj_magic, sizeof(blf_obj_magic))) {
3584 ws_debug("object magic is not LOBJ (pos: 0x%" PRIx64 ")", start_pos);
3586 else {
3587 break;
3590 /* we are moving back and try again but 1 byte later */
3591 /* TODO: better understand how this paddings works... */
3592 start_pos++;
3594 params->blf_data->start_of_last_obj = start_pos;
3596 if (!params->random) {
3597 /* Make sure that we start after this object next time,
3598 * but only if it's a linear read. We can have random reads
3599 * during the linear read, so we have to make sure we don't
3600 * lose track of our position.
3602 params->blf_data->current_real_seek_pos = start_pos + MAX(MAX(16, header.object_length), header.header_length);
3605 switch (header.header_type) {
3606 case BLF_HEADER_TYPE_DEFAULT:
3607 if (!blf_read_log_object_header(params, err, err_info, start_pos + sizeof(blf_blockheader_t), start_pos + header.header_length, &logheader)) {
3608 return false;
3610 flags = logheader.flags;
3611 object_timestamp = logheader.object_timestamp;
3612 object_version = logheader.object_version;
3613 break;
3615 case BLF_HEADER_TYPE_2:
3616 if (!blf_read_log_object_header2(params, err, err_info, start_pos + sizeof(blf_blockheader_t), start_pos + header.header_length, &logheader2)) {
3617 return false;
3619 flags = logheader2.flags;
3620 object_timestamp = logheader2.object_timestamp;
3621 object_version = logheader2.object_version;
3622 break;
3624 case BLF_HEADER_TYPE_3:
3625 if (!blf_read_log_object_header3(params, err, err_info, start_pos + sizeof(blf_blockheader_t), start_pos + header.header_length, &logheader3)) {
3626 return false;
3628 flags = logheader3.flags;
3629 object_timestamp = logheader3.object_timestamp;
3630 object_version = logheader3.object_version;
3631 break;
3633 default:
3634 *err = WTAP_ERR_UNSUPPORTED;
3635 *err_info = ws_strdup_printf("blf: unknown header type %u", header.header_type);
3636 ws_debug("unknown header type");
3637 return false;
3640 if (metadata_cont && header.object_type != BLF_OBJTYPE_APP_TEXT) {
3641 /* If we're in the middle of a sequence of AppText metadata objects,
3642 * but we get an AppText object from another source,
3643 * skip the previous incomplete packet and start fresh.
3645 metadata_cont = 0;
3646 last_metadata_start = 0;
3649 switch (header.object_type) {
3650 case BLF_OBJTYPE_LOG_CONTAINER:
3651 *err = WTAP_ERR_UNSUPPORTED;
3652 *err_info = ws_strdup("blf: log container in log container not supported");
3653 ws_debug("log container in log container not supported");
3654 return false;
3656 case BLF_OBJTYPE_ETHERNET_FRAME:
3657 return blf_read_ethernetframe(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3659 case BLF_OBJTYPE_ETHERNET_FRAME_EX:
3660 return blf_read_ethernetframe_ext(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, false);
3662 case BLF_OBJTYPE_ETHERNET_RX_ERROR:
3663 return blf_read_ethernet_rxerror(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3665 case BLF_OBJTYPE_ETHERNET_ERROR_EX:
3666 return blf_read_ethernetframe_ext(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, true);
3668 case BLF_OBJTYPE_WLAN_FRAME:
3669 return blf_read_wlanframe(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3671 case BLF_OBJTYPE_CAN_MESSAGE:
3672 return blf_read_canmessage(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, false);
3674 case BLF_OBJTYPE_CAN_ERROR:
3675 return blf_read_canerror(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, false);
3677 case BLF_OBJTYPE_CAN_OVERLOAD:
3678 return blf_read_canerror(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, true);
3680 case BLF_OBJTYPE_CAN_MESSAGE2:
3681 return blf_read_canmessage(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, true);
3683 case BLF_OBJTYPE_CAN_ERROR_EXT:
3684 return blf_read_canerrorext(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3686 case BLF_OBJTYPE_CAN_FD_MESSAGE:
3687 return blf_read_canfdmessage(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3689 case BLF_OBJTYPE_CAN_FD_MESSAGE_64:
3690 return blf_read_canfdmessage64(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3692 case BLF_OBJTYPE_CAN_FD_ERROR_64:
3693 return blf_read_canfderror64(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3695 case BLF_OBJTYPE_FLEXRAY_DATA:
3696 return blf_read_flexraydata(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3698 case BLF_OBJTYPE_FLEXRAY_MESSAGE:
3699 return blf_read_flexraymessage(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3701 case BLF_OBJTYPE_FLEXRAY_RCVMESSAGE:
3702 return blf_read_flexrayrcvmessageex(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, false);
3704 case BLF_OBJTYPE_FLEXRAY_RCVMESSAGE_EX:
3705 return blf_read_flexrayrcvmessageex(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, true);
3707 case BLF_OBJTYPE_LIN_MESSAGE:
3708 return blf_read_linmessage(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, false);
3710 case BLF_OBJTYPE_LIN_CRC_ERROR:
3711 return blf_read_linmessage(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, true);
3713 case BLF_OBJTYPE_LIN_RCV_ERROR:
3714 return blf_read_linrcverror(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3716 case BLF_OBJTYPE_LIN_SND_ERROR:
3717 return blf_read_linsenderror(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3719 case BLF_OBJTYPE_LIN_WAKEUP:
3720 return blf_read_linwakeupevent(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3722 case BLF_OBJTYPE_LIN_MESSAGE2:
3723 return blf_read_linmessage2(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, object_version);
3725 case BLF_OBJTYPE_LIN_CRC_ERROR2:
3726 return blf_read_lincrcerror2(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, object_version);
3728 case BLF_OBJTYPE_LIN_RCV_ERROR2:
3729 return blf_read_linrcverror2(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, object_version);
3731 case BLF_OBJTYPE_LIN_SND_ERROR2:
3732 return blf_read_linsenderror2(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, object_version);
3734 case BLF_OBJTYPE_LIN_WAKEUP2:
3735 return blf_read_linwakeupevent2(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3737 case BLF_OBJTYPE_LIN_SLEEP:
3738 return blf_read_linsleepmodeevent(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3740 case BLF_OBJTYPE_APP_TEXT:
3742 int result = blf_read_apptextmessage(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, metadata_cont);
3743 if (result == BLF_APPTEXT_CONT) {
3744 if (!metadata_cont) {
3745 /* First object of a sequence, save its start position */
3746 last_metadata_start = start_pos;
3748 /* Save a pointer to the end of the buffer */
3749 metadata_cont = params->buf->first_free;
3751 else {
3752 if (result == BLF_APPTEXT_METADATA && metadata_cont) {
3753 /* Last object of a sequence, restore the start position of the first object */
3754 params->blf_data->start_of_last_obj = last_metadata_start;
3756 /* Reset everything and start fresh */
3757 last_metadata_start = 0;
3758 metadata_cont = 0;
3760 switch (result) {
3761 case BLF_APPTEXT_FAILED:
3762 return false;
3763 case BLF_APPTEXT_COMMENT:
3764 case BLF_APPTEXT_METADATA:
3765 case BLF_APPTEXT_ATTACHMENT:
3766 case BLF_APPTEXT_TRACELINE:
3767 return true;
3768 case BLF_APPTEXT_CHANNEL:
3769 case BLF_APPTEXT_CONT:
3770 default:
3771 /* we do not return since there is no packet to show here */
3772 start_pos += MAX(MAX(16, header.object_length), header.header_length);
3773 break;
3776 break;
3778 case BLF_OBJTYPE_ETHERNET_STATUS:
3779 return blf_read_ethernet_status(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, object_version);
3781 case BLF_OBJTYPE_ETHERNET_PHY_STATE:
3782 return blf_read_ethernet_phystate(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3784 case BLF_OBJTYPE_ENV_INTEGER:
3785 case BLF_OBJTYPE_ENV_DOUBLE:
3786 case BLF_OBJTYPE_ENV_STRING:
3787 case BLF_OBJTYPE_ENV_DATA:
3788 case BLF_OBJTYPE_SYS_VARIABLE:
3789 case BLF_OBJTYPE_RESERVED5: /* Despite the name, this is actually used. Maybe it's worth investigating the content. */
3790 case BLF_OBJTYPE_TEST_STRUCTURE:
3791 ws_debug("skipping unsupported object type 0x%04x", header.object_type);
3792 start_pos += MAX(MAX(16, header.object_length), header.header_length);
3793 break;
3794 default:
3795 ws_info("unknown object type 0x%04x", header.object_type);
3796 start_pos += MAX(MAX(16, header.object_length), header.header_length);
3797 break;
3800 return true;
3803 static bool blf_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err, char **err_info, int64_t *data_offset) {
3804 blf_params_t blf_tmp;
3806 blf_tmp.wth = wth;
3807 blf_tmp.fh = wth->fh;
3808 blf_tmp.random = false;
3809 blf_tmp.pipe = wth->ispipe;
3810 blf_tmp.rec = rec;
3811 blf_tmp.buf = buf;
3812 blf_tmp.blf_data = (blf_t *)wth->priv;
3814 if (!blf_read_block(&blf_tmp, blf_tmp.blf_data->current_real_seek_pos, err, err_info)) {
3815 return false;
3817 *data_offset = blf_tmp.blf_data->start_of_last_obj;
3819 return true;
3822 static bool blf_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec, Buffer *buf, int *err, char **err_info) {
3823 blf_params_t blf_tmp;
3825 blf_tmp.wth = wth;
3826 blf_tmp.fh = wth->random_fh;
3827 blf_tmp.random = true;
3828 blf_tmp.pipe = wth->ispipe;
3829 blf_tmp.rec = rec;
3830 blf_tmp.buf = buf;
3831 blf_tmp.blf_data = (blf_t *)wth->priv;
3833 if (!blf_read_block(&blf_tmp, seek_off, err, err_info)) {
3834 ws_debug("couldn't read packet block (err=%d).", *err);
3835 return false;
3838 return true;
3841 static void blf_free(blf_t *blf) {
3842 if (blf != NULL) {
3843 if (blf->log_containers != NULL) {
3844 for (unsigned i = 0; i < blf->log_containers->len; i++) {
3845 blf_log_container_t* log_container = &g_array_index(blf->log_containers, blf_log_container_t, i);
3846 if (log_container->real_data != NULL) {
3847 g_free(log_container->real_data);
3850 g_array_free(blf->log_containers, true);
3851 blf->log_containers = NULL;
3853 if (blf->channel_to_iface_ht != NULL) {
3854 g_hash_table_destroy(blf->channel_to_iface_ht);
3855 blf->channel_to_iface_ht = NULL;
3857 if (blf->channel_to_name_ht != NULL) {
3858 g_hash_table_destroy(blf->channel_to_name_ht);
3859 blf->channel_to_name_ht = NULL;
3864 static void blf_close(wtap *wth) {
3865 blf_free((blf_t *)wth->priv);
3867 /* TODO: do we need to reverse the wtap_add_idb? how? */
3870 wtap_open_return_val
3871 blf_open(wtap *wth, int *err, char **err_info) {
3872 blf_fileheader_t header;
3873 blf_t *blf;
3875 ws_debug("opening file");
3877 if (!wtap_read_bytes_or_eof(wth->fh, &header, sizeof(blf_fileheader_t), err, err_info)) {
3879 ws_debug("wtap_read_bytes_or_eof() failed, err = %d.", *err);
3880 if (*err == 0 || *err == WTAP_ERR_SHORT_READ) {
3882 * Short read or EOF.
3884 * We're reading this as part of an open, so
3885 * the file is too short to be a blf file.
3887 *err = 0;
3888 g_free(*err_info);
3889 *err_info = NULL;
3890 return WTAP_OPEN_NOT_MINE;
3892 return WTAP_OPEN_ERROR;
3895 fix_endianness_blf_fileheader(&header);
3897 if (memcmp(header.magic, blf_magic, sizeof(blf_magic))) {
3898 return WTAP_OPEN_NOT_MINE;
3901 /* This seems to be an BLF! */
3902 /* Check for a valid header length */
3903 if (header.header_length < sizeof(blf_fileheader_t)) {
3904 *err = WTAP_ERR_BAD_FILE;
3905 *err_info = ws_strdup("blf: file header length too short");
3906 return WTAP_OPEN_ERROR;
3909 /* skip past the header, which may include padding/reserved space */
3910 if (!wtap_read_bytes(wth->fh, NULL, header.header_length - sizeof(blf_fileheader_t), err, err_info)) {
3911 return WTAP_OPEN_ERROR;
3914 /* Prepare our private context. */
3915 blf = g_new(blf_t, 1);
3916 blf->log_containers = g_array_new(false, false, sizeof(blf_log_container_t));
3917 blf->current_real_seek_pos = 0;
3918 blf->start_offset_ns = blf_get_start_offset_ns(&header.start_date);
3920 blf->channel_to_iface_ht = g_hash_table_new_full(g_int64_hash, g_int64_equal, &blf_free_key, &blf_free_channel_to_iface_entry);
3921 blf->channel_to_name_ht = g_hash_table_new_full(g_int64_hash, g_int64_equal, &blf_free_key, &blf_free_channel_to_name_entry);
3922 blf->next_interface_id = 0;
3924 wth->priv = (void *)blf;
3925 wth->file_encap = WTAP_ENCAP_NONE;
3926 wth->snapshot_length = 0;
3927 wth->file_tsprec = WTAP_TSPREC_UNKNOWN;
3928 wth->subtype_read = blf_read;
3929 wth->subtype_seek_read = blf_seek_read;
3930 wth->subtype_close = blf_close;
3931 wth->file_type_subtype = blf_file_type_subtype;
3933 return WTAP_OPEN_MINE;
3936 /* Options for interface blocks. */
3937 static const struct supported_option_type interface_block_options_supported[] = {
3938 /* No comments, just an interface name. */
3939 { OPT_IDB_NAME, ONE_OPTION_SUPPORTED }
3942 static const struct supported_block_type blf_blocks_supported[] = {
3943 { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED },
3944 { WTAP_BLOCK_IF_ID_AND_INFO, MULTIPLE_BLOCKS_SUPPORTED, OPTION_TYPES_SUPPORTED(interface_block_options_supported) },
3947 static const struct file_type_subtype_info blf_info = {
3948 "Vector Informatik Binary Logging Format (BLF) logfile", "blf", "blf", NULL,
3949 false, BLOCKS_SUPPORTED(blf_blocks_supported),
3950 NULL, NULL, NULL
3953 void register_blf(void)
3955 blf_file_type_subtype = wtap_register_file_type_subtype(&blf_info);
3958 * Register name for backwards compatibility with the
3959 * wtap_filetypes table in Lua.
3961 wtap_register_backwards_compatibility_lua_name("BLF", blf_file_type_subtype);
3965 * Editor modelines - https://www.wireshark.org/tools/modelines.html
3967 * Local variables:
3968 * c-basic-offset: 4
3969 * tab-width: 8
3970 * indent-tabs-mode: nil
3971 * End:
3973 * vi: set shiftwidth=4 tabstop=8 expandtab:
3974 * :indentSize=4:tabSize=8:noTabs=true: