dcerpc-netlogon: improve NetrLogonGetCapabilities dissection
[wireshark-sm.git] / wiretap / blf.c
blobc7f5ba76102ae8b60743174cee3f79575d84913e
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->len_compressed = GUINT64_FROM_LE(header->len_compressed);
343 header->len_uncompressed = GUINT64_FROM_LE(header->len_uncompressed);
344 header->obj_count = GUINT32_FROM_LE(header->obj_count);
345 header->obj_read = GUINT32_FROM_LE(header->obj_read);
346 fix_endianness_blf_date(&(header->start_date));
347 fix_endianness_blf_date(&(header->end_date));
348 header->length3 = GUINT32_FROM_LE(header->length3);
351 static void
352 fix_endianness_blf_blockheader(blf_blockheader_t *header) {
353 header->header_length = GUINT16_FROM_LE(header->header_length);
354 header->header_type = GUINT16_FROM_LE(header->header_type);
355 header->object_length = GUINT32_FROM_LE(header->object_length);
356 header->object_type = GUINT32_FROM_LE(header->object_type);
359 static void
360 fix_endianness_blf_logcontainerheader(blf_logcontainerheader_t *header) {
361 header->compression_method = GUINT16_FROM_LE(header->compression_method);
362 header->res1 = GUINT16_FROM_LE(header->res1);
363 header->res2 = GUINT32_FROM_LE(header->res2);
364 header->uncompressed_size = GUINT32_FROM_LE(header->uncompressed_size);
365 header->res4 = GUINT32_FROM_LE(header->res4);
368 static void
369 fix_endianness_blf_logobjectheader(blf_logobjectheader_t *header) {
370 header->flags = GUINT32_FROM_LE(header->flags);
371 header->client_index = GUINT16_FROM_LE(header->client_index);
372 header->object_version = GUINT16_FROM_LE(header->object_version);
373 header->object_timestamp = GUINT64_FROM_LE(header->object_timestamp);
376 static void
377 fix_endianness_blf_logobjectheader2(blf_logobjectheader2_t *header) {
378 header->flags = GUINT32_FROM_LE(header->flags);
379 header->object_version = GUINT16_FROM_LE(header->object_version);
380 header->object_timestamp = GUINT64_FROM_LE(header->object_timestamp);
381 header->original_timestamp = GUINT64_FROM_LE(header->object_timestamp);
384 static void
385 fix_endianness_blf_logobjectheader3(blf_logobjectheader3_t *header) {
386 header->flags = GUINT32_FROM_LE(header->flags);
387 header->static_size = GUINT16_FROM_LE(header->static_size);
388 header->object_version = GUINT16_FROM_LE(header->object_version);
389 header->object_timestamp = GUINT64_FROM_LE(header->object_timestamp);
392 static void
393 fix_endianness_blf_ethernetframeheader(blf_ethernetframeheader_t *header) {
394 header->channel = GUINT16_FROM_LE(header->channel);
395 header->direction = GUINT16_FROM_LE(header->direction);
396 header->ethtype = GUINT16_FROM_LE(header->ethtype);
397 header->tpid = GUINT16_FROM_LE(header->tpid);
398 header->tci = GUINT16_FROM_LE(header->tci);
399 header->payloadlength = GUINT16_FROM_LE(header->payloadlength);
402 static void
403 fix_endianness_blf_ethernetframeheader_ex(blf_ethernetframeheader_ex_t *header) {
404 header->struct_length = GUINT16_FROM_LE(header->struct_length);
405 header->flags = GUINT16_FROM_LE(header->flags);
406 header->channel = GUINT16_FROM_LE(header->channel);
407 header->hw_channel = GUINT16_FROM_LE(header->hw_channel);
408 header->frame_duration = GUINT64_FROM_LE(header->frame_duration);
409 header->frame_checksum = GUINT32_FROM_LE(header->frame_checksum);
410 header->direction = GUINT16_FROM_LE(header->direction);
411 header->frame_length = GUINT16_FROM_LE(header->frame_length);
412 header->frame_handle = GUINT32_FROM_LE(header->frame_handle);
413 header->error = GUINT32_FROM_LE(header->error);
416 static void
417 fix_endianness_blf_ethernet_rxerror(blf_ethernet_rxerror_t* header) {
418 header->struct_length = GUINT16_FROM_LE(header->struct_length);
419 header->channel = GUINT16_FROM_LE(header->channel);
420 header->direction = GUINT16_FROM_LE(header->direction);
421 header->hw_channel = GUINT16_FROM_LE(header->hw_channel);
422 header->frame_checksum = GUINT32_FROM_LE(header->frame_checksum);
423 header->frame_length = GUINT16_FROM_LE(header->frame_length);
424 header->error = GUINT32_FROM_LE(header->error);
427 static void
428 fix_endianness_blf_wlanframeheader(blf_wlanframeheader_t* header) {
429 header->channel = GUINT16_FROM_LE(header->channel);
430 header->flags = GUINT16_FROM_LE(header->flags);
431 header->signal_strength = GUINT16_FROM_LE(header->signal_strength);
432 header->signal_quality = GUINT16_FROM_LE(header->signal_quality);
433 header->frame_length = GUINT16_FROM_LE(header->frame_length);
436 static void
437 fix_endianness_blf_canmessage(blf_canmessage_t *header) {
438 header->channel = GUINT16_FROM_LE(header->channel);
439 header->id = GUINT32_FROM_LE(header->id);
442 static void
443 fix_endianness_blf_canmessage2_trailer(blf_canmessage2_trailer_t *header) {
444 header->frameLength_in_ns = GUINT32_FROM_LE(header->frameLength_in_ns);
445 header->reserved2 = GUINT16_FROM_LE(header->reserved1);
448 static void
449 fix_endianness_blf_canfdmessage(blf_canfdmessage_t *header) {
450 header->channel = GUINT16_FROM_LE(header->channel);
451 header->id = GUINT32_FROM_LE(header->id);
452 header->frameLength_in_ns = GUINT32_FROM_LE(header->frameLength_in_ns);
453 header->reservedCanFdMessage2 = GUINT32_FROM_LE(header->reservedCanFdMessage2);
456 static void
457 fix_endianness_blf_canfdmessage64(blf_canfdmessage64_t *header) {
458 header->id = GUINT32_FROM_LE(header->id);
459 header->frameLength_in_ns = GUINT32_FROM_LE(header->frameLength_in_ns);
460 header->flags = GUINT32_FROM_LE(header->flags);
461 header->btrCfgArb = GUINT32_FROM_LE(header->btrCfgArb);
462 header->btrCfgData = GUINT32_FROM_LE(header->btrCfgData);
463 header->timeOffsetBrsNs = GUINT32_FROM_LE(header->timeOffsetBrsNs);
464 header->timeOffsetCrcDelNs = GUINT32_FROM_LE(header->timeOffsetCrcDelNs);
465 header->bitCount = GUINT16_FROM_LE(header->bitCount);
466 header->crc = GUINT32_FROM_LE(header->crc);
469 static void
470 fix_endianness_blf_canerror(blf_canerror_t *header) {
471 header->channel = GUINT16_FROM_LE(header->channel);
472 header->length = GUINT16_FROM_LE(header->length);
475 static void
476 fix_endianness_blf_canerrorext(blf_canerrorext_t *header) {
477 header->channel = GUINT16_FROM_LE(header->channel);
478 header->length = GUINT16_FROM_LE(header->length);
479 header->flags = GUINT32_FROM_LE(header->flags);
480 header->frameLength_in_ns = GUINT32_FROM_LE(header->frameLength_in_ns);
481 header->id = GUINT32_FROM_LE(header->id);
482 header->errorCodeExt = GUINT16_FROM_LE(header->errorCodeExt);
485 static void
486 fix_endianness_blf_canfderror64(blf_canfderror64_t *header) {
487 header->flags = GUINT16_FROM_LE(header->flags);
488 header->errorCodeExt = GUINT16_FROM_LE(header->errorCodeExt);
489 header->extFlags = GUINT16_FROM_LE(header->extFlags);
490 header->id = GUINT32_FROM_LE(header->id);
491 header->frameLength_in_ns = GUINT32_FROM_LE(header->frameLength_in_ns);
492 header->btrCfgArb = GUINT32_FROM_LE(header->btrCfgArb);
493 header->btrCfgData = GUINT32_FROM_LE(header->btrCfgData);
494 header->timeOffsetBrsNs = GUINT32_FROM_LE(header->timeOffsetBrsNs);
495 header->timeOffsetCrcDelNs = GUINT32_FROM_LE(header->timeOffsetCrcDelNs);
496 header->crc = GUINT32_FROM_LE(header->crc);
497 header->errorPosition = GUINT16_FROM_LE(header->errorPosition);
500 static void
501 fix_endianness_blf_flexraydata(blf_flexraydata_t *header) {
502 header->channel = GUINT16_FROM_LE(header->channel);
503 header->messageId = GUINT16_FROM_LE(header->messageId);
504 header->crc = GUINT16_FROM_LE(header->crc);
505 header->reservedFlexRayData2 = GUINT16_FROM_LE(header->reservedFlexRayData2);
508 static void
509 fix_endianness_blf_flexraymessage(blf_flexraymessage_t *header) {
510 header->channel = GUINT16_FROM_LE(header->channel);
511 header->fpgaTick = GUINT32_FROM_LE(header->fpgaTick);
512 header->fpgaTickOverflow = GUINT32_FROM_LE(header->fpgaTickOverflow);
513 header->clientIndexFlexRayV6Message = GUINT32_FROM_LE(header->clientIndexFlexRayV6Message);
514 header->clusterTime = GUINT32_FROM_LE(header->clusterTime);
515 header->frameId = GUINT16_FROM_LE(header->frameId);
516 header->headerCrc = GUINT16_FROM_LE(header->headerCrc);
517 header->frameState = GUINT16_FROM_LE(header->frameState);
518 header->reservedFlexRayV6Message2 = GUINT16_FROM_LE(header->reservedFlexRayV6Message2);
521 static void
522 fix_endianness_blf_flexrayrcvmessage(blf_flexrayrcvmessage_t *header) {
523 header->channel = GUINT16_FROM_LE(header->channel);
524 header->version = GUINT16_FROM_LE(header->version);
525 header->channelMask = GUINT16_FROM_LE(header->channelMask);
526 header->dir = GUINT16_FROM_LE(header->dir);
527 header->clientIndex = GUINT32_FROM_LE(header->clientIndex);
528 header->clusterNo = GUINT32_FROM_LE(header->clusterNo);
529 header->frameId = GUINT16_FROM_LE(header->frameId);
530 header->headerCrc1 = GUINT16_FROM_LE(header->headerCrc1);
531 header->headerCrc2 = GUINT16_FROM_LE(header->headerCrc2);
532 header->payloadLength = GUINT16_FROM_LE(header->payloadLength);
533 header->payloadLengthValid = GUINT16_FROM_LE(header->payloadLengthValid);
534 header->cycle = GUINT16_FROM_LE(header->cycle);
535 header->tag = GUINT32_FROM_LE(header->tag);
536 header->data = GUINT32_FROM_LE(header->data);
537 header->frameFlags = GUINT32_FROM_LE(header->frameFlags);
538 header->appParameter = GUINT32_FROM_LE(header->appParameter);
539 /* this would be extra for ext format:
540 header->frameCRC = GUINT32_FROM_LE(header->frameCRC);
541 header->frameLengthInNs = GUINT32_FROM_LE(header->frameLengthInNs);
542 header->frameId1 = GUINT16_FROM_LE(header->frameId1);
543 header->pduOffset = GUINT16_FROM_LE(header->pduOffset);
544 header->blfLogMask = GUINT16_FROM_LE(header->blfLogMask);
548 static void
549 fix_endianness_blf_linmessage(blf_linmessage_t* message) {
550 message->channel = GUINT16_FROM_LE(message->channel);
551 message->crc = GUINT16_FROM_LE(message->crc);
552 /* skip the optional part
553 message->res2 = GUINT32_FROM_LE(message->res2);
557 static void
558 fix_endianness_blf_linbusevent(blf_linbusevent_t* linbusevent) {
559 linbusevent->sof = GUINT64_FROM_LE(linbusevent->sof);
560 linbusevent->eventBaudrate = GUINT32_FROM_LE(linbusevent->eventBaudrate);
561 linbusevent->channel = GUINT16_FROM_LE(linbusevent->channel);
564 static void
565 fix_endianness_blf_linsynchfieldevent(blf_linsynchfieldevent_t* linsynchfieldevent) {
566 fix_endianness_blf_linbusevent(&linsynchfieldevent->linBusEvent);
567 linsynchfieldevent->synchBreakLength = GUINT64_FROM_LE(linsynchfieldevent->synchBreakLength);
568 linsynchfieldevent->synchDelLength = GUINT64_FROM_LE(linsynchfieldevent->synchDelLength);
571 static void
572 fix_endianness_blf_linmessagedescriptor(blf_linmessagedescriptor_t* linmessagedescriptor) {
573 fix_endianness_blf_linsynchfieldevent(&linmessagedescriptor->linSynchFieldEvent);
574 linmessagedescriptor->supplierId = GUINT16_FROM_LE(linmessagedescriptor->supplierId);
575 linmessagedescriptor->messageId = GUINT16_FROM_LE(linmessagedescriptor->messageId);
578 static void
579 fix_endianness_blf_lindatabytetimestampevent(blf_lindatabytetimestampevent_t* lindatabytetimestampevent) {
580 int i;
581 fix_endianness_blf_linmessagedescriptor(&lindatabytetimestampevent->linMessageDescriptor);
582 for (i = 0; i < 9; i++) {
583 lindatabytetimestampevent->databyteTimestamps[i] = GUINT64_FROM_LE(lindatabytetimestampevent->databyteTimestamps[i]);
587 static void
588 fix_endianness_blf_linmessage2(blf_linmessage2_t* message) {
589 fix_endianness_blf_lindatabytetimestampevent(&message->linDataByteTimestampEvent);
590 message->crc = GUINT16_FROM_LE(message->crc);
591 /* skip the optional part
592 message->respBaudrate = GUINT32_FROM_LE(message->respBaudrate);
593 message->exactHeaderBaudrate = GUINT64_FROM_LE(message->exactHeaderBaudrate);
594 message->earlyStopBitOffset = GUINT32_FROM_LE(message->earlyStopBitOffset);
595 message->earlyStopBitOffsetResponse = GUINT32_FROM_LE(message->earlyStopBitOffsetResponse);
599 static void
600 fix_endianness_blf_lincrcerror2(blf_lincrcerror2_t* message) {
601 fix_endianness_blf_lindatabytetimestampevent(&message->linDataByteTimestampEvent);
602 message->crc = GUINT16_FROM_LE(message->crc);
603 /* skip the optional part
604 message->respBaudrate = GUINT32_FROM_LE(message->respBaudrate);
605 message->exactHeaderBaudrate = GUINT64_FROM_LE(message->exactHeaderBaudrate);
606 message->earlyStopBitOffset = GUINT32_FROM_LE(message->earlyStopBitOffset);
607 message->earlyStopBitOffsetResponse = GUINT32_FROM_LE(message->earlyStopBitOffsetResponse);
611 static void
612 fix_endianness_blf_linrcverror2(blf_linrcverror2_t* message) {
613 fix_endianness_blf_lindatabytetimestampevent(&message->linDataByteTimestampEvent);
614 /* skip the optional part
615 message->respBaudrate = GUINT32_FROM_LE(message->respBaudrate);
616 message->exactHeaderBaudrate = GUINT64_FROM_LE(message->exactHeaderBaudrate);
617 message->earlyStopBitOffset = GUINT32_FROM_LE(message->earlyStopBitOffset);
618 message->earlyStopBitOffsetResponse = GUINT32_FROM_LE(message->earlyStopBitOffsetResponse);
622 static void
623 fix_endianness_blf_linsenderror2(blf_linsenderror2_t* message) {
624 fix_endianness_blf_linmessagedescriptor(&message->linMessageDescriptor);
625 message->eoh = GUINT64_FROM_LE(message->eoh);
626 /* skip the optional part
627 message->exactHeaderBaudrate = GUINT64_FROM_LE(message->exactHeaderBaudrate);
628 message->earlyStopBitOffset = GUINT32_FROM_LE(message->earlyStopBitOffset);
632 static void
633 fix_endianness_blf_linwakeupevent2(blf_linwakeupevent2_t* message) {
634 fix_endianness_blf_linbusevent(&message->linBusEvent);
637 static void
638 fix_endianness_blf_apptext_header(blf_apptext_t *header) {
639 header->source = GUINT32_FROM_LE(header->source);
640 header->reservedAppText1 = GUINT32_FROM_LE(header->reservedAppText1);
641 header->textLength = GUINT32_FROM_LE(header->textLength);
642 header->reservedAppText2 = GUINT32_FROM_LE(header->reservedAppText2);
645 static void
646 fix_endianness_blf_ethernet_status_header(blf_ethernet_status_t* header) {
647 header->channel = GUINT16_FROM_LE(header->channel);
648 header->flags = GUINT16_FROM_LE(header->flags);
649 /*uint8_t linkStatus;*/
650 /*uint8_t ethernetPhy;*/
651 /*uint8_t duplex;*/
652 /*uint8_t mdi;*/
653 /*uint8_t connector;*/
654 /*uint8_t clockMode;*/
655 /*uint8_t pairs;*/
656 /*uint8_t hardwareChannel;*/
657 header->bitrate = GUINT32_FROM_LE(header->bitrate);
660 static void
661 fix_endianness_blf_ethernet_phystate_header(blf_ethernet_phystate_t* header) {
662 header->channel = GUINT16_FROM_LE(header->channel);
663 header->flags = GUINT16_FROM_LE(header->flags);
666 static void
667 blf_init_logcontainer(blf_log_container_t *tmp) {
668 tmp->infile_start_pos = 0;
669 tmp->infile_length = 0;
670 tmp->infile_data_start = 0;
671 tmp->real_start_pos = 0;
672 tmp->real_length = 0;
673 tmp->real_data = NULL;
674 tmp->compression_method = 0;
678 blf_logcontainers_cmp(const void *a, const void *b) {
679 const blf_log_container_t* container_a = (blf_log_container_t*)a;
680 const blf_log_container_t* container_b = (blf_log_container_t*)b;
682 if (container_a->real_start_pos < container_b->real_start_pos) {
683 return -1;
685 else if (container_a->real_start_pos > container_b->real_start_pos) {
686 return 1;
688 else {
689 return 0;
694 blf_logcontainers_search(const void *a, const void *b) {
695 const blf_log_container_t* container_a = (blf_log_container_t*)a;
696 uint64_t pos = *(uint64_t*)b;
698 if (container_a->real_start_pos > pos) {
699 return 1;
701 else if (pos >= container_a->real_start_pos + container_a->real_length) {
702 return -1;
704 else {
705 return 0;
709 /** Ensures the given log container is in memory
711 * If the log container already is not already in memory,
712 * it reads it from the current seek position, allocating a
713 * properly sized buffer.
714 * The file offset must be set to the start of the container
715 * data (container->infile_data_start) before calling this function.
717 static bool
718 blf_pull_logcontainer_into_memory(blf_params_t *params, blf_log_container_t *container, int *err, char **err_info) {
720 if (container == NULL) {
721 *err = WTAP_ERR_INTERNAL;
722 *err_info = ws_strdup("blf_pull_logcontainer_into_memory called with NULL container");
723 return false;
726 if (container->real_data != NULL) {
727 return true;
730 /* pull compressed data into buffer */
731 if (container->infile_start_pos < 0) {
733 * XXX - does this represent a bug (WTAP_ERR_INTERNAL) or a
734 * malformed file (WTAP_ERR_BAD_FILE)?
736 *err = WTAP_ERR_INTERNAL;
737 *err_info = ws_strdup_printf("blf_pull_logcontainer_into_memory: container.infile_start_pos (%" PRId64 ") < 0",
738 container->infile_start_pos);
739 return false;
741 if (container->infile_data_start < (uint64_t)container->infile_start_pos) {
743 * XXX - does this represent a bug (WTAP_ERR_INTERNAL) or a
744 * malformed file (WTAP_ERR_BAD_FILE)?
746 *err = WTAP_ERR_INTERNAL;
747 *err_info = ws_strdup_printf("blf_pull_logcontainer_into_memory: container.infile_data_start (%" PRIu64 ") < container.infile_start_pos (%" PRId64 ")",
748 container->infile_data_start, container->infile_start_pos);
749 return false;
751 if (container->infile_length < container->infile_data_start - (uint64_t)container->infile_start_pos) {
753 * XXX - does this represent a bug (WTAP_ERR_INTERNAL) or a
754 * malformed file (WTAP_ERR_BAD_FILE)?
756 *err = WTAP_ERR_INTERNAL;
757 *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,
758 container->infile_length,
759 container->infile_data_start, container->infile_start_pos,
760 container->infile_data_start - (uint64_t)container->infile_start_pos);
761 return false;
763 uint64_t data_length = container->infile_length - (container->infile_data_start - (uint64_t)container->infile_start_pos);
764 if (data_length > UINT_MAX) {
766 * XXX - does this represent a bug (WTAP_ERR_INTERNAL) or a
767 * malformed file (WTAP_ERR_BAD_FILE)?
769 *err = WTAP_ERR_INTERNAL;
770 *err_info = ws_strdup_printf("blf_pull_logcontainer_into_memory: data_length (%" PRIu64 ") > UINT_MAX",
771 data_length);
772 return false;
775 if (container->real_length == 0) {
776 ws_info("blf_pull_logcontainer_into_memory: found container with 0 length");
777 /* Skip empty container */
778 if (!wtap_read_bytes_or_eof(params->fh, NULL, (unsigned int)data_length, err, err_info)) {
779 if (*err == WTAP_ERR_SHORT_READ) {
781 * XXX - our caller will turn this into an EOF.
782 * How *should* it be treated?
783 * For now, we turn it into Yet Another Internal Error,
784 * pending having better documentation of the file
785 * format.
787 *err = WTAP_ERR_INTERNAL;
788 *err_info = ws_strdup("blf_pull_logcontainer_into_memory: short read on 0-length container");
790 return false;
792 return true;
795 if (container->compression_method == BLF_COMPRESSION_NONE) {
796 unsigned char* buf = g_try_malloc((size_t)container->real_length);
797 if (buf == NULL) {
798 *err = WTAP_ERR_INTERNAL;
799 *err_info = ws_strdup("blf_pull_logcontainer_into_memory: cannot allocate memory");
800 return false;
802 if (!wtap_read_bytes_or_eof(params->fh, buf, (unsigned int)data_length, err, err_info)) {
803 g_free(buf);
804 if (*err == WTAP_ERR_SHORT_READ) {
806 * XXX - our caller will turn this into an EOF.
807 * How *should* it be treated?
808 * For now, we turn it into Yet Another Internal Error,
809 * pending having better documentation of the file
810 * format.
812 *err = WTAP_ERR_INTERNAL;
813 *err_info = ws_strdup("blf_pull_logcontainer_into_memory: short read on uncompressed data");
815 return false;
817 container->real_data = buf;
818 return true;
821 else if (container->compression_method == BLF_COMPRESSION_ZLIB) {
822 #if defined (HAVE_ZLIB) || defined (HAVE_ZLIBNG)
823 unsigned char *compressed_data = g_try_malloc((size_t)data_length);
824 if (compressed_data == NULL) {
825 *err = WTAP_ERR_INTERNAL;
826 *err_info = ws_strdup("blf_pull_logcontainer_into_memory: cannot allocate memory");
827 return false;
829 if (!wtap_read_bytes_or_eof(params->fh, compressed_data, (unsigned int)data_length, err, err_info)) {
830 g_free(compressed_data);
831 if (*err == WTAP_ERR_SHORT_READ) {
833 * XXX - our caller will turn this into an EOF.
834 * How *should* it be treated?
835 * For now, we turn it into Yet Another Internal Error,
836 * pending having better documentation of the file
837 * format.
839 *err = WTAP_ERR_INTERNAL;
840 *err_info = ws_strdup("blf_pull_logcontainer_into_memory: short read on compressed data");
842 return false;
845 unsigned char *buf = g_try_malloc((size_t)container->real_length);
846 if (buf == NULL) {
847 g_free(compressed_data);
848 *err = WTAP_ERR_INTERNAL;
849 *err_info = ws_strdup("blf_pull_logcontainer_into_memory: cannot allocate memory");
850 return false;
852 zlib_stream infstream = {0};
854 infstream.avail_in = (unsigned int)data_length;
855 infstream.next_in = compressed_data;
856 infstream.avail_out = (unsigned int)container->real_length;
857 infstream.next_out = buf;
859 /* the actual DE-compression work. */
860 if (Z_OK != ZLIB_PREFIX(inflateInit)(&infstream)) {
862 * XXX - check the error code and handle this appropriately.
864 g_free(buf);
865 g_free(compressed_data);
866 *err = WTAP_ERR_INTERNAL;
867 if (infstream.msg != NULL) {
868 *err_info = ws_strdup_printf("blf_pull_logcontainer_into_memory: inflateInit failed for LogContainer, message\"%s\"",
869 infstream.msg);
870 } else {
871 *err_info = ws_strdup("blf_pull_logcontainer_into_memory: inflateInit failed for LogContainer");
873 ws_debug("inflateInit failed for LogContainer");
874 if (infstream.msg != NULL) {
875 ws_debug("inflateInit returned: \"%s\"", infstream.msg);
877 return false;
880 int ret = ZLIB_PREFIX(inflate)(&infstream, Z_NO_FLUSH);
881 /* Z_OK should not happen here since we know how big the buffer should be */
882 if (Z_STREAM_END != ret) {
883 switch (ret) {
885 case Z_NEED_DICT:
886 *err = WTAP_ERR_DECOMPRESS;
887 *err_info = ws_strdup("preset dictionary needed");
888 break;
890 case Z_STREAM_ERROR:
891 *err = WTAP_ERR_INTERNAL;
892 *err_info = ws_strdup_printf("blf_pull_logcontainer_into_memory: Z_STREAM_ERROR from inflate(), message \"%s\"",
893 (infstream.msg != NULL) ? infstream.msg : "(none)");
894 break;
896 case Z_MEM_ERROR:
897 /* This means "not enough memory". */
898 *err = ENOMEM;
899 *err_info = NULL;
900 break;
902 case Z_DATA_ERROR:
903 /* This means "deflate stream invalid" */
904 *err = WTAP_ERR_DECOMPRESS;
905 *err_info = (infstream.msg != NULL) ? ws_strdup(infstream.msg) : NULL;
906 break;
908 case Z_BUF_ERROR:
909 /* XXX - this is recoverable; what should we do here? */
910 *err = WTAP_ERR_INTERNAL;
911 *err_info = ws_strdup_printf("blf_pull_logcontainer_into_memory: Z_BUF_ERROR from inflate(), message \"%s\"",
912 (infstream.msg != NULL) ? infstream.msg : "(none)");
913 break;
915 case Z_VERSION_ERROR:
916 *err = WTAP_ERR_INTERNAL;
917 *err_info = ws_strdup_printf("blf_pull_logcontainer_into_memory: Z_VERSION_ERROR from inflate(), message \"%s\"",
918 (infstream.msg != NULL) ? infstream.msg : "(none)");
919 break;
921 default:
922 *err = WTAP_ERR_INTERNAL;
923 *err_info = ws_strdup_printf("blf_pull_logcontainer_into_memory: unexpected error %d from inflate(), message \"%s\"",
924 ret,
925 (infstream.msg != NULL) ? infstream.msg : "(none)");
926 break;
928 g_free(buf);
929 g_free(compressed_data);
930 ws_debug("inflate failed (return code %d) for LogContainer", ret);
931 if (infstream.msg != NULL) {
932 ws_debug("inflate returned: \"%s\"", infstream.msg);
934 /* Free up any dynamically-allocated memory in infstream */
935 ZLIB_PREFIX(inflateEnd)(&infstream);
936 return false;
939 if (Z_OK != ZLIB_PREFIX(inflateEnd)(&infstream)) {
941 * The zlib manual says this only returns Z_OK on success
942 * and Z_STREAM_ERROR if the stream state was inconsistent.
944 * It's not clear what useful information can be reported
945 * for Z_STREAM_ERROR; a look at the 1.2.11 source indicates
946 * that no string is returned to indicate what the problem
947 * was.
949 * It's also not clear what to do about infstream if this
950 * fails.
952 *err = WTAP_ERR_INTERNAL;
953 *err_info = ws_strdup("blf_pull_logcontainer_into_memory: inflateEnd failed for LogContainer");
954 g_free(buf);
955 g_free(compressed_data);
956 ws_debug("inflateEnd failed for LogContainer");
957 if (infstream.msg != NULL) {
958 ws_debug("inflateEnd returned: \"%s\"", infstream.msg);
960 return false;
963 g_free(compressed_data);
964 container->real_data = buf;
965 return true;
966 #else
967 (void) params;
968 *err = WTAP_ERR_DECOMPRESSION_NOT_SUPPORTED;
969 *err_info = ws_strdup("blf_pull_logcontainer_into_memory: reading gzip-compressed containers isn't supported");
970 return false;
971 #endif
974 return false;
977 /** Finds the next log container starting at the current file offset
979 * Adds the container to the containers array for later access
981 static bool
982 blf_find_next_logcontainer(blf_params_t* params, int* err, char** err_info) {
983 blf_blockheader_t header;
984 blf_logcontainerheader_t logcontainer_header;
985 blf_log_container_t tmp;
986 unsigned char* header_ptr;
987 unsigned int i;
989 uint64_t current_real_start;
990 if (params->blf_data->log_containers->len == 0) {
991 current_real_start = 0;
993 else {
994 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);
995 current_real_start = container->real_start_pos + container->real_length;
998 header_ptr = (unsigned char*)&header;
999 i = 0;
1001 /** Find Object
1003 * We read one byte at a time so that we don't have to seek backward (allows us to do a linear read)
1005 while (i < sizeof(blf_obj_magic)) {
1006 if (!wtap_read_bytes_or_eof(params->fh, &header_ptr[i], 1, err, err_info)) {
1007 ws_debug("we found end of file");
1008 return false;
1010 if (header_ptr[i] != blf_obj_magic[i]) {
1011 if (params->pipe) {
1012 ws_debug("container object magic is not LOBJ");
1014 else {
1015 ws_debug("container object magic is not LOBJ (pos: 0x%" PRIx64 ")", file_tell(params->fh) - 1);
1017 if (i > 0) {
1018 int j = i;
1020 while (memcmp(&header_ptr[i - j + 1], blf_obj_magic, j)) {
1021 /* Check if the last j bytes match the first j bytes of the magic */
1022 j--;
1025 /* The last j bytes match, and the first j bytes are already in the buffer, since j<=i */
1026 i = j;
1029 else {
1030 /* Character matches */
1031 i++;
1035 if (!wtap_read_bytes_or_eof(params->fh, &header.header_length, sizeof(blf_blockheader_t) - sizeof(blf_obj_magic), err, err_info)) {
1036 ws_debug("we found end of file");
1037 return false;
1040 fix_endianness_blf_blockheader(&header);
1042 if (header.header_length < sizeof(blf_blockheader_t)) {
1043 *err = WTAP_ERR_BAD_FILE;
1044 *err_info = ws_strdup("blf: header length too short while looking for object");
1045 return false;
1048 if (header.header_type != BLF_HEADER_TYPE_DEFAULT) {
1049 *err = WTAP_ERR_UNSUPPORTED;
1050 *err_info = ws_strdup_printf("blf: unknown header type (%u), I know only BLF_HEADER_TYPE_DEFAULT (1)", header.header_type);
1051 return false;
1054 if (header.object_length < header.header_length) {
1055 *err = WTAP_ERR_BAD_FILE;
1056 *err_info = ws_strdup("blf: header object length less than header length while looking for objects");
1057 return false;
1060 if (header.object_type == BLF_OBJTYPE_LOG_CONTAINER) {
1061 /* skip unknown header part if needed */
1062 if (header.header_length > sizeof(blf_blockheader_t)) {
1063 /* seek over unknown header part */
1064 if (!wtap_read_bytes(params->fh, NULL, header.header_length - sizeof(blf_blockheader_t), err, err_info)) {
1065 ws_debug("error skipping unknown header bytes in log container");
1066 return false;
1070 /* Read the log container header */
1071 if (!wtap_read_bytes_or_eof(params->fh, &logcontainer_header, sizeof(blf_logcontainerheader_t), err, err_info)) {
1072 ws_debug("not enough bytes for log container header");
1073 return false;
1076 fix_endianness_blf_logcontainerheader(&logcontainer_header);
1078 blf_init_logcontainer(&tmp);
1080 if (params->pipe) {
1081 tmp.infile_start_pos = 0;
1082 tmp.infile_data_start = sizeof(blf_logcontainerheader_t) + header.header_length;
1084 else {
1085 tmp.infile_data_start = file_tell(params->fh);
1086 tmp.infile_start_pos = tmp.infile_data_start - sizeof(blf_logcontainerheader_t) - header.header_length;
1088 tmp.infile_length = header.object_length;
1090 tmp.real_start_pos = current_real_start;
1091 tmp.real_length = logcontainer_header.uncompressed_size;
1092 tmp.compression_method = logcontainer_header.compression_method;
1094 ws_debug("found log container with real_pos=0x%" PRIx64 ", real_length=0x%" PRIx64, tmp.real_start_pos, tmp.real_length);
1096 else {
1097 ws_debug("found BLF object without log container");
1099 /* Create a fake log container for the lone object.
1100 * In order to avoid seeking backwards, we need to pull the fake log container now.
1102 unsigned char* buf = g_try_malloc((size_t)header.object_length);
1103 if (buf == NULL) {
1105 * XXX - we need an "out of memory" error code here.
1107 *err = WTAP_ERR_INTERNAL;
1108 *err_info = ws_strdup("blf_find_next_logcontainer: cannot allocate memory");
1109 return false;
1112 memcpy(buf, &header, sizeof(blf_blockheader_t));
1114 if (header.object_length > sizeof(blf_blockheader_t)) {
1115 if (!wtap_read_bytes(params->fh, buf + sizeof(blf_blockheader_t), header.object_length - sizeof(blf_blockheader_t), err, err_info)) {
1116 g_free(buf);
1117 ws_debug("cannot pull object without log container");
1118 return false;
1122 blf_init_logcontainer(&tmp);
1124 tmp.infile_start_pos = params->pipe ? 0 : (file_tell(params->fh) - header.object_length);
1125 tmp.infile_data_start = tmp.infile_start_pos;
1126 tmp.infile_length = header.object_length;
1128 tmp.real_start_pos = current_real_start;
1129 tmp.real_length = header.object_length;
1130 tmp.compression_method = BLF_COMPRESSION_NONE;
1132 tmp.real_data = buf;
1134 ws_debug("found non-log-container object with real_pos=0x%" PRIx64 ", real_length=0x%" PRIx64, tmp.real_start_pos, tmp.real_length);
1137 g_array_append_val(params->blf_data->log_containers, tmp);
1139 return true;
1142 static bool
1143 // NOLINTNEXTLINE(misc-no-recursion)
1144 blf_pull_next_logcontainer(blf_params_t* params, int* err, char** err_info) {
1145 blf_log_container_t* container;
1147 if (!blf_find_next_logcontainer(params, err, err_info)) {
1148 return false;
1151 /* Is there a next log container to pull? */
1152 if (params->blf_data->log_containers->len == 0) {
1153 /* No. */
1154 return false;
1157 container = &g_array_index(params->blf_data->log_containers, blf_log_container_t, params->blf_data->log_containers->len - 1);
1158 if (!blf_pull_logcontainer_into_memory(params, container, err, err_info)) {
1159 if (*err == WTAP_ERR_DECOMPRESS) {
1160 report_warning("Error while decompressing BLF log container number %u (file pos. 0x%" PRIx64 "): %s",
1161 params->blf_data->log_containers->len - 1, container->infile_start_pos, *err_info ? *err_info : "(none)");
1162 *err = 0;
1163 g_free(*err_info);
1164 *err_info = NULL;
1166 /* Skip this log container and try to get the next one. */
1167 g_array_remove_index(params->blf_data->log_containers, params->blf_data->log_containers->len - 1);
1168 /* Calling blf_pull_logcontainer_into_memory advances the file pointer. Eventually we will reach the end of the file and stop recursing. */
1169 return blf_pull_next_logcontainer(params, err, err_info);
1172 return false;
1175 return true;
1178 static bool
1179 blf_read_bytes_or_eof(blf_params_t *params, uint64_t real_pos, void *target_buffer, uint64_t count, int *err, char **err_info) {
1180 blf_log_container_t* container;
1181 unsigned container_index;
1183 uint64_t end_pos = real_pos + count;
1185 uint64_t copied = 0;
1186 uint64_t data_left;
1187 uint64_t start_in_buf;
1189 unsigned char *buf = (unsigned char *)target_buffer;
1191 if (count == 0) {
1192 ws_debug("called blf_read_bytes_or_eof with 0 count");
1193 return false;
1196 if (count > UINT32_MAX) {
1197 ws_debug("trying to read too many bytes");
1198 return false;
1201 if (params->random) {
1203 * Do a binary search for the container in which real_pos
1204 * is included.
1206 if (!g_array_binary_search(params->blf_data->log_containers, &real_pos, blf_logcontainers_search, &container_index)) {
1208 * XXX - why is this treated as an EOF rather than an error?
1209 * *err appears to be 0, which means our caller treats it as an
1210 * EOF, at least when reading the log object header.
1212 ws_debug("cannot read data because start position cannot be mapped");
1213 return false;
1215 container = &g_array_index(params->blf_data->log_containers, blf_log_container_t, container_index);
1217 else {
1218 if (params->blf_data->log_containers->len == 0) {
1220 * This is the first (linear) pass, and we haven't yet
1221 * added any containers. Pull the next log container
1222 * into memory, so that the array isn't empty.
1224 if (!blf_pull_next_logcontainer(params, err, err_info)) {
1225 return false;
1230 * Search backwards in the array, from the last entry to the
1231 * first, to find the log container in which real_pos is
1232 * included.
1234 container_index = params->blf_data->log_containers->len;
1235 do {
1236 container = &g_array_index(params->blf_data->log_containers, blf_log_container_t, --container_index);
1237 } while (real_pos < container->real_start_pos && container_index > 0); /* For some reason we skipped past the correct container */
1240 while (real_pos < end_pos) {
1242 while (real_pos >= container->real_start_pos + container->real_length) {
1243 container_index++;
1244 if (!params->random) { /* First (linear) pass */
1245 if (!blf_pull_next_logcontainer(params, err, err_info)) {
1246 return false;
1249 if (container_index >= params->blf_data->log_containers->len) {
1250 ws_debug("cannot find real_pos in container");
1251 return false;
1253 container = &g_array_index(params->blf_data->log_containers, blf_log_container_t, container_index);
1254 if (real_pos < container->real_start_pos) {
1255 ws_debug("cannot find real_pos in container");
1256 return false;
1260 if (real_pos < container->real_start_pos) {
1261 ws_debug("cannot find real_pos in container");
1262 return false;
1265 start_in_buf = real_pos - container->real_start_pos;
1267 if (params->random) {
1268 if (file_seek(params->fh, container->infile_data_start, SEEK_SET, err) == -1) {
1269 return false;
1271 if (!blf_pull_logcontainer_into_memory(params, container, err, err_info)) {
1272 return false;
1276 data_left = container->real_length - start_in_buf;
1278 if (data_left < (count - copied)) {
1279 memcpy(buf + copied, container->real_data + start_in_buf, data_left);
1280 copied += data_left;
1281 real_pos += data_left;
1283 else {
1284 memcpy(buf + copied, container->real_data + start_in_buf, count - copied);
1285 return true;
1291 * XXX - does this represent a bug (WTAP_ERR_INTERNAL) or a
1292 * malformed file (WTAP_ERR_BAD_FILE)?
1294 *err = WTAP_ERR_INTERNAL;
1295 *err_info = ws_strdup("blf_read_bytes_or_eof: ran out of containers");
1296 return false;
1299 static bool
1300 blf_read_bytes(blf_params_t *params, uint64_t real_pos, void *target_buffer, uint64_t count, int *err, char **err_info) {
1301 if (!blf_read_bytes_or_eof(params, real_pos, target_buffer, count, err, err_info)) {
1302 if (*err == 0) {
1303 *err = WTAP_ERR_SHORT_READ;
1305 return false;
1307 return true;
1310 static void
1311 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) {
1312 params->rec->rec_type = REC_TYPE_PACKET;
1313 params->rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
1314 params->rec->presence_flags = WTAP_HAS_CAP_LEN | WTAP_HAS_INTERFACE_ID;
1315 params->rec->ts_rel_cap_valid = false;
1316 switch (flags) {
1317 case BLF_TIMESTAMP_RESOLUTION_10US:
1318 params->rec->presence_flags |= WTAP_HAS_TS;
1319 params->rec->tsprec = WTAP_TSPREC_10_USEC;
1320 object_timestamp *= 10000;
1321 object_timestamp += params->blf_data->start_offset_ns;
1322 params->rec->ts_rel_cap_valid = true;
1323 break;
1325 case BLF_TIMESTAMP_RESOLUTION_1NS:
1326 params->rec->presence_flags |= WTAP_HAS_TS;
1327 params->rec->tsprec = WTAP_TSPREC_NSEC;
1328 object_timestamp += params->blf_data->start_offset_ns;
1329 params->rec->ts_rel_cap_valid = true;
1330 break;
1332 default:
1333 /* Metadata objects have both flags and timestamp equal to zero, so that combination is not an error. */
1334 if (flags != 0 || object_timestamp != 0) {
1336 * XXX - report this as an error?
1338 * Or provide a mechanism to allow file readers to report
1339 * a warning (an error that the reader tries to work
1340 * around and that the caller should report)?
1342 ws_debug("Unknown combination of flags and timestamp (0x%x, %" PRIu64 ")", flags, object_timestamp);
1343 object_timestamp = 0;
1345 break;
1347 params->rec->ts.secs = object_timestamp / (1000 * 1000 * 1000);
1348 params->rec->ts.nsecs = object_timestamp % (1000 * 1000 * 1000);
1349 params->rec->rec_header.packet_header.caplen = caplen;
1350 params->rec->rec_header.packet_header.len = len;
1352 nstime_t tmp_ts;
1353 tmp_ts.secs = params->blf_data->start_offset_ns / (1000 * 1000 * 1000);
1354 tmp_ts.nsecs = params->blf_data->start_offset_ns % (1000 * 1000 * 1000);
1355 nstime_delta(&params->rec->ts_rel_cap, &params->rec->ts, &tmp_ts);
1357 params->rec->rec_header.packet_header.pkt_encap = pkt_encap;
1358 params->rec->rec_header.packet_header.interface_id = blf_lookup_interface(params, pkt_encap, channel, hwchannel, NULL);
1360 /* TODO: before we had to remove comments and verdict here to not leak memory but APIs have changed ... */
1363 static void
1364 blf_add_direction_option(blf_params_t *params, uint16_t direction) {
1365 uint32_t tmp = 0; /* dont care */
1367 switch (direction) {
1368 case BLF_DIR_RX:
1369 tmp = 1; /* inbound */
1370 break;
1371 case BLF_DIR_TX:
1372 case BLF_DIR_TX_RQ:
1373 tmp = 2; /* outbound */
1374 break;
1377 /* pcapng.c: #define OPT_EPB_FLAGS 0x0002 */
1378 wtap_block_add_uint32_option(params->rec->block, 0x0002, tmp);
1381 static bool
1382 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) {
1383 if (data_start - header2_start < (int64_t)sizeof(blf_logobjectheader_t)) {
1384 *err = WTAP_ERR_BAD_FILE;
1385 *err_info = ws_strdup("blf: not enough bytes for log object header");
1386 ws_debug("not enough bytes for timestamp header");
1387 return false;
1390 if (!blf_read_bytes_or_eof(params, header2_start, logheader, sizeof(*logheader), err, err_info)) {
1391 ws_debug("not enough bytes for logheader");
1392 return false;
1394 fix_endianness_blf_logobjectheader(logheader);
1395 return true;
1398 static bool
1399 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) {
1400 if (data_start - header2_start < (int64_t)sizeof(blf_logobjectheader2_t)) {
1401 *err = WTAP_ERR_BAD_FILE;
1402 *err_info = ws_strdup("blf: not enough bytes for log object header");
1403 ws_debug("not enough bytes for timestamp header");
1404 return false;
1407 if (!blf_read_bytes_or_eof(params, header2_start, logheader, sizeof(*logheader), err, err_info)) {
1408 ws_debug("not enough bytes for logheader");
1409 return false;
1411 fix_endianness_blf_logobjectheader2(logheader);
1412 return true;
1415 static bool
1416 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) {
1417 if (data_start - header2_start < (int64_t)sizeof(blf_logobjectheader3_t)) {
1418 *err = WTAP_ERR_BAD_FILE;
1419 *err_info = ws_strdup("blf: not enough bytes for log object header");
1420 ws_debug("not enough bytes for timestamp header");
1421 return false;
1424 if (!blf_read_bytes_or_eof(params, header2_start, logheader, sizeof(*logheader), err, err_info)) {
1425 ws_debug("not enough bytes for logheader");
1426 return false;
1428 fix_endianness_blf_logobjectheader3(logheader);
1429 return true;
1432 static bool
1433 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) {
1434 blf_ethernetframeheader_t ethheader;
1435 uint8_t tmpbuf[18];
1436 unsigned caplen, len;
1438 if (object_length < (data_start - block_start) + (int) sizeof(blf_ethernetframeheader_t)) {
1439 *err = WTAP_ERR_BAD_FILE;
1440 *err_info = ws_strdup("blf: ETHERNET_FRAME: not enough bytes for ethernet frame header in object");
1441 ws_debug("not enough bytes for ethernet frame header in object");
1442 return false;
1445 if (!blf_read_bytes(params, data_start, &ethheader, sizeof(ethheader), err, err_info)) {
1446 ws_debug("not enough bytes for ethernet frame header in file");
1447 return false;
1449 fix_endianness_blf_ethernetframeheader(&ethheader);
1452 * BLF breaks up and reorders the Ethernet header and VLAN tag fields.
1453 * This is a really bad design and makes this format one of the worst.
1454 * If you want a fast format that keeps your data intact, avoid this format!
1455 * So, lets hope we can reconstruct the original packet successfully.
1458 tmpbuf[0] = ethheader.dst_addr[0];
1459 tmpbuf[1] = ethheader.dst_addr[1];
1460 tmpbuf[2] = ethheader.dst_addr[2];
1461 tmpbuf[3] = ethheader.dst_addr[3];
1462 tmpbuf[4] = ethheader.dst_addr[4];
1463 tmpbuf[5] = ethheader.dst_addr[5];
1464 tmpbuf[6] = ethheader.src_addr[0];
1465 tmpbuf[7] = ethheader.src_addr[1];
1466 tmpbuf[8] = ethheader.src_addr[2];
1467 tmpbuf[9] = ethheader.src_addr[3];
1468 tmpbuf[10] = ethheader.src_addr[4];
1469 tmpbuf[11] = ethheader.src_addr[5];
1471 if (ethheader.tpid != 0 && ethheader.tci != 0) {
1472 tmpbuf[12] = (ethheader.tpid & 0xff00) >> 8;
1473 tmpbuf[13] = (ethheader.tpid & 0x00ff);
1474 tmpbuf[14] = (ethheader.tci & 0xff00) >> 8;
1475 tmpbuf[15] = (ethheader.tci & 0x00ff);
1476 tmpbuf[16] = (ethheader.ethtype & 0xff00) >> 8;
1477 tmpbuf[17] = (ethheader.ethtype & 0x00ff);
1478 ws_buffer_assure_space(params->buf, (size_t)18 + ethheader.payloadlength);
1479 ws_buffer_append(params->buf, tmpbuf, (size_t)18);
1480 caplen = ((uint32_t)18 + ethheader.payloadlength);
1481 len = ((uint32_t)18 + ethheader.payloadlength);
1482 } else {
1483 tmpbuf[12] = (ethheader.ethtype & 0xff00) >> 8;
1484 tmpbuf[13] = (ethheader.ethtype & 0x00ff);
1485 ws_buffer_assure_space(params->buf, (size_t)14 + ethheader.payloadlength);
1486 ws_buffer_append(params->buf, tmpbuf, (size_t)14);
1487 caplen = ((uint32_t)14 + ethheader.payloadlength);
1488 len = ((uint32_t)14 + ethheader.payloadlength);
1491 if (!blf_read_bytes(params, data_start + sizeof(blf_ethernetframeheader_t), ws_buffer_end_ptr(params->buf), ethheader.payloadlength, err, err_info)) {
1492 ws_debug("copying ethernet frame failed");
1493 return false;
1495 params->buf->first_free += ethheader.payloadlength;
1497 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_ETHERNET, ethheader.channel, UINT16_MAX, caplen, len);
1498 blf_add_direction_option(params, ethheader.direction);
1500 return true;
1503 static bool
1504 blf_read_ethernetframe_ext(blf_params_t *params, int *err, char **err_info, int64_t block_start,int64_t data_start,
1505 int64_t object_length, uint32_t flags, uint64_t object_timestamp, gboolean error) {
1506 blf_ethernetframeheader_ex_t ethheader;
1508 if (object_length < (data_start - block_start) + (int) sizeof(blf_ethernetframeheader_ex_t)) {
1509 *err = WTAP_ERR_BAD_FILE;
1510 *err_info = ws_strdup_printf("blf: %s: not enough bytes for ethernet frame header in object", error ? "ETHERNET_ERROR_EX" : "ETHERNET_FRAME_EX");
1511 ws_debug("not enough bytes for ethernet frame header in object");
1512 return false;
1515 if (!blf_read_bytes(params, data_start, &ethheader, sizeof(blf_ethernetframeheader_ex_t), err, err_info)) {
1516 ws_debug("not enough bytes for ethernet frame header in file");
1517 return false;
1519 fix_endianness_blf_ethernetframeheader_ex(&ethheader);
1521 ws_buffer_assure_space(params->buf, ethheader.frame_length);
1523 if (object_length - (data_start - block_start) - sizeof(blf_ethernetframeheader_ex_t) < ethheader.frame_length) {
1524 *err = WTAP_ERR_BAD_FILE;
1525 *err_info = ws_strdup_printf("blf: %s: frame too short", error ? "ETHERNET_ERROR_EX" : "ETHERNET_FRAME_EX");
1526 ws_debug("frame too short");
1527 return false;
1530 if (!blf_read_bytes(params, data_start + sizeof(blf_ethernetframeheader_ex_t), ws_buffer_start_ptr(params->buf), ethheader.frame_length, err, err_info)) {
1531 ws_debug("copying ethernet frame failed");
1532 return false;
1535 if (ethheader.flags & BLF_ETHERNET_EX_HARDWARECHANNEL) {
1536 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_ETHERNET, ethheader.channel, ethheader.hw_channel, ethheader.frame_length, ethheader.frame_length);
1537 wtap_block_add_uint32_option(params->rec->block, OPT_PKT_QUEUE, ethheader.hw_channel);
1539 else {
1540 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_ETHERNET, ethheader.channel, UINT16_MAX, ethheader.frame_length, ethheader.frame_length);
1543 blf_add_direction_option(params, ethheader.direction);
1545 return true;
1548 static bool
1549 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) {
1550 blf_ethernet_rxerror_t ethheader;
1552 if (object_length < (data_start - block_start) + (int)sizeof(blf_ethernet_rxerror_t)) {
1553 *err = WTAP_ERR_BAD_FILE;
1554 *err_info = ws_strdup("blf: ETHERNET_RXERROR: not enough bytes for ethernet frame header in object");
1555 ws_debug("not enough bytes for ethernet rx error header in object");
1556 return false;
1559 if (!blf_read_bytes(params, data_start, &ethheader, sizeof(blf_ethernet_rxerror_t), err, err_info)) {
1560 ws_debug("not enough bytes for ethernet rx error header in file");
1561 return false;
1563 fix_endianness_blf_ethernet_rxerror(&ethheader);
1565 ws_buffer_assure_space(params->buf, ethheader.frame_length);
1567 if (object_length - (data_start - block_start) < ethheader.frame_length) {
1568 *err = WTAP_ERR_BAD_FILE;
1569 *err_info = ws_strdup("blf: ETHERNET_RXERROR: frame too short");
1570 ws_debug("frame too short");
1571 return false;
1574 if (!blf_read_bytes(params, data_start + sizeof(blf_ethernet_rxerror_t), ws_buffer_start_ptr(params->buf), ethheader.frame_length, err, err_info)) {
1575 ws_debug("copying ethernet rx error failed");
1576 return false;
1579 if (ethheader.hw_channel != 0) { /* In this object type, a value of 0 is considered invalid. */
1580 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_ETHERNET, ethheader.channel, ethheader.hw_channel, ethheader.frame_length, ethheader.frame_length);
1581 wtap_block_add_uint32_option(params->rec->block, OPT_PKT_QUEUE, ethheader.hw_channel);
1583 else {
1584 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_ETHERNET, ethheader.channel, UINT16_MAX, ethheader.frame_length, ethheader.frame_length);
1586 blf_add_direction_option(params, ethheader.direction);
1588 return true;
1592 * XXX - provide radio information to our caller in the pseudo-header.
1594 static bool
1595 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) {
1596 blf_wlanframeheader_t wlanheader;
1598 if (object_length < (data_start - block_start) + (int)sizeof(blf_wlanframeheader_t)) {
1599 *err = WTAP_ERR_BAD_FILE;
1600 *err_info = ws_strdup("blf: WLAN_FRAME: not enough bytes for wlan frame header in object");
1601 ws_debug("not enough bytes for wlan frame header in object");
1602 return false;
1605 if (!blf_read_bytes(params, data_start, &wlanheader, sizeof(blf_wlanframeheader_t), err, err_info)) {
1606 ws_debug("not enough bytes for wlan frame header in file");
1607 return false;
1609 fix_endianness_blf_wlanframeheader(&wlanheader);
1611 ws_buffer_assure_space(params->buf, wlanheader.frame_length);
1613 if (object_length - (data_start - block_start) - sizeof(blf_wlanframeheader_t) < wlanheader.frame_length) {
1614 *err = WTAP_ERR_BAD_FILE;
1615 *err_info = ws_strdup("blf: WLAN_FRAME: frame too short");
1616 ws_debug("frame too short");
1617 return false;
1620 if (!blf_read_bytes(params, data_start + sizeof(blf_wlanframeheader_t), ws_buffer_start_ptr(params->buf), wlanheader.frame_length, err, err_info)) {
1621 ws_debug("copying wlan frame failed");
1622 return false;
1625 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_IEEE_802_11, wlanheader.channel, UINT16_MAX, wlanheader.frame_length, wlanheader.frame_length);
1626 blf_add_direction_option(params, wlanheader.direction);
1628 return true;
1631 static uint8_t can_dlc_to_length[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8 };
1632 static uint8_t canfd_dlc_to_length[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64 };
1634 static bool
1635 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,
1636 uint32_t flags, uint64_t object_timestamp, uint16_t channel, uint8_t canfd_flags) {
1637 uint8_t tmpbuf[8];
1638 unsigned caplen, len;
1640 tmpbuf[0] = (canid & 0xff000000) >> 24;
1641 tmpbuf[1] = (canid & 0x00ff0000) >> 16;
1642 tmpbuf[2] = (canid & 0x0000ff00) >> 8;
1643 tmpbuf[3] = (canid & 0x000000ff);
1644 tmpbuf[4] = payload_length;
1645 tmpbuf[5] = canfd_flags;
1646 tmpbuf[6] = 0;
1647 tmpbuf[7] = 0;
1649 ws_buffer_assure_space(params->buf, sizeof(tmpbuf) + payload_length_valid);
1650 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
1651 caplen = sizeof(tmpbuf) + payload_length_valid;
1652 len = sizeof(tmpbuf) + payload_length;
1654 if (payload_length_valid > 0 && !blf_read_bytes(params, start_position, ws_buffer_end_ptr(params->buf), payload_length_valid, err, err_info)) {
1655 ws_debug("copying can payload failed");
1656 return false;
1658 params->buf->first_free += payload_length_valid;
1660 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_SOCKETCAN, channel, UINT16_MAX, caplen, len);
1662 return true;
1665 static bool
1666 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) {
1667 blf_canmessage_t canheader;
1668 blf_canmessage2_trailer_t can2trailer;
1670 uint32_t canid;
1671 uint8_t payload_length;
1673 if (object_length < (data_start - block_start) + (int) sizeof(canheader)) {
1674 *err = WTAP_ERR_BAD_FILE;
1675 *err_info = ws_strdup_printf("blf: %s: not enough bytes for can header in object",
1676 can_message2 ? "CAN_MESSAGE2" : "CAN_MESSAGE");
1677 ws_debug("not enough bytes for can header in object");
1678 return false;
1681 if (!blf_read_bytes(params, data_start, &canheader, sizeof(canheader), err, err_info)) {
1682 ws_debug("not enough bytes for can header in file");
1683 return false;
1685 fix_endianness_blf_canmessage(&canheader);
1687 canheader.dlc &= 0x0f;
1689 payload_length = canheader.dlc;
1690 if (payload_length > 8) {
1691 ws_debug("regular CAN tries more than 8 bytes? Cutting to 8!");
1692 payload_length = 8;
1695 canid = canheader.id;
1697 if ((canheader.flags & BLF_CANMESSAGE_FLAG_RTR) == BLF_CANMESSAGE_FLAG_RTR) {
1698 canid |= CAN_RTR_FLAG;
1699 payload_length = 0;
1702 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)) {
1703 return false;
1706 /* actually, we do not really need the data, right now.... */
1707 if (can_message2) {
1708 if (object_length < (data_start - block_start) + (int) sizeof(canheader) + 8 + (int) sizeof(can2trailer)) {
1709 *err = WTAP_ERR_BAD_FILE;
1710 *err_info = ws_strdup("blf: CAN_MESSAGE2: not enough bytes for can message 2 trailer");
1711 ws_debug("not enough bytes for can message 2 trailer");
1712 return false;
1714 if (!blf_read_bytes(params, data_start + sizeof(canheader) + 8, &can2trailer, sizeof(can2trailer), err, err_info)) {
1715 ws_debug("not enough bytes for can message 2 trailer in file");
1716 return false;
1718 fix_endianness_blf_canmessage2_trailer(&can2trailer);
1721 blf_add_direction_option(params, (canheader.flags & BLF_CANMESSAGE_FLAG_TX) == BLF_CANMESSAGE_FLAG_TX ? BLF_DIR_TX: BLF_DIR_RX);
1723 return true;
1726 static bool
1727 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) {
1728 blf_canfdmessage_t canheader;
1730 bool canfd;
1731 uint32_t canid;
1732 uint8_t payload_length;
1733 uint8_t payload_length_valid;
1734 uint8_t canfd_flags;
1736 if (object_length < (data_start - block_start) + (int) sizeof(canheader)) {
1737 *err = WTAP_ERR_BAD_FILE;
1738 *err_info = ws_strdup("blf: CAN_FD_MESSAGE: not enough bytes for canfd header in object");
1739 ws_debug("not enough bytes for canfd header in object");
1740 return false;
1743 if (!blf_read_bytes(params, data_start, &canheader, sizeof(canheader), err, err_info)) {
1744 ws_debug("not enough bytes for canfd header in file");
1745 return false;
1747 fix_endianness_blf_canfdmessage(&canheader);
1749 canheader.dlc &= 0x0f;
1751 canfd = (canheader.canfdflags & BLF_CANFDMESSAGE_CANFDFLAG_EDL) == BLF_CANFDMESSAGE_CANFDFLAG_EDL;
1752 if (canfd) {
1753 payload_length = canfd_dlc_to_length[canheader.dlc];
1754 canfd_flags = (canheader.canfdflags & BLF_CANFDMESSAGE_CANFDFLAG_EDL) << 2 | (canheader.canfdflags & BLF_CANFDMESSAGE_CANFDFLAG_ESI) >> 1 | (canheader.canfdflags & BLF_CANFDMESSAGE_CANFDFLAG_BRS) >> 1;
1755 } else {
1756 if (canheader.dlc > 8) {
1757 ws_debug("regular CAN tries more than 8 bytes?");
1759 payload_length = can_dlc_to_length[canheader.dlc];
1760 canfd_flags = 0;
1763 if (payload_length > canheader.validDataBytes) {
1764 ws_debug("shortening canfd payload because valid data bytes shorter!");
1765 payload_length = canheader.validDataBytes;
1768 canid = canheader.id;
1770 if (!canfd && (canheader.flags & BLF_CANMESSAGE_FLAG_RTR) == BLF_CANMESSAGE_FLAG_RTR) {
1771 canid |= CAN_RTR_FLAG;
1772 payload_length = 0; /* Should already be zero from validDataBytes */
1775 payload_length_valid = payload_length;
1777 if (payload_length_valid > object_length - (data_start - block_start) + sizeof(canheader)) {
1778 ws_debug("shortening can payload because buffer is too short!");
1779 payload_length_valid = (uint8_t)(object_length - (data_start - block_start));
1782 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)) {
1783 return false;
1786 blf_add_direction_option(params, (canheader.flags & BLF_CANMESSAGE_FLAG_TX) == BLF_CANMESSAGE_FLAG_TX ? BLF_DIR_TX : BLF_DIR_RX);
1788 return true;
1791 static bool
1792 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) {
1793 blf_canfdmessage64_t canheader;
1795 bool canfd;
1796 uint32_t canid;
1797 uint8_t payload_length;
1798 uint8_t payload_length_valid;
1799 uint8_t canfd_flags;
1801 if (object_length < (data_start - block_start) + (int) sizeof(canheader)) {
1802 *err = WTAP_ERR_BAD_FILE;
1803 *err_info = ws_strdup("blf: CAN_FD_MESSAGE_64: not enough bytes for canfd header in object");
1804 ws_debug("not enough bytes for canfd header in object");
1805 return false;
1808 if (!blf_read_bytes(params, data_start, &canheader, sizeof(canheader), err, err_info)) {
1809 ws_debug("not enough bytes for canfd header in file");
1810 return false;
1812 fix_endianness_blf_canfdmessage64(&canheader);
1814 canheader.dlc &= 0x0f;
1816 canfd = (canheader.flags & BLF_CANFDMESSAGE64_FLAG_EDL) == BLF_CANFDMESSAGE64_FLAG_EDL;
1817 if (canfd) {
1818 payload_length = canfd_dlc_to_length[canheader.dlc];
1819 canfd_flags = (canheader.flags & BLF_CANFDMESSAGE64_FLAG_EDL) >> 10 | (canheader.flags & BLF_CANFDMESSAGE64_FLAG_ESI) >> 13 | (canheader.flags & BLF_CANFDMESSAGE64_FLAG_BRS) >> 13;
1820 } else {
1821 if (canheader.dlc > 8) {
1822 ws_debug("regular CAN tries more than 8 bytes?");
1824 payload_length = can_dlc_to_length[canheader.dlc];
1825 canfd_flags = 0;
1828 if (payload_length > canheader.validDataBytes) {
1829 ws_debug("shortening canfd payload because valid data bytes shorter!");
1830 payload_length = canheader.validDataBytes;
1833 canid = canheader.id;
1835 if (!canfd && (canheader.flags & BLF_CANFDMESSAGE64_FLAG_REMOTE_FRAME) == BLF_CANFDMESSAGE64_FLAG_REMOTE_FRAME) {
1836 canid |= CAN_RTR_FLAG;
1837 payload_length = 0; /* Should already be zero from validDataBytes */
1840 payload_length_valid = payload_length;
1842 if (payload_length_valid > object_length - (data_start - block_start)) {
1843 ws_debug("shortening can payload because buffer is too short!");
1844 payload_length_valid = (uint8_t)(object_length - (data_start - block_start));
1847 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)) {
1848 return false;
1851 blf_add_direction_option(params, canheader.dir);
1853 return true;
1856 static bool
1857 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) {
1858 blf_canerror_t canheader;
1859 uint32_t canid;
1860 uint8_t payload_length;
1861 uint8_t tmpbuf[16] = {0};
1863 if (object_length < (data_start - block_start) + (int) sizeof(canheader)) {
1864 *err = WTAP_ERR_BAD_FILE;
1865 *err_info = ws_strdup("blf: CAN_ERROR: not enough bytes for canerror header in object");
1866 ws_debug("not enough bytes for canerror header in object");
1867 return false;
1870 if (!blf_read_bytes(params, data_start, &canheader, sizeof(canheader), err, err_info)) {
1871 ws_debug("not enough bytes for canerror header in file");
1872 return false;
1874 fix_endianness_blf_canerror(&canheader);
1876 // Set CAN_ERR_FLAG in unused bits of Can ID to indicate error in socketcan
1877 canid = CAN_ERR_FLAG;
1879 // Fixed packet data length for socketcan error messages
1880 payload_length = CAN_ERR_DLC;
1882 if (overload) {
1883 tmpbuf[10] = CAN_ERR_PROT_OVERLOAD;
1884 canid |= CAN_ERR_PROT;
1887 tmpbuf[0] = (canid & 0xff000000) >> 24;
1888 tmpbuf[1] = (canid & 0x00ff0000) >> 16;
1889 tmpbuf[2] = (canid & 0x0000ff00) >> 8;
1890 tmpbuf[3] = (canid & 0x000000ff);
1891 tmpbuf[4] = payload_length;
1893 ws_buffer_assure_space(params->buf, sizeof(tmpbuf));
1894 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
1896 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_SOCKETCAN, canheader.channel, UINT16_MAX, sizeof(tmpbuf), sizeof(tmpbuf));
1897 return true;
1900 static bool
1901 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) {
1902 blf_canerrorext_t canheader;
1904 bool err_ack = false;
1905 bool err_prot = false;
1906 bool direction_tx;
1907 uint32_t canid;
1908 uint8_t payload_length;
1909 uint8_t tmpbuf[16] = {0};
1911 if (object_length < (data_start - block_start) + (int) sizeof(canheader)) {
1912 *err = WTAP_ERR_BAD_FILE;
1913 *err_info = ws_strdup("blf: CAN_ERROR_EXT: not enough bytes for canerrorext header in object");
1914 ws_debug("not enough bytes for canerrorext header in object");
1915 return false;
1918 if (!blf_read_bytes(params, data_start, &canheader, sizeof(canheader), err, err_info)) {
1919 ws_debug("not enough bytes for canerrorext header in file");
1920 return false;
1922 fix_endianness_blf_canerrorext(&canheader);
1924 if (canheader.flags & BLF_CANERROREXT_FLAG_CANCORE) {
1925 // Map Vector Can Core error codes to compareable socketcan errors
1926 switch ((canheader.errorCodeExt >> 6) & 0x3f) {
1927 case BLF_CANERROREXT_ECC_MEANING_BIT_ERROR:
1928 err_prot = true;
1929 tmpbuf[10] = CAN_ERR_PROT_BIT;
1930 break;
1931 case BLF_CANERROREXT_ECC_MEANING_FORM_ERROR:
1932 err_prot = true;
1933 tmpbuf[10] = CAN_ERR_PROT_FORM;
1934 break;
1935 case BLF_CANERROREXT_ECC_MEANING_STUFF_ERROR:
1936 err_prot = true;
1937 tmpbuf[10] = CAN_ERR_PROT_STUFF;
1938 break;
1939 case BLF_CANERROREXT_ECC_MEANING_CRC_ERROR:
1940 err_prot = true;
1941 tmpbuf[11] = CAN_ERR_PROT_LOC_CRC_SEQ;
1942 break;
1943 case BLF_CANERROREXT_ECC_MEANING_NACK_ERROR:
1944 err_ack = true;
1945 tmpbuf[11] = CAN_ERR_PROT_LOC_ACK;
1946 break;
1947 case BLF_CANERROREXT_ECC_MEANING_OVERLOAD:
1948 err_prot = true;
1949 tmpbuf[10] = CAN_ERR_PROT_OVERLOAD;
1950 break;
1951 default:
1952 err_prot = true;
1953 tmpbuf[10] = CAN_ERR_PROT_UNSPEC;
1954 break;
1956 err_ack = err_ack || (canheader.errorCodeExt & BLF_CANERROREXT_EXTECC_NOT_ACK) == 0x0;
1957 if (err_ack) {
1958 // Don't set protocol error on ack errors
1959 err_prot = false;
1963 // CanID contains error class in socketcan
1964 canid = CAN_ERR_FLAG;
1965 canid |= err_prot ? CAN_ERR_PROT : 0;
1966 canid |= err_ack ? CAN_ERR_ACK : 0;
1968 // Fixed packet data length for socketcan error messages
1969 payload_length = CAN_ERR_DLC;
1970 canheader.dlc = payload_length;
1972 tmpbuf[0] = (canid & 0xff000000) >> 24;
1973 tmpbuf[1] = (canid & 0x00ff0000) >> 16;
1974 tmpbuf[2] = (canid & 0x0000ff00) >> 8;
1975 tmpbuf[3] = (canid & 0x000000ff);
1976 tmpbuf[4] = payload_length;
1978 ws_buffer_assure_space(params->buf, sizeof(tmpbuf));
1979 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
1981 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_SOCKETCAN, canheader.channel, UINT16_MAX, sizeof(tmpbuf), sizeof(tmpbuf));
1982 if (canheader.flags & BLF_CANERROREXT_FLAG_CANCORE) {
1983 direction_tx = (canheader.errorCodeExt & BLF_CANERROREXT_EXTECC_TX) == BLF_CANERROREXT_EXTECC_TX;
1984 blf_add_direction_option(params, direction_tx ? BLF_DIR_TX: BLF_DIR_RX);
1986 return true;
1989 static bool
1990 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) {
1991 blf_canfderror64_t canheader;
1993 bool err_ack = false;
1994 bool err_prot = false;
1995 bool direction_tx;
1996 uint32_t canid;
1997 uint8_t payload_length;
1998 uint8_t tmpbuf[16] = {0};
2000 if (object_length < (data_start - block_start) + (int) sizeof(canheader)) {
2001 *err = WTAP_ERR_BAD_FILE;
2002 *err_info = ws_strdup("blf: CAN_FD_ERROR_64: not enough bytes for canfderror header in object");
2003 ws_debug("not enough bytes for canfderror header in object");
2004 return false;
2007 if (!blf_read_bytes(params, data_start, &canheader, sizeof(canheader), err, err_info)) {
2008 ws_debug("not enough bytes for canfderror header in file");
2009 return false;
2011 fix_endianness_blf_canfderror64(&canheader);
2013 if (canheader.flags & BLF_CANERROREXT_FLAG_CANCORE) {
2014 // Map Vector Can Core error codes to compareable socketcan errors
2015 switch ((canheader.errorCodeExt >> 6) & 0x3f) {
2016 case BLF_CANERROREXT_ECC_MEANING_BIT_ERROR:
2017 err_prot = true;
2018 tmpbuf[10] = CAN_ERR_PROT_BIT;
2019 break;
2020 case BLF_CANERROREXT_ECC_MEANING_FORM_ERROR:
2021 err_prot = true;
2022 tmpbuf[10] = CAN_ERR_PROT_FORM;
2023 break;
2024 case BLF_CANERROREXT_ECC_MEANING_STUFF_ERROR:
2025 err_prot = true;
2026 tmpbuf[10] = CAN_ERR_PROT_STUFF;
2027 break;
2028 case BLF_CANERROREXT_ECC_MEANING_CRC_ERROR:
2029 err_prot = true;
2030 tmpbuf[11] = CAN_ERR_PROT_LOC_CRC_SEQ;
2031 break;
2032 case BLF_CANERROREXT_ECC_MEANING_NACK_ERROR:
2033 err_ack = true;
2034 tmpbuf[11] = CAN_ERR_PROT_LOC_ACK;
2035 break;
2036 case BLF_CANERROREXT_ECC_MEANING_OVERLOAD:
2037 err_prot = true;
2038 tmpbuf[10] = CAN_ERR_PROT_OVERLOAD;
2039 break;
2040 default:
2041 err_prot = true;
2042 tmpbuf[10] = CAN_ERR_PROT_UNSPEC;
2043 break;
2045 err_ack = err_ack || (canheader.errorCodeExt & BLF_CANERROREXT_EXTECC_NOT_ACK) == 0x0;
2046 if (err_ack) {
2047 // Don't set protocol error on ack errors
2048 err_prot = false;
2052 // CanID contains error class in socketcan
2053 canid = CAN_ERR_FLAG;
2054 canid |= err_prot ? CAN_ERR_PROT : 0;
2055 canid |= err_ack ? CAN_ERR_ACK : 0;
2057 // Fixed packet data length for socketcan error messages
2058 payload_length = CAN_ERR_DLC;
2059 canheader.dlc = payload_length;
2061 tmpbuf[0] = (canid & 0xff000000) >> 24;
2062 tmpbuf[1] = (canid & 0x00ff0000) >> 16;
2063 tmpbuf[2] = (canid & 0x0000ff00) >> 8;
2064 tmpbuf[3] = (canid & 0x000000ff);
2065 tmpbuf[4] = payload_length;
2066 // Don't set FDF, ESI and BRS flags, since error messages are always encapsulated in Classic CAN frames
2068 ws_buffer_assure_space(params->buf, sizeof(tmpbuf));
2069 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2071 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_SOCKETCAN, canheader.channel, UINT16_MAX, sizeof(tmpbuf), sizeof(tmpbuf));
2072 if (canheader.flags & BLF_CANERROREXT_FLAG_CANCORE) {
2073 direction_tx = (canheader.errorCodeExt & BLF_CANERROREXT_EXTECC_TX) == BLF_CANERROREXT_EXTECC_TX;
2074 blf_add_direction_option(params, direction_tx ? BLF_DIR_TX: BLF_DIR_RX);
2076 return true;
2079 static bool
2080 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) {
2081 blf_flexraydata_t frheader;
2083 uint8_t payload_length;
2084 uint8_t payload_length_valid;
2085 uint8_t tmpbuf[7];
2086 unsigned caplen, len;
2088 if (object_length < (data_start - block_start) + (int) sizeof(frheader)) {
2089 *err = WTAP_ERR_BAD_FILE;
2090 *err_info = ws_strdup("blf: FLEXRAY_DATA: not enough bytes for flexrayheader in object");
2091 ws_debug("not enough bytes for flexrayheader in object");
2092 return false;
2095 if (!blf_read_bytes(params, data_start, &frheader, sizeof(frheader), err, err_info)) {
2096 ws_debug("not enough bytes for flexrayheader header in file");
2097 return false;
2099 fix_endianness_blf_flexraydata(&frheader);
2101 payload_length = frheader.len;
2102 payload_length_valid = payload_length;
2104 if ((frheader.len & 0x01) == 0x01) {
2105 ws_debug("reading odd length in FlexRay!?");
2108 if (payload_length_valid > object_length - (data_start - block_start) - sizeof(frheader)) {
2109 ws_debug("shortening FlexRay payload because buffer is too short!");
2110 payload_length_valid = (uint8_t)(object_length - (data_start - block_start) - sizeof(frheader));
2113 if (frheader.channel != 0 && frheader.channel != 1) {
2114 ws_debug("FlexRay supports only two channels.");
2117 /* Measurement Header */
2118 if (frheader.channel == 0) {
2119 tmpbuf[0] = BLF_FLEXRAYDATA_FRAME;
2120 } else {
2121 tmpbuf[0] = BLF_FLEXRAYDATA_FRAME | BLF_FLEXRAYDATA_CHANNEL_B;
2124 /* Error Flags */
2125 tmpbuf[1] = 0;
2127 /* Frame Header */
2128 tmpbuf[2] = 0x20 | ((0x0700 & frheader.messageId) >> 8);
2129 tmpbuf[3] = 0x00ff & frheader.messageId;
2130 tmpbuf[4] = (0xfe & frheader.len) | ((frheader.crc & 0x0400) >> 10);
2131 tmpbuf[5] = (0x03fc & frheader.crc) >> 2;
2132 tmpbuf[6] = ((0x0003 & frheader.crc) << 6) | (0x3f & frheader.mux);
2134 ws_buffer_assure_space(params->buf, sizeof(tmpbuf) + payload_length_valid);
2135 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2136 caplen = sizeof(tmpbuf) + payload_length_valid;
2137 len = sizeof(tmpbuf) + payload_length;
2139 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)) {
2140 ws_debug("copying flexray payload failed");
2141 return false;
2143 params->buf->first_free += payload_length_valid;
2145 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_FLEXRAY, frheader.channel, UINT16_MAX, caplen, len);
2146 blf_add_direction_option(params, frheader.dir);
2148 return true;
2151 static bool
2152 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) {
2153 blf_flexraymessage_t frheader;
2155 uint8_t payload_length;
2156 uint8_t payload_length_valid;
2157 uint8_t tmpbuf[7];
2158 unsigned caplen, len;
2160 if (object_length < (data_start - block_start) + (int) sizeof(frheader)) {
2161 *err = WTAP_ERR_BAD_FILE;
2162 *err_info = ws_strdup("blf: FLEXRAY_MESSAGE: not enough bytes for flexrayheader in object");
2163 ws_debug("not enough bytes for flexrayheader in object");
2164 return false;
2167 if (!blf_read_bytes(params, data_start, &frheader, sizeof(frheader), err, err_info)) {
2168 ws_debug("not enough bytes for flexrayheader header in file");
2169 return false;
2171 fix_endianness_blf_flexraymessage(&frheader);
2173 payload_length = frheader.length;
2174 payload_length_valid = payload_length;
2176 if ((frheader.length & 0x01) == 0x01) {
2177 ws_debug("reading odd length in FlexRay!?");
2180 if (payload_length_valid > object_length - (data_start - block_start) - sizeof(frheader)) {
2181 ws_debug("shortening FlexRay payload because buffer is too short!");
2182 payload_length_valid = (uint8_t)(object_length - (data_start - block_start) - sizeof(frheader));
2185 if (frheader.channel != 0 && frheader.channel != 1) {
2186 ws_debug("FlexRay supports only two channels.");
2189 /* Measurement Header */
2190 if (frheader.channel == 0) {
2191 tmpbuf[0] = BLF_FLEXRAYDATA_FRAME;
2192 } else {
2193 tmpbuf[0] = BLF_FLEXRAYDATA_FRAME | BLF_FLEXRAYDATA_CHANNEL_B;
2196 /* Error Flags */
2197 tmpbuf[1] = 0;
2199 /* Frame Header */
2200 tmpbuf[2] = ((0x0700 & frheader.frameId) >> 8);
2201 if ((frheader.frameState & BLF_FLEXRAYMESSAGE_STATE_PPI) == BLF_FLEXRAYMESSAGE_STATE_PPI) {
2202 tmpbuf[2] |= BLF_DLT_FLEXRAY_PPI;
2205 if ((frheader.frameState & BLF_FLEXRAYMESSAGE_STATE_SFI) == BLF_FLEXRAYMESSAGE_STATE_SFI) {
2206 tmpbuf[2] |= BLF_DLT_FLEXRAY_SFI;
2209 if ((frheader.frameState & BLF_FLEXRAYMESSAGE_STATE_NFI) != BLF_FLEXRAYMESSAGE_STATE_NFI) {
2210 /* NFI needs to be inversed !? */
2211 tmpbuf[2] |= BLF_DLT_FLEXRAY_NFI;
2214 if ((frheader.frameState & BLF_FLEXRAYMESSAGE_STATE_STFI) == BLF_FLEXRAYMESSAGE_STATE_STFI) {
2215 tmpbuf[2] |= BLF_DLT_FLEXRAY_STFI;
2218 tmpbuf[3] = 0x00ff & frheader.frameId;
2219 tmpbuf[4] = (0xfe & frheader.length) | ((frheader.headerCrc & 0x0400) >> 10);
2220 tmpbuf[5] = (0x03fc & frheader.headerCrc) >> 2;
2221 tmpbuf[6] = ((0x0003 & frheader.headerCrc) << 6) | (0x3f & frheader.cycle);
2223 ws_buffer_assure_space(params->buf, sizeof(tmpbuf) + payload_length_valid);
2224 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2225 caplen = sizeof(tmpbuf) + payload_length_valid;
2226 len = sizeof(tmpbuf) + payload_length;
2228 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)) {
2229 ws_debug("copying flexray payload failed");
2230 return false;
2232 params->buf->first_free += payload_length_valid;
2234 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_FLEXRAY, frheader.channel, UINT16_MAX, caplen, len);
2235 blf_add_direction_option(params, frheader.dir);
2237 return true;
2240 static bool
2241 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) {
2242 blf_flexrayrcvmessage_t frheader;
2244 uint16_t payload_length;
2245 uint16_t payload_length_valid;
2246 uint8_t tmpbuf[7];
2247 int frheadersize = sizeof(frheader);
2248 unsigned caplen, len;
2250 if (ext) {
2251 frheadersize += 40;
2254 if ((int64_t)object_length < (data_start - block_start) + frheadersize) {
2255 *err = WTAP_ERR_BAD_FILE;
2256 *err_info = ws_strdup_printf("blf: %s: not enough bytes for flexrayheader in object",
2257 ext ? "FLEXRAY_RCVMESSAGE_EX" : "FLEXRAY_RCVMESSAGE");
2258 ws_debug("not enough bytes for flexrayheader in object");
2259 return false;
2262 if (!blf_read_bytes(params, data_start, &frheader, sizeof(frheader), err, err_info)) {
2263 ws_debug("not enough bytes for flexrayheader header in file");
2264 return false;
2266 fix_endianness_blf_flexrayrcvmessage(&frheader);
2268 if (!ext) {
2269 frheader.dir &= 0xff;
2270 frheader.cycle &= 0xff;
2273 payload_length = frheader.payloadLength;
2274 payload_length_valid = frheader.payloadLengthValid;
2276 if ((frheader.payloadLength & 0x01) == 0x01) {
2277 ws_debug("reading odd length in FlexRay!?");
2280 if (payload_length_valid > object_length - (data_start - block_start) - frheadersize) {
2281 ws_debug("shortening FlexRay payload because buffer is too short!");
2282 payload_length_valid = (uint8_t)(object_length - (data_start - block_start) - frheadersize);
2285 /* Measurement Header */
2286 /* TODO: It seems that this format support both channels at the same time!? */
2287 if (frheader.channelMask == BLF_FLEXRAYRCVMSG_CHANNELMASK_A) {
2288 tmpbuf[0] = BLF_FLEXRAYDATA_FRAME;
2289 } else {
2290 tmpbuf[0] = BLF_FLEXRAYDATA_FRAME | BLF_FLEXRAYDATA_CHANNEL_B;
2293 /* Error Flags */
2294 tmpbuf[1] = 0;
2296 /* Frame Header */
2297 tmpbuf[2] = ((0x0700 & frheader.frameId) >> 8);
2298 if ((frheader.frameFlags & BLF_FLEXRAYRCVMSG_FRAME_FLAG_PAYLOAD_PREAM) == BLF_FLEXRAYRCVMSG_FRAME_FLAG_PAYLOAD_PREAM) {
2299 tmpbuf[2] |= BLF_DLT_FLEXRAY_PPI;
2302 if ((frheader.frameFlags & BLF_FLEXRAYRCVMSG_FRAME_FLAG_SYNC) == BLF_FLEXRAYRCVMSG_FRAME_FLAG_SYNC) {
2303 tmpbuf[2] |= BLF_DLT_FLEXRAY_SFI;
2306 if ((frheader.frameFlags & BLF_FLEXRAYRCVMSG_FRAME_FLAG_NULL_FRAME) != BLF_FLEXRAYRCVMSG_FRAME_FLAG_NULL_FRAME) {
2307 /* NFI needs to be inversed !? */
2308 tmpbuf[2] |= BLF_DLT_FLEXRAY_NFI;
2311 if ((frheader.frameFlags & BLF_FLEXRAYRCVMSG_FRAME_FLAG_STARTUP) == BLF_FLEXRAYRCVMSG_FRAME_FLAG_STARTUP) {
2312 tmpbuf[2] |= BLF_DLT_FLEXRAY_STFI;
2315 tmpbuf[3] = 0x00ff & frheader.frameId;
2316 tmpbuf[4] = (0xfe & frheader.payloadLength) | ((frheader.headerCrc1 & 0x0400) >> 10);
2317 tmpbuf[5] = (0x03fc & frheader.headerCrc1) >> 2;
2318 tmpbuf[6] = ((0x0003 & frheader.headerCrc1) << 6) | (0x3f & frheader.cycle);
2320 ws_buffer_assure_space(params->buf, sizeof(tmpbuf) + payload_length_valid);
2321 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2322 caplen = sizeof(tmpbuf) + payload_length_valid;
2323 len = sizeof(tmpbuf) + payload_length;
2325 if (payload_length_valid > 0 && !blf_read_bytes(params, data_start + frheadersize, ws_buffer_end_ptr(params->buf), payload_length_valid, err, err_info)) {
2326 ws_debug("copying flexray payload failed");
2327 return false;
2329 params->buf->first_free += payload_length_valid;
2331 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_FLEXRAY, frheader.channelMask, UINT16_MAX, caplen, len);
2332 blf_add_direction_option(params, frheader.dir);
2334 return true;
2337 static bool
2338 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) {
2339 blf_linmessage_t linmessage;
2341 uint8_t payload_length;
2342 unsigned len;
2344 if (object_length < (data_start - block_start) + (int)sizeof(linmessage)) {
2345 *err = WTAP_ERR_BAD_FILE;
2346 *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");
2347 ws_debug("not enough bytes for %s in object", crc_error ? "lincrcerror" : "linmessage");
2348 return false;
2351 if (!blf_read_bytes(params, data_start, &linmessage, sizeof(linmessage), err, err_info)) {
2352 ws_debug("not enough bytes for %s in file", crc_error ? "lincrcerror" : "linmessage");
2353 return false;
2355 fix_endianness_blf_linmessage(&linmessage);
2357 linmessage.dlc &= 0x0f;
2358 linmessage.id &= 0x3f;
2360 payload_length = MIN(linmessage.dlc, 8);
2362 uint8_t tmpbuf[8];
2363 tmpbuf[0] = 1; /* message format rev = 1 */
2364 tmpbuf[1] = 0; /* reserved */
2365 tmpbuf[2] = 0; /* reserved */
2366 tmpbuf[3] = 0; /* reserved */
2367 tmpbuf[4] = linmessage.dlc << 4; /* dlc (4bit) | type (2bit) | checksum type (2bit) */
2368 tmpbuf[5] = linmessage.id; /* parity (2bit) | id (6bit) */
2369 tmpbuf[6] = (uint8_t)(linmessage.crc & 0xff); /* checksum */
2370 tmpbuf[7] = 0; /* errors */
2372 if (crc_error) {
2373 tmpbuf[7] |= 0x08;
2376 ws_buffer_assure_space(params->buf, sizeof(tmpbuf) + payload_length);
2377 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2378 ws_buffer_append(params->buf, linmessage.data, payload_length);
2379 len = sizeof(tmpbuf) + payload_length;
2381 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_LIN, linmessage.channel, UINT16_MAX, len, len);
2382 blf_add_direction_option(params, linmessage.dir);
2384 return true;
2387 static bool
2388 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) {
2389 blf_linrcverror_t linmessage;
2391 if (object_length < (data_start - block_start) + (int)sizeof(linmessage)) {
2392 *err = WTAP_ERR_BAD_FILE;
2393 *err_info = ws_strdup("blf: LIN_RCV_ERROR: not enough bytes for linrcverror in object");
2394 ws_debug("not enough bytes for linrcverror in object");
2395 return false;
2398 if (!blf_read_bytes(params, data_start, &linmessage, sizeof(linmessage), err, err_info)) {
2399 ws_debug("not enough bytes for linrcverror in file");
2400 return false;
2402 linmessage.channel = GUINT16_FROM_LE(linmessage.channel);
2404 linmessage.dlc &= 0x0f;
2405 linmessage.id &= 0x3f;
2407 uint8_t tmpbuf[8];
2408 tmpbuf[0] = 1; /* message format rev = 1 */
2409 tmpbuf[1] = 0; /* reserved */
2410 tmpbuf[2] = 0; /* reserved */
2411 tmpbuf[3] = 0; /* reserved */
2412 tmpbuf[4] = linmessage.dlc << 4; /* dlc (4bit) | type (2bit) | checksum type (2bit) */
2413 tmpbuf[5] = linmessage.id; /* parity (2bit) | id (6bit) */
2414 tmpbuf[6] = 0; /* checksum */
2415 /* XXX - This object can represent many different error types.
2416 * For now we always treat it as framing error,
2417 * but in the future we should expand it. */
2418 tmpbuf[7] = 0x02; /* errors */
2420 ws_buffer_assure_space(params->buf, sizeof(tmpbuf));
2421 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2423 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_LIN, linmessage.channel, UINT16_MAX, sizeof(tmpbuf), sizeof(tmpbuf));
2425 return true;
2428 static bool
2429 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) {
2430 blf_linsenderror_t linmessage;
2432 if (object_length < (data_start - block_start) + (int)sizeof(linmessage)) {
2433 *err = WTAP_ERR_BAD_FILE;
2434 *err_info = ws_strdup("blf: LIN_SND_ERROR: not enough bytes for linsenderror in object");
2435 ws_debug("not enough bytes for linsenderror in object");
2436 return false;
2439 if (!blf_read_bytes(params, data_start, &linmessage, sizeof(linmessage), err, err_info)) {
2440 ws_debug("not enough bytes for linsenderror in file");
2441 return false;
2443 linmessage.channel = GUINT16_FROM_LE(linmessage.channel);
2445 linmessage.dlc &= 0x0f;
2446 linmessage.id &= 0x3f;
2448 uint8_t tmpbuf[8];
2449 tmpbuf[0] = 1; /* message format rev = 1 */
2450 tmpbuf[1] = 0; /* reserved */
2451 tmpbuf[2] = 0; /* reserved */
2452 tmpbuf[3] = 0; /* reserved */
2453 tmpbuf[4] = linmessage.dlc << 4; /* dlc (4bit) | type (2bit) | checksum type (2bit) */
2454 tmpbuf[5] = linmessage.id; /* parity (2bit) | id (6bit) */
2455 tmpbuf[6] = 0; /* checksum */
2456 tmpbuf[7] = 0x01; /* errors */
2458 ws_buffer_assure_space(params->buf, sizeof(tmpbuf));
2459 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2461 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_LIN, linmessage.channel, UINT16_MAX, sizeof(tmpbuf), sizeof(tmpbuf));
2463 return true;
2466 static bool
2467 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) {
2468 blf_linwakeupevent_t linevent;
2470 if (object_length < (data_start - block_start) + (int)sizeof(linevent)) {
2471 *err = WTAP_ERR_BAD_FILE;
2472 *err_info = ws_strdup("blf: LIN_WAKEUP: not enough bytes for linwakeup in object");
2473 ws_debug("not enough bytes for linwakeup in object");
2474 return false;
2477 if (!blf_read_bytes(params, data_start, &linevent, sizeof(linevent), err, err_info)) {
2478 ws_debug("not enough bytes for linwakeup in file");
2479 return false;
2481 linevent.channel = GUINT16_FROM_LE(linevent.channel);
2483 uint8_t tmpbuf[12]; /* LIN events have a fixed length of 12 bytes */
2484 tmpbuf[0] = 1; /* message format rev = 1 */
2485 tmpbuf[1] = 0; /* reserved */
2486 tmpbuf[2] = 0; /* reserved */
2487 tmpbuf[3] = 0; /* reserved */
2488 tmpbuf[4] = 3 << 2; /* dlc (4bit) | type (2bit) | checksum type (2bit) */
2489 tmpbuf[5] = 0; /* parity (2bit) | id (6bit) */
2490 tmpbuf[6] = 0; /* checksum */
2491 tmpbuf[7] = 0; /* errors */
2493 /* Wake-up event */
2494 tmpbuf[8] = 0xB0;
2495 tmpbuf[9] = 0xB0;
2496 tmpbuf[10] = 0x00;
2497 tmpbuf[11] = 0x04;
2499 ws_buffer_assure_space(params->buf, sizeof(tmpbuf));
2500 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2502 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_LIN, linevent.channel, UINT16_MAX, sizeof(tmpbuf), sizeof(tmpbuf));
2504 return true;
2507 static bool
2508 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) {
2509 blf_linmessage2_t linmessage;
2511 uint8_t payload_length;
2512 unsigned len;
2514 if (object_length < (data_start - block_start) + (int)sizeof(linmessage)) {
2515 *err = WTAP_ERR_BAD_FILE;
2516 *err_info = ws_strdup("blf: LIN_MESSAGE2: not enough bytes for linmessage2 in object");
2517 ws_debug("not enough bytes for linmessage2 in object");
2518 return false;
2521 if (!blf_read_bytes(params, data_start, &linmessage, sizeof(linmessage), err, err_info)) {
2522 ws_debug("not enough bytes for linmessage2 in file");
2523 return false;
2525 fix_endianness_blf_linmessage2(&linmessage);
2527 linmessage.linDataByteTimestampEvent.linMessageDescriptor.dlc &= 0x0f;
2528 linmessage.linDataByteTimestampEvent.linMessageDescriptor.id &= 0x3f;
2530 payload_length = MIN(linmessage.linDataByteTimestampEvent.linMessageDescriptor.dlc, 8);
2532 uint8_t tmpbuf[8];
2533 tmpbuf[0] = 1; /* message format rev = 1 */
2534 tmpbuf[1] = 0; /* reserved */
2535 tmpbuf[2] = 0; /* reserved */
2536 tmpbuf[3] = 0; /* reserved */
2537 tmpbuf[4] = linmessage.linDataByteTimestampEvent.linMessageDescriptor.dlc << 4; /* dlc (4bit) | type (2bit) | checksum type (2bit) */
2538 if (object_version >= 1) { /* The 'checksumModel' field is valid only if objectVersion >= 1 */
2539 switch (linmessage.linDataByteTimestampEvent.linMessageDescriptor.checksumModel) {
2540 case 0:
2541 tmpbuf[4] |= 1; /* Classic */
2542 break;
2543 case 1:
2544 tmpbuf[4] |= 2; /* Enhanced */
2545 break;
2546 default:
2547 break;
2550 tmpbuf[5] = linmessage.linDataByteTimestampEvent.linMessageDescriptor.id; /* parity (2bit) | id (6bit) */
2551 tmpbuf[6] = (uint8_t)(linmessage.crc & 0xff); /* checksum */
2552 tmpbuf[7] = 0; /* errors */
2554 ws_buffer_assure_space(params->buf, sizeof(tmpbuf) + payload_length);
2555 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2556 ws_buffer_append(params->buf, linmessage.data, payload_length);
2557 len = sizeof(tmpbuf) + payload_length;
2559 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_LIN, linmessage.linDataByteTimestampEvent.linMessageDescriptor.linSynchFieldEvent.linBusEvent.channel, UINT16_MAX, len, len);
2560 blf_add_direction_option(params, linmessage.dir);
2562 return true;
2565 static bool
2566 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) {
2567 blf_lincrcerror2_t linmessage;
2569 uint8_t payload_length;
2570 unsigned len;
2572 if (object_length < (data_start - block_start) + (int)sizeof(linmessage)) {
2573 *err = WTAP_ERR_BAD_FILE;
2574 *err_info = ws_strdup("blf: LIN_CRC_ERROR2: not enough bytes for lincrcerror2 in object");
2575 ws_debug("not enough bytes for lincrcerror2 in object");
2576 return false;
2579 if (!blf_read_bytes(params, data_start, &linmessage, sizeof(linmessage), err, err_info)) {
2580 ws_debug("not enough bytes for lincrcerror2 in file");
2581 return false;
2583 fix_endianness_blf_lincrcerror2(&linmessage);
2585 linmessage.linDataByteTimestampEvent.linMessageDescriptor.dlc &= 0x0f;
2586 linmessage.linDataByteTimestampEvent.linMessageDescriptor.id &= 0x3f;
2588 payload_length = MIN(linmessage.linDataByteTimestampEvent.linMessageDescriptor.dlc, 8);
2590 uint8_t tmpbuf[8];
2591 tmpbuf[0] = 1; /* message format rev = 1 */
2592 tmpbuf[1] = 0; /* reserved */
2593 tmpbuf[2] = 0; /* reserved */
2594 tmpbuf[3] = 0; /* reserved */
2595 tmpbuf[4] = linmessage.linDataByteTimestampEvent.linMessageDescriptor.dlc << 4; /* dlc (4bit) | type (2bit) | checksum type (2bit) */
2596 if (object_version >= 1) { /* The 'checksumModel' field is valid only if objectVersion >= 1 */
2597 switch (linmessage.linDataByteTimestampEvent.linMessageDescriptor.checksumModel) {
2598 case 0:
2599 tmpbuf[4] |= 1; /* Classic */
2600 break;
2601 case 1:
2602 tmpbuf[4] |= 2; /* Enhanced */
2603 break;
2604 default:
2605 break;
2608 tmpbuf[5] = linmessage.linDataByteTimestampEvent.linMessageDescriptor.id; /* parity (2bit) | id (6bit) */
2609 tmpbuf[6] = (uint8_t)(linmessage.crc & 0xff); /* checksum */
2610 tmpbuf[7] = 0x08; /* errors */
2612 ws_buffer_assure_space(params->buf, sizeof(tmpbuf) + payload_length);
2613 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2614 ws_buffer_append(params->buf, linmessage.data, payload_length);
2615 len = sizeof(tmpbuf) + payload_length;
2617 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_LIN, linmessage.linDataByteTimestampEvent.linMessageDescriptor.linSynchFieldEvent.linBusEvent.channel, UINT16_MAX, len, len);
2618 blf_add_direction_option(params, linmessage.dir);
2620 return true;
2623 static bool
2624 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) {
2625 blf_linrcverror2_t linmessage;
2627 uint8_t payload_length;
2628 unsigned len;
2630 if (object_length < (data_start - block_start) + (int)sizeof(linmessage)) {
2631 *err = WTAP_ERR_BAD_FILE;
2632 *err_info = ws_strdup("blf: LIN_RCV_ERROR2: not enough bytes for linrcverror2 in object");
2633 ws_debug("not enough bytes for linrcverror2 in object");
2634 return false;
2637 if (!blf_read_bytes(params, data_start, &linmessage, sizeof(linmessage), err, err_info)) {
2638 ws_debug("not enough bytes for linrcverror2 in file");
2639 return false;
2641 fix_endianness_blf_linrcverror2(&linmessage);
2643 linmessage.linDataByteTimestampEvent.linMessageDescriptor.dlc &= 0x0f;
2644 linmessage.linDataByteTimestampEvent.linMessageDescriptor.id &= 0x3f;
2646 if (linmessage.hasDataBytes) {
2647 payload_length = MIN(linmessage.linDataByteTimestampEvent.linMessageDescriptor.dlc, 8);
2649 else {
2650 payload_length = 0;
2653 uint8_t tmpbuf[8];
2654 tmpbuf[0] = 1; /* message format rev = 1 */
2655 tmpbuf[1] = 0; /* reserved */
2656 tmpbuf[2] = 0; /* reserved */
2657 tmpbuf[3] = 0; /* reserved */
2658 tmpbuf[4] = linmessage.linDataByteTimestampEvent.linMessageDescriptor.dlc << 4; /* dlc (4bit) | type (2bit) | checksum type (2bit) */
2659 if (object_version >= 1) { /* The 'checksumModel' field is valid only if objectVersion >= 1 */
2660 switch (linmessage.linDataByteTimestampEvent.linMessageDescriptor.checksumModel) {
2661 case 0:
2662 tmpbuf[4] |= 1; /* Classic */
2663 break;
2664 case 1:
2665 tmpbuf[4] |= 2; /* Enhanced */
2666 break;
2667 default:
2668 break;
2671 tmpbuf[5] = linmessage.linDataByteTimestampEvent.linMessageDescriptor.id; /* parity (2bit) | id (6bit) */
2672 tmpbuf[6] = 0; /* checksum */
2673 /* XXX - This object can represent many different error types.
2674 * For now we always treat it as framing error,
2675 * but in the future we should expand it. */
2676 tmpbuf[7] = 0x02; /* errors */
2678 ws_buffer_assure_space(params->buf, sizeof(tmpbuf) + payload_length);
2679 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2680 if (payload_length > 0) {
2681 ws_buffer_append(params->buf, linmessage.data, payload_length);
2683 len = sizeof(tmpbuf) + payload_length;
2685 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_LIN, linmessage.linDataByteTimestampEvent.linMessageDescriptor.linSynchFieldEvent.linBusEvent.channel, UINT16_MAX, len, len);
2687 return true;
2690 static bool
2691 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) {
2692 blf_linsenderror2_t linmessage;
2694 if (object_length < (data_start - block_start) + (int)sizeof(linmessage)) {
2695 *err = WTAP_ERR_BAD_FILE;
2696 *err_info = ws_strdup("blf: LIN_SND_ERROR2: not enough bytes for linsenderror2 in object");
2697 ws_debug("not enough bytes for linsenderror2 in object");
2698 return false;
2701 if (!blf_read_bytes(params, data_start, &linmessage, sizeof(linmessage), err, err_info)) {
2702 ws_debug("not enough bytes for linsenderror2 in file");
2703 return false;
2705 fix_endianness_blf_linsenderror2(&linmessage);
2707 linmessage.linMessageDescriptor.dlc &= 0x0f;
2708 linmessage.linMessageDescriptor.id &= 0x3f;
2710 uint8_t tmpbuf[8];
2711 tmpbuf[0] = 1; /* message format rev = 1 */
2712 tmpbuf[1] = 0; /* reserved */
2713 tmpbuf[2] = 0; /* reserved */
2714 tmpbuf[3] = 0; /* reserved */
2715 tmpbuf[4] = linmessage.linMessageDescriptor.dlc << 4; /* dlc (4bit) | type (2bit) | checksum type (2bit) */
2716 if (object_version >= 1) { /* The 'checksumModel' field is valid only if objectVersion >= 1 */
2717 switch (linmessage.linMessageDescriptor.checksumModel) {
2718 case 0:
2719 tmpbuf[4] |= 1; /* Classic */
2720 break;
2721 case 1:
2722 tmpbuf[4] |= 2; /* Enhanced */
2723 break;
2724 default:
2725 break;
2728 tmpbuf[5] = linmessage.linMessageDescriptor.id; /* parity (2bit) | id (6bit) */
2729 tmpbuf[6] = 0; /* checksum */
2730 tmpbuf[7] = 0x01; /* errors */
2732 ws_buffer_assure_space(params->buf, sizeof(tmpbuf));
2733 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2735 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_LIN, linmessage.linMessageDescriptor.linSynchFieldEvent.linBusEvent.channel, UINT16_MAX, sizeof(tmpbuf), sizeof(tmpbuf));
2737 return true;
2740 static bool
2741 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) {
2742 blf_linwakeupevent2_t linevent;
2744 if (object_length < (data_start - block_start) + (int)sizeof(linevent)) {
2745 *err = WTAP_ERR_BAD_FILE;
2746 *err_info = ws_strdup("blf: LIN_WAKEUP2: not enough bytes for linwakeup2 in object");
2747 ws_debug("not enough bytes for linwakeup2 in object");
2748 return false;
2751 if (!blf_read_bytes(params, data_start, &linevent, sizeof(linevent), err, err_info)) {
2752 ws_debug("not enough bytes for linwakeup2 in file");
2753 return false;
2755 fix_endianness_blf_linwakeupevent2(&linevent);
2757 uint8_t tmpbuf[12]; /* LIN events have a fixed length of 12 bytes */
2758 tmpbuf[0] = 1; /* message format rev = 1 */
2759 tmpbuf[1] = 0; /* reserved */
2760 tmpbuf[2] = 0; /* reserved */
2761 tmpbuf[3] = 0; /* reserved */
2762 tmpbuf[4] = 3 << 2; /* dlc (4bit) | type (2bit) | checksum type (2bit) */
2763 tmpbuf[5] = 0; /* parity (2bit) | id (6bit) */
2764 tmpbuf[6] = 0; /* checksum */
2765 tmpbuf[7] = 0; /* errors */
2767 /* Wake-up event */
2768 tmpbuf[8] = 0xB0;
2769 tmpbuf[9] = 0xB0;
2770 tmpbuf[10] = 0x00;
2771 tmpbuf[11] = 0x04;
2773 ws_buffer_assure_space(params->buf, sizeof(tmpbuf));
2774 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2776 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_LIN, linevent.linBusEvent.channel, UINT16_MAX, sizeof(tmpbuf), sizeof(tmpbuf));
2778 return true;
2781 static bool
2782 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) {
2783 blf_linsleepmodeevent_t linevent;
2785 if (object_length < (data_start - block_start) + (int)sizeof(linevent)) {
2786 *err = WTAP_ERR_BAD_FILE;
2787 *err_info = ws_strdup("blf: LIN_SLEEP: not enough bytes for linsleep in object");
2788 ws_debug("not enough bytes for linsleep in object");
2789 return false;
2792 if (!blf_read_bytes(params, data_start, &linevent, sizeof(linevent), err, err_info)) {
2793 ws_debug("not enough bytes for linsleep in file");
2794 return false;
2796 linevent.channel = GUINT16_FROM_LE(linevent.channel);
2798 uint8_t tmpbuf[12]; /* LIN events have a fixed length of 12 bytes */
2799 tmpbuf[0] = 1; /* message format rev = 1 */
2800 tmpbuf[1] = 0; /* reserved */
2801 tmpbuf[2] = 0; /* reserved */
2802 tmpbuf[3] = 0; /* reserved */
2803 tmpbuf[4] = 3 << 2; /* dlc (4bit) | type (2bit) | checksum type (2bit) */
2804 tmpbuf[5] = 0; /* parity (2bit) | id (6bit) */
2805 tmpbuf[6] = 0; /* checksum */
2806 tmpbuf[7] = 0; /* errors */
2808 switch (linevent.reason) {
2809 case BLF_LIN_SLEEP_REASON_GO_TO_SLEEP_FRAME:
2810 /* Go-to-Sleep event by Go-to-Sleep frame */
2811 tmpbuf[8] = 0xB0;
2812 tmpbuf[9] = 0xB0;
2813 tmpbuf[10] = 0x00;
2814 tmpbuf[11] = 0x01;
2815 break;
2816 case BLF_LIN_SLEEP_REASON_BUS_IDLE_TIMEOUT:
2817 case BLF_LIN_SLEEP_REASON_SILENT_SLEEPMODE_CMD:
2818 /* Go-to-Sleep event by Inactivity for more than 4s */
2819 tmpbuf[8] = 0xB0;
2820 tmpbuf[9] = 0xB0;
2821 tmpbuf[10] = 0x00;
2822 tmpbuf[11] = 0x02;
2823 break;
2824 case BLF_LIN_WU_REASON_EXTERNAL_WAKEUP_SIG:
2825 case BLF_LIN_WU_REASON_INTERNAL_WAKEUP_SIG:
2826 case BLF_LIN_WU_REASON_BUS_TRAFFIC: /* There's no "wake-up by bus traffic" event in the LIN packet. */
2827 /* Wake-up event by Wake-up signal */
2828 tmpbuf[8] = 0xB0;
2829 tmpbuf[9] = 0xB0;
2830 tmpbuf[10] = 0x00;
2831 tmpbuf[11] = 0x04;
2832 break;
2833 case BLF_LIN_WU_SLEEP_REASON_START_STATE:
2834 case BLF_LIN_NO_SLEEP_REASON_BUS_TRAFFIC:
2835 /* If we're just reporting on the initial state,
2836 * or the interface doesn't want to go to sleep,
2837 * report the current state as "event". */
2838 if (linevent.flags & 0x2) {
2839 /* Wake-up event by Wake-up signal */
2840 tmpbuf[8] = 0xB0;
2841 tmpbuf[9] = 0xB0;
2842 tmpbuf[10] = 0x00;
2843 tmpbuf[11] = 0x04;
2845 else {
2846 /* Go-to-Sleep event by Inactivity for more than 4s */
2847 tmpbuf[8] = 0xB0;
2848 tmpbuf[9] = 0xB0;
2849 tmpbuf[10] = 0x00;
2850 tmpbuf[11] = 0x02;
2852 break;
2853 default:
2854 tmpbuf[8] = 0x00;
2855 tmpbuf[9] = 0x00;
2856 tmpbuf[10] = 0x00;
2857 tmpbuf[11] = 0x00;
2858 break;
2861 ws_buffer_assure_space(params->buf, sizeof(tmpbuf));
2862 ws_buffer_append(params->buf, tmpbuf, sizeof(tmpbuf));
2864 blf_init_rec(params, flags, object_timestamp, WTAP_ENCAP_LIN, linevent.channel, UINT16_MAX, sizeof(tmpbuf), sizeof(tmpbuf));
2866 return true;
2869 uint16_t blf_get_xml_channel_number(const char* start, const char* end) {
2870 char* text;
2871 size_t len;
2872 uint16_t res;
2874 if (start == NULL || end == NULL || end <= start) {
2875 return UINT16_MAX;
2878 len = (size_t)(end - start);
2879 text = g_try_malloc(len + 1); /* Accommodate '\0' */
2880 if (text == NULL) {
2881 ws_debug("cannot allocate memory");
2882 return UINT16_MAX;
2884 memcpy(text, start, len);
2885 text[len] = '\0';
2887 if (!ws_strtou16(text, NULL, &res)) {
2888 res = UINT16_MAX;
2891 g_free(text);
2892 return res;
2895 char* blf_get_xml_channel_name(const char* start, const char* end) {
2896 char* text;
2897 size_t len;
2899 if (start == NULL || end == NULL || end <= start) {
2900 return NULL;
2903 len = (size_t)(end - start);
2904 text = g_try_malloc(len + 1); /* Accommodate '\0' */
2905 if (text == NULL) {
2906 ws_debug("cannot allocate memory");
2907 return NULL;
2909 memcpy(text, start, len);
2910 text[len] = '\0';
2912 return text;
2915 bool blf_parse_xml_port(const char* start, const char* end, char** name, uint16_t* hwchannel, bool* simulated) {
2916 static const char name_magic[] = "name=";
2917 static const char hwchannel_magic[] = "hwchannel=";
2918 static const char simulated_magic[] = "simulated=";
2920 char* text;
2921 size_t len;
2922 char** tokens;
2923 const char* token;
2925 if (start == NULL || end == NULL || name == NULL || end <= start) {
2926 return false;
2929 len = (size_t)(end - start);
2930 text = g_try_malloc(len + 1); /* Accommodate '\0' */
2931 if (text == NULL) {
2932 ws_debug("cannot allocate memory");
2933 return false;
2935 memcpy(text, start, len);
2936 text[len] = '\0';
2938 tokens = g_strsplit_set(text, ";", -1);
2939 g_free(text);
2940 if (tokens == NULL) {
2941 ws_debug("cannot split XML port data");
2942 return false;
2945 *name = NULL;
2946 *hwchannel = UINT16_MAX;
2947 *simulated = false;
2949 for (int i = 0; tokens[i] != NULL; i++) {
2950 token = tokens[i];
2951 if (strncmp(token, name_magic, strlen(name_magic)) == 0) {
2952 if (*name == NULL) { /* Avoid memory leak in case of malformed string */
2953 *name = ws_strdup(token + strlen(name_magic));
2956 else if (strncmp(token, hwchannel_magic, strlen(hwchannel_magic)) == 0) {
2957 if (!ws_strtou16(token + strlen(hwchannel_magic), NULL, hwchannel)) {
2958 *hwchannel = UINT16_MAX;
2961 else if (strncmp(token, simulated_magic, strlen(simulated_magic)) == 0) {
2962 if (strlen(token) > strlen(simulated_magic) && token[strlen(simulated_magic)] != '0') {
2963 *simulated = true; /* TODO: Find a way to use this information */
2968 g_strfreev(tokens);
2970 return true;
2973 int blf_get_xml_pkt_encap(const char* start, const char* end) {
2974 size_t len;
2976 if (start == NULL || end == NULL || end <= start) {
2977 return 0;
2980 len = (size_t)(end - start);
2982 if (strncmp(start, "CAN", len) == 0) {
2983 return WTAP_ENCAP_SOCKETCAN;
2985 if (strncmp(start, "FlexRay", len) == 0) {
2986 return WTAP_ENCAP_FLEXRAY;
2988 if (strncmp(start, "LIN", len) == 0) {
2989 return WTAP_ENCAP_LIN;
2991 if (strncmp(start, "Ethernet", len) == 0) {
2992 return WTAP_ENCAP_ETHERNET;
2994 if (strncmp(start, "WLAN", len) == 0) { /* Not confirmed with a real capture */
2995 return WTAP_ENCAP_IEEE_802_11;
2998 return 0xffffffff;
3001 /** Finds a NULL-terminated string in a block of memory.
3003 * 'start' points to the first byte of the block of memory.
3004 * 'end' points to the first byte after the end of the block of memory,
3005 * so that the size of the block is end-start.
3006 * 'str' is a NULL-terminated string.
3008 const char* blf_strmem(const char* start, const char* end, const char* str) {
3009 if (start == NULL || end == NULL || str == NULL || end <= start) {
3010 return NULL;
3013 return ws_memmem(start, end - start, str, strlen(str));
3016 /** Extracts the channel and port names from a channels XML.
3018 * A sample channels XML looks like this:
3020 * <?xml version="1.0" encoding="UTF-8"?>
3021 * <channels version="1">
3022 * <channel number="1" type="CAN" network="CAN01">
3023 * <databases>
3024 * <database file="DB.arxml" path="C:\...\" cluster="CAN01" />
3025 * <database file="DB.dbc" path="C:\...\" cluster="General" />
3026 * </databases>
3027 * </channel>
3028 * <channel number="1" type="LIN" network="LIN01">
3029 * <databases>
3030 * <database file="DB.dbc" path="C:\...\" cluster="General" />
3031 * <database file="DB.ldf" path="C:\...\" cluster="LIN01" />
3032 * </databases>
3033 * </channel>
3034 * <channel number="1" type="Ethernet" network="ETH01">
3035 * <databases>
3036 * <database file="DB.dbc" path="C:\...\" cluster="General" />
3037 * </databases>
3038 * <channel_properties>
3039 * <elist name="ports">
3040 * <eli name="port">name=Port1;hwchannel=11;simulated=1</eli>
3041 * <eli name="port">name=Port2;hwchannel=12;simulated=0</eli>
3042 * </elist>
3043 * </channel_properties>
3044 * </channel>
3045 * </channels>
3047 static bool
3048 blf_set_xml_channels(blf_params_t* params, const char* text, size_t len) {
3049 static const char xml_magic[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
3050 static const char channels_start_magic[] = "<channels ";
3051 static const char channels_end_magic[] = "</channels>";
3052 static const char channel_start_magic[] = "<channel ";
3053 static const char channel_end_magic[] = "</channel>";
3054 static const char number_start_magic[] = "number=\"";
3055 static const char number_end_magic[] = "\"";
3056 static const char type_start_magic[] = "type=\"";
3057 static const char type_end_magic[] = "\"";
3058 static const char network_start_magic[] = "network=\"";
3059 static const char network_end_magic[] = "\"";
3060 static const char ports_start_magic[] = "<elist name=\"ports\">";
3061 static const char ports_end_magic[] = "</elist>";
3062 static const char port_start_magic[] = "<eli name=\"port\">";
3063 static const char port_end_magic[] = "</eli>";
3065 const char* xml_start;
3066 const char* channels_start;
3067 const char* channels_end;
3068 const char* channel_start;
3069 const char* channel_end;
3070 const char* number_start;
3071 const char* number_end;
3072 const char* type_start;
3073 const char* type_end;
3074 const char* network_start;
3075 const char* network_end;
3076 const char* ports_start;
3077 const char* ports_end;
3078 const char* port_start;
3079 const char* port_end;
3081 const char* search_start;
3082 bool res;
3084 int pkt_encap;
3085 uint16_t channel;
3086 uint16_t hwchannel = UINT16_MAX;
3087 char* channel_name = NULL;
3088 char* port_name = NULL;
3089 bool simulated = false;
3090 char* iface_name = NULL;
3092 if (text == NULL || len < strlen(xml_magic)) {
3093 return false;
3096 xml_start = blf_strmem(text, text + len, xml_magic);
3097 if (xml_start == NULL) {
3098 ws_debug("no valid xml magic found");
3099 return false;
3101 search_start = xml_start + strlen(xml_magic);
3103 channels_start = blf_strmem(search_start, text + len, channels_start_magic);
3104 channels_end = blf_strmem(search_start, text + len, channels_end_magic);
3105 if (channels_start == NULL || channels_end == NULL || channels_end <= channels_start + strlen(channels_start_magic)) {
3106 ws_debug("no channels tag found in xml");
3107 return false;
3109 search_start = channels_start + strlen(channels_start_magic);
3111 while (search_start < channels_end) {
3112 channel_start = blf_strmem(search_start, channels_end, channel_start_magic);
3113 search_start = search_start + strlen(channel_start_magic);
3114 channel_end = blf_strmem(search_start, channels_end, channel_end_magic);
3115 if (channel_start == NULL || channel_end == NULL || channel_end <= channel_start + strlen(channel_start_magic)) {
3116 ws_debug("found end of channel list");
3117 return true;
3120 number_start = blf_strmem(channel_start, channel_end, number_start_magic);
3121 if (number_start == NULL) {
3122 ws_debug("channel without number found in xml");
3123 search_start = channel_end + strlen(channel_end_magic);
3124 continue;
3127 number_end = blf_strmem(number_start + strlen(number_start_magic), channel_end, number_end_magic);
3128 if (number_end == NULL) {
3129 ws_debug("channel with malformed number attribute found in xml");
3130 search_start = channel_end + strlen(channel_end_magic);
3131 continue;
3134 channel = blf_get_xml_channel_number(number_start + strlen(number_start_magic), number_end);
3135 if (channel == UINT16_MAX) {
3136 ws_debug("invalid channel number found in xml");
3137 search_start = channel_end + strlen(channel_end_magic);
3138 continue;
3141 type_start = blf_strmem(channel_start, channel_end, type_start_magic);
3142 if (type_start == NULL) {
3143 ws_debug("channel without type found in xml");
3144 search_start = channel_end + strlen(channel_end_magic);
3145 continue;
3148 type_end = blf_strmem(type_start + strlen(type_start_magic), channel_end, type_end_magic);
3149 if (type_end == NULL) {
3150 ws_debug("channel with malformed type attribute found in xml");
3151 search_start = channel_end + strlen(channel_end_magic);
3152 continue;
3155 pkt_encap = blf_get_xml_pkt_encap(type_start + strlen(type_start_magic), type_end);
3157 network_start = blf_strmem(channel_start, channel_end, network_start_magic);
3158 if (network_start == NULL) {
3159 ws_debug("channel without name found in xml");
3160 search_start = channel_end + strlen(channel_end_magic);
3161 continue;
3164 network_end = blf_strmem(network_start + strlen(network_start_magic), channel_end, network_end_magic);
3165 if (network_end == NULL) {
3166 ws_debug("channel with malformed network attribute found in xml");
3167 search_start = channel_end + strlen(channel_end_magic);
3168 continue;
3171 channel_name = blf_get_xml_channel_name(network_start + strlen(network_start_magic), network_end);
3172 if (channel_name == NULL || strlen(channel_name) == 0) {
3173 ws_debug("channel with empty name found in xml");
3174 if (channel_name) {
3175 g_free(channel_name);
3176 channel_name = NULL;
3178 search_start = channel_end + strlen(channel_end_magic);
3179 continue;
3182 ws_debug("Found channel in XML: PKT_ENCAP: %d, ID: %u, name: %s", pkt_encap, channel, channel_name);
3183 blf_prepare_interface_name(params, pkt_encap, channel, UINT16_MAX, channel_name, true);
3185 search_start = MAX(MAX(number_end + strlen(number_end_magic), type_end + strlen(type_end_magic)), network_end + strlen(network_end_magic));
3187 ports_start = blf_strmem(search_start, channel_end, ports_start_magic);
3188 if (ports_start == NULL) {
3189 /* Not an error, channel has no ports */
3190 g_free(channel_name);
3191 channel_name = NULL;
3192 search_start = channel_end + strlen(channel_end_magic);
3193 continue;
3196 search_start = ports_start + strlen(ports_start_magic);
3198 ports_end = blf_strmem(search_start, channel_end, ports_end_magic);
3199 if (ports_end == NULL) {
3200 ws_debug("channel with malformed ports tag found in xml");
3201 g_free(channel_name);
3202 channel_name = NULL;
3203 search_start = channel_end + strlen(channel_end_magic);
3204 continue;
3207 while (search_start < ports_end) {
3208 port_start = blf_strmem(search_start, ports_end, port_start_magic);
3209 port_end = blf_strmem(search_start + strlen(port_start_magic), ports_end, port_end_magic);
3210 if (port_start == NULL || port_end == NULL || port_end <= port_start + strlen(port_start_magic)) {
3211 ws_debug("found end of ports list");
3212 search_start = ports_end + strlen(ports_end_magic);
3213 continue;
3216 res = blf_parse_xml_port(port_start + strlen(port_start_magic), port_end, &port_name, &hwchannel, &simulated);
3217 if (!res || port_name == NULL || hwchannel == UINT16_MAX) {
3218 if (port_name) {
3219 g_free(port_name);
3220 port_name = NULL;
3222 ws_debug("port with missing or malformed info found in xml");
3223 search_start = port_end + strlen(port_end_magic);
3224 continue;
3227 iface_name = ws_strdup_printf("%s::%s", channel_name, port_name);
3228 ws_debug("Found channel in XML: PKT_ENCAP: %d, ID: %u, HW ID: %u, name: %s", pkt_encap, channel, hwchannel, iface_name);
3229 blf_prepare_interface_name(params, pkt_encap, channel, hwchannel, iface_name, true);
3230 g_free(iface_name);
3232 if (port_name) {
3233 g_free(port_name);
3234 port_name = NULL;
3237 search_start = port_end + strlen(port_end_magic);
3240 g_free(channel_name);
3241 channel_name = NULL;
3243 search_start = channel_end + strlen(channel_end_magic);
3246 return true;
3249 static int
3250 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) {
3251 blf_apptext_t apptextheader;
3253 if (object_length < (data_start - block_start) + (int)sizeof(apptextheader)) {
3254 *err = WTAP_ERR_BAD_FILE;
3255 *err_info = ws_strdup("blf: APP_TEXT: not enough bytes for apptext header in object");
3256 ws_debug("not enough bytes for apptext header in object");
3257 return BLF_APPTEXT_FAILED;
3260 if (!blf_read_bytes(params, data_start, &apptextheader, sizeof(apptextheader), err, err_info)) {
3261 ws_debug("not enough bytes for apptext header in file");
3262 return BLF_APPTEXT_FAILED;
3264 fix_endianness_blf_apptext_header(&apptextheader);
3266 if (metadata_cont && apptextheader.source != BLF_APPTEXT_METADATA) {
3267 /* If we're in the middle of a sequence of metadata objects,
3268 * but we get an AppText object from another source,
3269 * skip the previously incomplete object and start fresh.
3271 metadata_cont = 0;
3274 /* Add an extra byte for a terminating '\0' */
3275 char* text = g_try_malloc((size_t)apptextheader.textLength + 1);
3276 if (text == NULL) {
3277 ws_debug("cannot allocate memory");
3278 return BLF_APPTEXT_FAILED;
3281 if (!blf_read_bytes(params, data_start + sizeof(apptextheader), text, apptextheader.textLength, err, err_info)) {
3282 ws_debug("not enough bytes for apptext text in file");
3283 g_free(text);
3284 return BLF_APPTEXT_FAILED;
3286 text[apptextheader.textLength] = '\0'; /* Here's the '\0' */
3288 switch (apptextheader.source) {
3289 case BLF_APPTEXT_CHANNEL:
3292 /* returns a NULL terminated array of NULL terminates strings */
3293 char** tokens = g_strsplit_set(text, ";", -1);
3295 if (tokens == NULL || tokens[0] == NULL || tokens[1] == NULL) {
3296 if (tokens != NULL) {
3297 g_strfreev(tokens);
3299 g_free(text);
3300 return BLF_APPTEXT_CHANNEL;
3303 uint16_t channel = (apptextheader.reservedAppText1 >> 8) & 0xff;
3304 int pkt_encap;
3306 switch ((apptextheader.reservedAppText1 >> 16) & 0xff) {
3307 case BLF_BUSTYPE_CAN:
3308 pkt_encap = WTAP_ENCAP_SOCKETCAN;
3309 break;
3311 case BLF_BUSTYPE_FLEXRAY:
3312 pkt_encap = WTAP_ENCAP_FLEXRAY;
3313 break;
3315 case BLF_BUSTYPE_LIN:
3316 pkt_encap = WTAP_ENCAP_LIN;
3317 break;
3319 case BLF_BUSTYPE_ETHERNET:
3320 pkt_encap = WTAP_ENCAP_ETHERNET;
3321 break;
3323 case BLF_BUSTYPE_WLAN:
3324 pkt_encap = WTAP_ENCAP_IEEE_802_11;
3325 break;
3327 default:
3328 pkt_encap = 0xffffffff;
3329 break;
3332 /* we use lookup to create interface, if not existing yet */
3333 blf_prepare_interface_name(params, pkt_encap, channel, UINT16_MAX, tokens[1], false);
3335 g_strfreev(tokens);
3336 g_free(text);
3337 return BLF_APPTEXT_CHANNEL;
3339 case BLF_APPTEXT_METADATA:
3340 if (metadata_cont) {
3341 /* Set the buffer pointer to the end of the previous object */
3342 params->buf->first_free = metadata_cont;
3344 else {
3345 /* First object of a sequence of one or more */
3346 wtap_buffer_append_epdu_string(params->buf, EXP_PDU_TAG_DISSECTOR_NAME, "data-text-lines");
3347 wtap_buffer_append_epdu_string(params->buf, EXP_PDU_TAG_COL_PROT_TEXT, "BLF App text");
3348 wtap_buffer_append_epdu_string(params->buf, EXP_PDU_TAG_COL_INFO_TEXT, "Metadata");
3349 wtap_buffer_append_epdu_end(params->buf);
3352 ws_buffer_assure_space(params->buf, apptextheader.textLength);
3353 ws_buffer_append(params->buf, text, apptextheader.textLength);
3354 g_free(text);
3356 if ((apptextheader.reservedAppText1 & 0x00ffffff) > apptextheader.textLength) {
3357 /* Continues in the next object */
3358 return BLF_APPTEXT_CONT;
3361 if (((apptextheader.reservedAppText1 >> 24) & 0xff) == BLF_APPTEXT_XML_CHANNELS) {
3362 blf_set_xml_channels(params, params->buf->data, ws_buffer_length(params->buf));
3365 /* 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. */
3366 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));
3367 return BLF_APPTEXT_METADATA;
3368 case BLF_APPTEXT_COMMENT:
3369 case BLF_APPTEXT_ATTACHMENT:
3370 case BLF_APPTEXT_TRACELINE:
3372 wtap_buffer_append_epdu_string(params->buf, EXP_PDU_TAG_DISSECTOR_NAME, "data-text-lines");
3373 wtap_buffer_append_epdu_string(params->buf, EXP_PDU_TAG_COL_PROT_TEXT, "BLF App text");
3375 char* info_line = NULL;
3376 switch (apptextheader.source) {
3377 case BLF_APPTEXT_COMMENT:
3378 info_line = ws_strdup_printf("Comment: %s", text);
3379 break;
3380 case BLF_APPTEXT_ATTACHMENT:
3381 info_line = ws_strdup_printf("Attachment: %s", text);
3382 break;
3383 case BLF_APPTEXT_TRACELINE:
3384 info_line = ws_strdup_printf("Trace line%s: %s", (apptextheader.reservedAppText1 & 0x00000010) ? "" : " (hidden)", text);
3385 break;
3386 default:
3387 break;
3390 wtap_buffer_append_epdu_string(params->buf, EXP_PDU_TAG_COL_INFO_TEXT, info_line);
3391 wtap_buffer_append_epdu_end(params->buf);
3393 size_t text_length = strlen(text); /* The string can contain '\0' before textLength bytes */
3394 ws_buffer_assure_space(params->buf, text_length); /* The dissector doesn't need NULL-terminated strings */
3395 ws_buffer_append(params->buf, text, text_length);
3397 /* We'll write this as a WS UPPER PDU packet with a text blob */
3398 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));
3399 g_free(text);
3400 if (info_line) {
3401 g_free(info_line);
3403 return apptextheader.source;
3405 default:
3406 g_free(text);
3407 return BLF_APPTEXT_CHANNEL; /* Cheat - no block to write */;
3409 return BLF_APPTEXT_CHANNEL; /* Cheat - no block to write */
3412 static bool
3413 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) {
3414 blf_ethernet_status_t ethernet_status_header;
3415 uint8_t tmpbuf[24];
3416 uint64_t linkUpDuration;
3418 if (object_length < (data_start - block_start) + (int)sizeof(ethernet_status_header) + (int)(object_version >= 1 ? 8 : 0)) {
3419 *err = WTAP_ERR_BAD_FILE;
3420 *err_info = ws_strdup("blf: ETHERNET_STATUS: not enough bytes for ethernet status header in object");
3421 ws_debug("not enough bytes for ethernet status header in object");
3422 return false;
3425 if (!blf_read_bytes(params, data_start, &ethernet_status_header, sizeof(ethernet_status_header), err, err_info)) {
3426 ws_debug("not enough bytes for ethernet_status_header header in file");
3427 return false;
3430 if (object_version >= 1) {
3431 if (!blf_read_bytes(params, data_start + sizeof(ethernet_status_header), &linkUpDuration, 8, err, err_info)) {
3432 ws_debug("not enough bytes for ethernet_status_header header in file");
3433 return false;
3435 linkUpDuration = GUINT64_FROM_LE(linkUpDuration);
3438 fix_endianness_blf_ethernet_status_header(&ethernet_status_header);
3440 tmpbuf[0] = (ethernet_status_header.channel & 0xff00) >> 8;
3441 tmpbuf[1] = (ethernet_status_header.channel & 0x00ff);
3442 tmpbuf[2] = (ethernet_status_header.flags & 0xff00) >> 8;
3443 tmpbuf[3] = (ethernet_status_header.flags & 0x00ff);
3444 tmpbuf[4] = (ethernet_status_header.linkStatus);
3445 tmpbuf[5] = (ethernet_status_header.ethernetPhy);
3446 tmpbuf[6] = (ethernet_status_header.duplex);
3447 tmpbuf[7] = (ethernet_status_header.mdi);
3448 tmpbuf[8] = (ethernet_status_header.connector);
3449 tmpbuf[9] = (ethernet_status_header.clockMode);
3450 tmpbuf[10] = (ethernet_status_header.pairs);
3451 tmpbuf[11] = (ethernet_status_header.hardwareChannel);
3452 tmpbuf[12] = (ethernet_status_header.bitrate & 0xff000000) >> 24;
3453 tmpbuf[13] = (ethernet_status_header.bitrate & 0x00ff0000) >> 16;
3454 tmpbuf[14] = (ethernet_status_header.bitrate & 0x0000ff00) >> 8;
3455 tmpbuf[15] = (ethernet_status_header.bitrate & 0x000000ff);
3457 if (object_version >= 1) {
3458 tmpbuf[16] = (uint8_t)((linkUpDuration & UINT64_C(0xff00000000000000)) >> 56);
3459 tmpbuf[17] = (uint8_t)((linkUpDuration & UINT64_C(0x00ff000000000000)) >> 48);
3460 tmpbuf[18] = (uint8_t)((linkUpDuration & UINT64_C(0x0000ff0000000000)) >> 40);
3461 tmpbuf[19] = (uint8_t)((linkUpDuration & UINT64_C(0x000000ff00000000)) >> 32);
3462 tmpbuf[20] = (uint8_t)((linkUpDuration & UINT64_C(0x00000000ff000000)) >> 24);
3463 tmpbuf[21] = (uint8_t)((linkUpDuration & UINT64_C(0x0000000000ff0000)) >> 16);
3464 tmpbuf[22] = (uint8_t)((linkUpDuration & UINT64_C(0x000000000000ff00)) >> 8);
3465 tmpbuf[23] = (uint8_t)((linkUpDuration & UINT64_C(0x00000000000000ff)));
3468 wtap_buffer_append_epdu_string(params->buf, EXP_PDU_TAG_DISSECTOR_NAME, "blf-ethernetstatus-obj");
3469 wtap_buffer_append_epdu_end(params->buf);
3471 ws_buffer_assure_space(params->buf, sizeof(ethernet_status_header));
3472 ws_buffer_append(params->buf, tmpbuf, (size_t)(object_version >= 1 ? 24 : 16));
3474 /* We'll write this as a WS UPPER PDU packet with a data blob */
3475 /* This will create an interface with the "name" of the matching
3476 * WTAP_ENCAP_ETHERNET interface with the same channel and hardware
3477 * channel prefixed with "STATUS" and with a different interface ID,
3478 * because IDBs in pcapng can only have one linktype.
3479 * The other option would be to write everything as UPPER_PDU, including
3480 * the Ethernet data (with one of the "eth_" dissectors.)
3482 char* iface_name = ws_strdup_printf("STATUS-ETH-%u-%u", ethernet_status_header.channel, ethernet_status_header.hardwareChannel);
3483 blf_lookup_interface(params, WTAP_ENCAP_WIRESHARK_UPPER_PDU, ethernet_status_header.channel, ethernet_status_header.hardwareChannel, iface_name);
3484 g_free(iface_name);
3485 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));
3487 if ((ethernet_status_header.flags & BLF_ETH_STATUS_HARDWARECHANNEL) == BLF_ETH_STATUS_HARDWARECHANNEL) {
3488 /* If HW channel valid */
3489 wtap_block_add_uint32_option(params->rec->block, OPT_PKT_QUEUE, ethernet_status_header.hardwareChannel);
3492 return true;
3495 static bool
3496 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) {
3497 blf_ethernet_phystate_t ethernet_phystate_header;
3498 uint8_t tmpbuf[8];
3500 if (object_length < (data_start - block_start) + (int)sizeof(ethernet_phystate_header)) {
3501 *err = WTAP_ERR_BAD_FILE;
3502 *err_info = ws_strdup("blf: ETHERNET_PHY_STATE: not enough bytes for ethernet phystate header in object");
3503 ws_debug("not enough bytes for ethernet phystate header in object");
3504 return false;
3507 if (!blf_read_bytes(params, data_start, &ethernet_phystate_header, sizeof(ethernet_phystate_header), err, err_info)) {
3508 ws_debug("not enough bytes for ethernet phystate header in file");
3509 return false;
3512 fix_endianness_blf_ethernet_phystate_header(&ethernet_phystate_header);
3514 tmpbuf[0] = (ethernet_phystate_header.channel & 0xff00) >> 8;
3515 tmpbuf[1] = (ethernet_phystate_header.channel & 0x00ff);
3516 tmpbuf[2] = (ethernet_phystate_header.flags & 0xff00) >> 8;
3517 tmpbuf[3] = (ethernet_phystate_header.flags & 0x00ff);
3518 tmpbuf[4] = (ethernet_phystate_header.phyState);
3519 tmpbuf[5] = (ethernet_phystate_header.phyEvent);
3520 tmpbuf[6] = (ethernet_phystate_header.hardwareChannel);
3521 tmpbuf[7] = (ethernet_phystate_header.res1);
3523 wtap_buffer_append_epdu_string(params->buf, EXP_PDU_TAG_DISSECTOR_NAME, "blf-ethernetphystate-obj");
3524 wtap_buffer_append_epdu_end(params->buf);
3526 ws_buffer_assure_space(params->buf, sizeof(ethernet_phystate_header));
3527 ws_buffer_append(params->buf, tmpbuf, sizeof(ethernet_phystate_header));
3529 /* We'll write this as a WS UPPER PDU packet with a data blob */
3530 /* This will create an interface with the "name" of the matching
3531 * WTAP_ENCAP_ETHERNET interface with the same channel and hardware
3532 * channel prefixed with "STATUS" and with a different interface ID,
3533 * because IDBs in pcapng can only have one linktype.
3534 * The other option would be to write everything as UPPER_PDU, including
3535 * the Ethernet data (with one of the "eth_" dissectors.)
3537 char* iface_name = ws_strdup_printf("STATUS-ETH-%u-%u", ethernet_phystate_header.channel, ethernet_phystate_header.hardwareChannel);
3538 blf_lookup_interface(params, WTAP_ENCAP_WIRESHARK_UPPER_PDU, ethernet_phystate_header.channel, ethernet_phystate_header.hardwareChannel, iface_name);
3539 g_free(iface_name);
3540 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));
3542 if ((ethernet_phystate_header.flags & BLF_PHY_STATE_HARDWARECHANNEL) == BLF_PHY_STATE_HARDWARECHANNEL) {
3543 /* If HW channel valid */
3544 wtap_block_add_uint32_option(params->rec->block, OPT_PKT_QUEUE, ethernet_phystate_header.hardwareChannel);
3547 return true;
3550 static bool
3551 blf_read_block(blf_params_t *params, int64_t start_pos, int *err, char **err_info) {
3552 blf_blockheader_t header;
3553 blf_logobjectheader_t logheader;
3554 blf_logobjectheader2_t logheader2;
3555 blf_logobjectheader3_t logheader3;
3556 uint32_t flags;
3557 uint64_t object_timestamp;
3558 uint16_t object_version;
3559 int64_t last_metadata_start = 0;
3560 size_t metadata_cont = 0;
3562 while (1) {
3563 /* Find Object */
3565 /* Resetting buffer */
3566 params->buf->first_free = params->buf->start;
3568 while (1) {
3569 if (!blf_read_bytes_or_eof(params, start_pos, &header, sizeof header, err, err_info)) {
3570 ws_debug("not enough bytes for block header or unsupported file");
3571 if (*err == WTAP_ERR_SHORT_READ) {
3572 /* we have found the end that is not a short read therefore. */
3573 *err = 0;
3574 g_free(*err_info);
3575 *err_info = NULL;
3577 return false;
3580 fix_endianness_blf_blockheader(&header);
3582 if (memcmp(header.magic, blf_obj_magic, sizeof(blf_obj_magic))) {
3583 ws_debug("object magic is not LOBJ (pos: 0x%" PRIx64 ")", start_pos);
3585 else {
3586 break;
3589 /* we are moving back and try again but 1 byte later */
3590 /* TODO: better understand how this paddings works... */
3591 start_pos++;
3593 params->blf_data->start_of_last_obj = start_pos;
3595 if (!params->random) {
3596 /* Make sure that we start after this object next time,
3597 * but only if it's a linear read. We can have random reads
3598 * during the linear read, so we have to make sure we don't
3599 * lose track of our position.
3601 params->blf_data->current_real_seek_pos = start_pos + MAX(MAX(16, header.object_length), header.header_length);
3604 switch (header.header_type) {
3605 case BLF_HEADER_TYPE_DEFAULT:
3606 if (!blf_read_log_object_header(params, err, err_info, start_pos + sizeof(blf_blockheader_t), start_pos + header.header_length, &logheader)) {
3607 return false;
3609 flags = logheader.flags;
3610 object_timestamp = logheader.object_timestamp;
3611 object_version = logheader.object_version;
3612 break;
3614 case BLF_HEADER_TYPE_2:
3615 if (!blf_read_log_object_header2(params, err, err_info, start_pos + sizeof(blf_blockheader_t), start_pos + header.header_length, &logheader2)) {
3616 return false;
3618 flags = logheader2.flags;
3619 object_timestamp = logheader2.object_timestamp;
3620 object_version = logheader2.object_version;
3621 break;
3623 case BLF_HEADER_TYPE_3:
3624 if (!blf_read_log_object_header3(params, err, err_info, start_pos + sizeof(blf_blockheader_t), start_pos + header.header_length, &logheader3)) {
3625 return false;
3627 flags = logheader3.flags;
3628 object_timestamp = logheader3.object_timestamp;
3629 object_version = logheader3.object_version;
3630 break;
3632 default:
3633 *err = WTAP_ERR_UNSUPPORTED;
3634 *err_info = ws_strdup_printf("blf: unknown header type %u", header.header_type);
3635 ws_debug("unknown header type");
3636 return false;
3639 if (metadata_cont && header.object_type != BLF_OBJTYPE_APP_TEXT) {
3640 /* If we're in the middle of a sequence of AppText metadata objects,
3641 * but we get an AppText object from another source,
3642 * skip the previous incomplete packet and start fresh.
3644 metadata_cont = 0;
3645 last_metadata_start = 0;
3648 switch (header.object_type) {
3649 case BLF_OBJTYPE_LOG_CONTAINER:
3650 *err = WTAP_ERR_UNSUPPORTED;
3651 *err_info = ws_strdup("blf: log container in log container not supported");
3652 ws_debug("log container in log container not supported");
3653 return false;
3655 case BLF_OBJTYPE_ETHERNET_FRAME:
3656 return blf_read_ethernetframe(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3658 case BLF_OBJTYPE_ETHERNET_FRAME_EX:
3659 return blf_read_ethernetframe_ext(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, false);
3661 case BLF_OBJTYPE_ETHERNET_RX_ERROR:
3662 return blf_read_ethernet_rxerror(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3664 case BLF_OBJTYPE_ETHERNET_ERROR_EX:
3665 return blf_read_ethernetframe_ext(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, true);
3667 case BLF_OBJTYPE_WLAN_FRAME:
3668 return blf_read_wlanframe(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3670 case BLF_OBJTYPE_CAN_MESSAGE:
3671 return blf_read_canmessage(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, false);
3673 case BLF_OBJTYPE_CAN_ERROR:
3674 return blf_read_canerror(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, false);
3676 case BLF_OBJTYPE_CAN_OVERLOAD:
3677 return blf_read_canerror(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, true);
3679 case BLF_OBJTYPE_CAN_MESSAGE2:
3680 return blf_read_canmessage(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, true);
3682 case BLF_OBJTYPE_CAN_ERROR_EXT:
3683 return blf_read_canerrorext(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3685 case BLF_OBJTYPE_CAN_FD_MESSAGE:
3686 return blf_read_canfdmessage(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3688 case BLF_OBJTYPE_CAN_FD_MESSAGE_64:
3689 return blf_read_canfdmessage64(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3691 case BLF_OBJTYPE_CAN_FD_ERROR_64:
3692 return blf_read_canfderror64(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3694 case BLF_OBJTYPE_FLEXRAY_DATA:
3695 return blf_read_flexraydata(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3697 case BLF_OBJTYPE_FLEXRAY_MESSAGE:
3698 return blf_read_flexraymessage(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3700 case BLF_OBJTYPE_FLEXRAY_RCVMESSAGE:
3701 return blf_read_flexrayrcvmessageex(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, false);
3703 case BLF_OBJTYPE_FLEXRAY_RCVMESSAGE_EX:
3704 return blf_read_flexrayrcvmessageex(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, true);
3706 case BLF_OBJTYPE_LIN_MESSAGE:
3707 return blf_read_linmessage(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, false);
3709 case BLF_OBJTYPE_LIN_CRC_ERROR:
3710 return blf_read_linmessage(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, true);
3712 case BLF_OBJTYPE_LIN_RCV_ERROR:
3713 return blf_read_linrcverror(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3715 case BLF_OBJTYPE_LIN_SND_ERROR:
3716 return blf_read_linsenderror(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3718 case BLF_OBJTYPE_LIN_WAKEUP:
3719 return blf_read_linwakeupevent(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3721 case BLF_OBJTYPE_LIN_MESSAGE2:
3722 return blf_read_linmessage2(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, object_version);
3724 case BLF_OBJTYPE_LIN_CRC_ERROR2:
3725 return blf_read_lincrcerror2(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, object_version);
3727 case BLF_OBJTYPE_LIN_RCV_ERROR2:
3728 return blf_read_linrcverror2(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, object_version);
3730 case BLF_OBJTYPE_LIN_SND_ERROR2:
3731 return blf_read_linsenderror2(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, object_version);
3733 case BLF_OBJTYPE_LIN_WAKEUP2:
3734 return blf_read_linwakeupevent2(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3736 case BLF_OBJTYPE_LIN_SLEEP:
3737 return blf_read_linsleepmodeevent(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3739 case BLF_OBJTYPE_APP_TEXT:
3741 int result = blf_read_apptextmessage(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, metadata_cont);
3742 if (result == BLF_APPTEXT_CONT) {
3743 if (!metadata_cont) {
3744 /* First object of a sequence, save its start position */
3745 last_metadata_start = start_pos;
3747 /* Save a pointer to the end of the buffer */
3748 metadata_cont = params->buf->first_free;
3750 else {
3751 if (result == BLF_APPTEXT_METADATA && metadata_cont) {
3752 /* Last object of a sequence, restore the start position of the first object */
3753 params->blf_data->start_of_last_obj = last_metadata_start;
3755 /* Reset everything and start fresh */
3756 last_metadata_start = 0;
3757 metadata_cont = 0;
3759 switch (result) {
3760 case BLF_APPTEXT_FAILED:
3761 return false;
3762 case BLF_APPTEXT_COMMENT:
3763 case BLF_APPTEXT_METADATA:
3764 case BLF_APPTEXT_ATTACHMENT:
3765 case BLF_APPTEXT_TRACELINE:
3766 return true;
3767 case BLF_APPTEXT_CHANNEL:
3768 case BLF_APPTEXT_CONT:
3769 default:
3770 /* we do not return since there is no packet to show here */
3771 start_pos += MAX(MAX(16, header.object_length), header.header_length);
3772 break;
3775 break;
3777 case BLF_OBJTYPE_ETHERNET_STATUS:
3778 return blf_read_ethernet_status(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp, object_version);
3780 case BLF_OBJTYPE_ETHERNET_PHY_STATE:
3781 return blf_read_ethernet_phystate(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, flags, object_timestamp);
3783 case BLF_OBJTYPE_ENV_INTEGER:
3784 case BLF_OBJTYPE_ENV_DOUBLE:
3785 case BLF_OBJTYPE_ENV_STRING:
3786 case BLF_OBJTYPE_ENV_DATA:
3787 case BLF_OBJTYPE_SYS_VARIABLE:
3788 case BLF_OBJTYPE_RESERVED5: /* Despite the name, this is actually used. Maybe it's worth investigating the content. */
3789 case BLF_OBJTYPE_TEST_STRUCTURE:
3790 ws_debug("skipping unsupported object type 0x%04x", header.object_type);
3791 start_pos += MAX(MAX(16, header.object_length), header.header_length);
3792 break;
3793 default:
3794 ws_info("unknown object type 0x%04x", header.object_type);
3795 start_pos += MAX(MAX(16, header.object_length), header.header_length);
3796 break;
3799 return true;
3802 static bool blf_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err, char **err_info, int64_t *data_offset) {
3803 blf_params_t blf_tmp;
3805 blf_tmp.wth = wth;
3806 blf_tmp.fh = wth->fh;
3807 blf_tmp.random = false;
3808 blf_tmp.pipe = wth->ispipe;
3809 blf_tmp.rec = rec;
3810 blf_tmp.buf = buf;
3811 blf_tmp.blf_data = (blf_t *)wth->priv;
3813 if (!blf_read_block(&blf_tmp, blf_tmp.blf_data->current_real_seek_pos, err, err_info)) {
3814 return false;
3816 *data_offset = blf_tmp.blf_data->start_of_last_obj;
3818 return true;
3821 static bool blf_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec, Buffer *buf, int *err, char **err_info) {
3822 blf_params_t blf_tmp;
3824 blf_tmp.wth = wth;
3825 blf_tmp.fh = wth->random_fh;
3826 blf_tmp.random = true;
3827 blf_tmp.pipe = wth->ispipe;
3828 blf_tmp.rec = rec;
3829 blf_tmp.buf = buf;
3830 blf_tmp.blf_data = (blf_t *)wth->priv;
3832 if (!blf_read_block(&blf_tmp, seek_off, err, err_info)) {
3833 ws_debug("couldn't read packet block (err=%d).", *err);
3834 return false;
3837 return true;
3840 static void blf_free(blf_t *blf) {
3841 if (blf != NULL) {
3842 if (blf->log_containers != NULL) {
3843 for (unsigned i = 0; i < blf->log_containers->len; i++) {
3844 blf_log_container_t* log_container = &g_array_index(blf->log_containers, blf_log_container_t, i);
3845 if (log_container->real_data != NULL) {
3846 g_free(log_container->real_data);
3849 g_array_free(blf->log_containers, true);
3850 blf->log_containers = NULL;
3852 if (blf->channel_to_iface_ht != NULL) {
3853 g_hash_table_destroy(blf->channel_to_iface_ht);
3854 blf->channel_to_iface_ht = NULL;
3856 if (blf->channel_to_name_ht != NULL) {
3857 g_hash_table_destroy(blf->channel_to_name_ht);
3858 blf->channel_to_name_ht = NULL;
3863 static void blf_close(wtap *wth) {
3864 blf_free((blf_t *)wth->priv);
3866 /* TODO: do we need to reverse the wtap_add_idb? how? */
3869 wtap_open_return_val
3870 blf_open(wtap *wth, int *err, char **err_info) {
3871 blf_fileheader_t header;
3872 blf_t *blf;
3874 ws_debug("opening file");
3876 if (!wtap_read_bytes_or_eof(wth->fh, &header, sizeof(blf_fileheader_t), err, err_info)) {
3878 ws_debug("wtap_read_bytes_or_eof() failed, err = %d.", *err);
3879 if (*err == 0 || *err == WTAP_ERR_SHORT_READ) {
3881 * Short read or EOF.
3883 * We're reading this as part of an open, so
3884 * the file is too short to be a blf file.
3886 *err = 0;
3887 g_free(*err_info);
3888 *err_info = NULL;
3889 return WTAP_OPEN_NOT_MINE;
3891 return WTAP_OPEN_ERROR;
3894 fix_endianness_blf_fileheader(&header);
3896 if (memcmp(header.magic, blf_magic, sizeof(blf_magic))) {
3897 return WTAP_OPEN_NOT_MINE;
3900 /* This seems to be an BLF! */
3901 /* Check for a valid header length */
3902 if (header.header_length < sizeof(blf_fileheader_t)) {
3903 *err = WTAP_ERR_BAD_FILE;
3904 *err_info = ws_strdup("blf: file header length too short");
3905 return WTAP_OPEN_ERROR;
3908 /* skip past the header, which may include padding/reserved space */
3909 if (!wtap_read_bytes(wth->fh, NULL, header.header_length - sizeof(blf_fileheader_t), err, err_info)) {
3910 return WTAP_OPEN_ERROR;
3913 /* Prepare our private context. */
3914 blf = g_new(blf_t, 1);
3915 blf->log_containers = g_array_new(false, false, sizeof(blf_log_container_t));
3916 blf->current_real_seek_pos = 0;
3917 blf->start_offset_ns = blf_get_start_offset_ns(&header.start_date);
3919 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);
3920 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);
3921 blf->next_interface_id = 0;
3923 wth->priv = (void *)blf;
3924 wth->file_encap = WTAP_ENCAP_NONE;
3925 wth->snapshot_length = 0;
3926 wth->file_tsprec = WTAP_TSPREC_UNKNOWN;
3927 wth->subtype_read = blf_read;
3928 wth->subtype_seek_read = blf_seek_read;
3929 wth->subtype_close = blf_close;
3930 wth->file_type_subtype = blf_file_type_subtype;
3932 return WTAP_OPEN_MINE;
3935 /* Options for interface blocks. */
3936 static const struct supported_option_type interface_block_options_supported[] = {
3937 /* No comments, just an interface name. */
3938 { OPT_IDB_NAME, ONE_OPTION_SUPPORTED }
3941 static const struct supported_block_type blf_blocks_supported[] = {
3942 { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED },
3943 { WTAP_BLOCK_IF_ID_AND_INFO, MULTIPLE_BLOCKS_SUPPORTED, OPTION_TYPES_SUPPORTED(interface_block_options_supported) },
3946 static const struct file_type_subtype_info blf_info = {
3947 "Vector Informatik Binary Logging Format (BLF) logfile", "blf", "blf", NULL,
3948 false, BLOCKS_SUPPORTED(blf_blocks_supported),
3949 NULL, NULL, NULL
3952 void register_blf(void)
3954 blf_file_type_subtype = wtap_register_file_type_subtype(&blf_info);
3957 * Register name for backwards compatibility with the
3958 * wtap_filetypes table in Lua.
3960 wtap_register_backwards_compatibility_lua_name("BLF", blf_file_type_subtype);
3964 * Editor modelines - https://www.wireshark.org/tools/modelines.html
3966 * Local variables:
3967 * c-basic-offset: 4
3968 * tab-width: 8
3969 * indent-tabs-mode: nil
3970 * End:
3972 * vi: set shiftwidth=4 tabstop=8 expandtab:
3973 * :indentSize=4:tabSize=8:noTabs=true: