1 /* file-blf.c
2  * BLF File Format.
3  * By Dr. Lars Voelker <lars.voelker@technica-engineering.de>
4  * Copyright 2020-2021 Dr. Lars Voelker
5   *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * SPDX-License-Identifier: GPL-2.0-or-later
11  *
12  * This dissector allows to parse BLF files.
13  */
14 
15  /*
16   * The following was used as a reference for the file format:
17   *     https://bitbucket.org/tobylorenz/vector_blf
18   * The repo above includes multiple examples files as well.
19   */
20 
21 #include "config.h"
22 
23 #include <epan/packet.h>
24 #include <epan/prefs.h>
25 #include <epan/expert.h>
26 #include <epan/exceptions.h>
27 #include <epan/show_exception.h>
28 #include <epan/wmem_scopes.h>
29 #include <wiretap/blf.h>
30 
31 static int proto_blf = -1;
32 
33 static int hf_blf_file_header = -1;
34 static int hf_blf_file_header_magic = -1;
35 static int hf_blf_file_header_length = -1;
36 static int hf_blf_file_header_api = -1;
37 static int hf_blf_file_header_app = -1;
38 static int hf_blf_file_header_comp_level = -1;
39 static int hf_blf_file_header_app_major = -1;
40 static int hf_blf_file_header_app_minor = -1;
41 static int hf_blf_file_header_len_comp = -1;
42 static int hf_blf_file_header_len_uncomp = -1;
43 static int hf_blf_file_header_obj_count = -1;
44 static int hf_blf_file_header_app_build = -1;
45 static int hf_blf_file_header_start_date = -1;
46 static int hf_blf_file_header_end_date = -1;
47 static int hf_blf_file_header_restore_point_offset = -1;
48 
49 static int hf_blf_lobj = -1;
50 static int hf_blf_lobj_hdr = -1;
51 static int hf_blf_lobj_magic = -1;
52 static int hf_blf_lobj_hdr_len = -1;
53 static int hf_blf_lobj_hdr_type = -1;
54 static int hf_blf_lobj_obj_len = -1;
55 static int hf_blf_lobj_obj_type = -1;
56 static int hf_blf_lobj_hdr_remains = -1;
57 static int hf_blf_lobj_payload = -1;
58 
59 static int hf_blf_cont_comp_method = -1;
60 static int hf_blf_cont_res1 = -1;
61 static int hf_blf_cont_res2 = -1;
62 static int hf_blf_cont_uncomp_size = -1;
63 static int hf_blf_cont_res4 = -1;
64 static int hf_blf_cont_payload = -1;
65 
66 static gint ett_blf = -1;
67 static gint ett_blf_header = -1;
68 static gint ett_blf_obj = -1;
69 static gint ett_blf_obj_header = -1;
70 static gint ett_blf_logcontainer_payload = -1;
71 
72 static const value_string blf_object_names[] = {
73     { BLF_OBJTYPE_UNKNOWN,                          "Unknown" },
74     { BLF_OBJTYPE_CAN_MESSAGE,                      "CAN Message" },
75     { BLF_OBJTYPE_CAN_ERROR,                        "CAN Error" },
76     { BLF_OBJTYPE_CAN_OVERLOAD,                     "CAN Overload" },
77     { BLF_OBJTYPE_CAN_STATISTIC,                    "CAN Statistics" },
78     { BLF_OBJTYPE_APP_TRIGGER,                      "App Trigger" },
79     { BLF_OBJTYPE_ENV_INTEGER,                      "Env Integer" },
80     { BLF_OBJTYPE_ENV_DOUBLE,                       "Env Double" },
81     { BLF_OBJTYPE_ENV_STRING,                       "Env String" },
82     { BLF_OBJTYPE_ENV_DATA,                         "Env Data" },
83     { BLF_OBJTYPE_LOG_CONTAINER,                    "Log Container" },
84     { BLF_OBJTYPE_LIN_MESSAGE,                      "LIN Message" },
85     { BLF_OBJTYPE_LIN_CRC_ERROR,                    "LIN CRC Error" },
86     { BLF_OBJTYPE_LIN_DLC_INFO,                     "LIN DLC Info" },
87     { BLF_OBJTYPE_LIN_RCV_ERROR,                    "LIN Receive Error" },
88     { BLF_OBJTYPE_LIN_SND_ERROR,                    "LIN Send Error" },
89     { BLF_OBJTYPE_LIN_SLV_TIMEOUT,                  "LIN Slave Timeout" },
90     { BLF_OBJTYPE_LIN_SCHED_MODCH,                  "LIN Schedule Mode Change" },
91     { BLF_OBJTYPE_LIN_SYN_ERROR,                    "LIN Sync Error" },
92     { BLF_OBJTYPE_LIN_BAUDRATE,                     "LIN Baudrate" },
93     { BLF_OBJTYPE_LIN_SLEEP,                        "LIN Sleep" },
94     { BLF_OBJTYPE_LIN_WAKEUP,                       "LIN Wakeup" },
95     { BLF_OBJTYPE_MOST_SPY,                         "MOST Spy" },
96     { BLF_OBJTYPE_MOST_CTRL,                        "MOST Control" },
97     { BLF_OBJTYPE_MOST_LIGHTLOCK,                   "MOST Light Lock" },
98     { BLF_OBJTYPE_MOST_STATISTIC,                   "MOST Statistics" },
99     { BLF_OBJTYPE_FLEXRAY_DATA,                     "FlexRay Data" },
100     { BLF_OBJTYPE_FLEXRAY_SYNC,                     "FlexRay Sync" },
101     { BLF_OBJTYPE_CAN_DRIVER_ERROR,                 "CAN Driver Error" },
102     { BLF_OBJTYPE_MOST_PKT,                         "MOST Packet" },
103     { BLF_OBJTYPE_MOST_PKT2,                        "MOST Packet 2" },
104     { BLF_OBJTYPE_MOST_HWMODE,                      "MOST Hardware Mode" },
105     { BLF_OBJTYPE_MOST_REG,                         "MOST Register Data" },
106     { BLF_OBJTYPE_MOST_GENREG,                      "MOST Register Data" },
107     { BLF_OBJTYPE_MOST_NETSTATE,                    "MOST Net State" },
108     { BLF_OBJTYPE_MOST_DATALOST,                    "MOST Data Lost" },
109     { BLF_OBJTYPE_MOST_TRIGGER,                     "MOST Trigger" },
110     { BLF_OBJTYPE_FLEXRAY_CYCLE,                    "FlexRay Cycle" },
111     { BLF_OBJTYPE_FLEXRAY_MESSAGE,                  "FlexRay Message" },
112     { BLF_OBJTYPE_LIN_CHECKSUM_INFO,                "LIN Checksum Info" },
113     { BLF_OBJTYPE_LIN_SPIKE_EVENT,                  "LIN Spike Event" },
114     { BLF_OBJTYPE_CAN_DRIVER_SYNC,                  "CAN Driver Sync" },
115     { BLF_OBJTYPE_FLEXRAY_STATUS,                   "FlexRay Status" },
116     { BLF_OBJTYPE_GPS_EVENT,                        "GPS Event" },
117     { BLF_OBJTYPE_FLEXRAY_ERROR,                    "FlexRay Error" },
118     { BLF_OBJTYPE_FLEXRAY_STATUS2,                  "FlexRay Status 2" },
119     { BLF_OBJTYPE_FLEXRAY_STARTCYCLE,               "FlexRay Start Cycle" },
120     { BLF_OBJTYPE_FLEXRAY_RCVMESSAGE,               "FlexRay Receive Message" },
121     { BLF_OBJTYPE_REALTIMECLOCK,                    "Realtime Clock" },
122     { BLF_OBJTYPE_LIN_STATISTIC,                    "LIN Statistics" },
123     { BLF_OBJTYPE_J1708_MESSAGE,                    "J1708 Message" },
124     { BLF_OBJTYPE_J1708_VIRTUAL_MSG,                "J1708 Virtual Message" },
125     { BLF_OBJTYPE_LIN_MESSAGE2,                     "LIN Message 2" },
126     { BLF_OBJTYPE_LIN_SND_ERROR2,                   "LIN Send Error 2" },
127     { BLF_OBJTYPE_LIN_SYN_ERROR2,                   "LIN Sync Error 2" },
128     { BLF_OBJTYPE_LIN_CRC_ERROR2,                   "LIN CRC Error 2" },
129     { BLF_OBJTYPE_LIN_RCV_ERROR2,                   "LIN Receive Error 2" },
130     { BLF_OBJTYPE_LIN_WAKEUP2,                      "LIN Wakeup 2" },
131     { BLF_OBJTYPE_LIN_SPIKE_EVENT2,                 "LIN Spike Event 2" },
132     { BLF_OBJTYPE_LIN_LONG_DOM_SIG,                 "LIN Long Dominant Signal" },
133     { BLF_OBJTYPE_APP_TEXT,                         "Text" },
134     { BLF_OBJTYPE_FLEXRAY_RCVMESSAGE_EX,            "FlexRay Receive Message Ext" },
135     { BLF_OBJTYPE_MOST_STATISTICEX,                 "MOST Statistics Ext" },
136     { BLF_OBJTYPE_MOST_TXLIGHT,                     "MOST TX Light" },
137     { BLF_OBJTYPE_MOST_ALLOCTAB,                    "MOST Allocation Table" },
138     { BLF_OBJTYPE_MOST_STRESS,                      "MOST Stress" },
139     { BLF_OBJTYPE_ETHERNET_FRAME,                   "Ethernet Frame" },
140     { BLF_OBJTYPE_SYS_VARIABLE,                     "System Variable" },
141     { BLF_OBJTYPE_CAN_ERROR_EXT,                    "CAN Error Ext" },
142     { BLF_OBJTYPE_CAN_DRIVER_ERROR_EXT,             "CAN Driver Error Ext" },
143     { BLF_OBJTYPE_LIN_LONG_DOM_SIG2,                "LIN Long Dominant Signal 2" },
144     { BLF_OBJTYPE_MOST_150_MESSAGE,                 "MOST150 Message" },
145     { BLF_OBJTYPE_MOST_150_PKT,                     "MOST150 Packet" },
146     { BLF_OBJTYPE_MOST_ETHERNET_PKT,                "MOST Ethernet Packet" },
147     { BLF_OBJTYPE_MOST_150_MESSAGE_FRAGMENT,        "MOST150 Message Fragment" },
148     { BLF_OBJTYPE_MOST_150_PKT_FRAGMENT,            "MOST150 Packet Fragment" },
149     { BLF_OBJTYPE_MOST_ETHERNET_PKT_FRAGMENT,       "MOST Ethernet Packet Fragment" },
150     { BLF_OBJTYPE_MOST_SYSTEM_EVENT,                "MOST System Event" },
151     { BLF_OBJTYPE_MOST_150_ALLOCTAB,                "MOST150 Allocation Table" },
152     { BLF_OBJTYPE_MOST_50_MESSAGE,                  "MOST50 Message" },
153     { BLF_OBJTYPE_MOST_50_PKT,                      "MOST50 Packet" },
154     { BLF_OBJTYPE_CAN_MESSAGE2,                     "CAN Message 2" },
155     { BLF_OBJTYPE_LIN_UNEXPECTED_WAKEUP,            "LIN Unexpected Wakeup" },
156     { BLF_OBJTYPE_LIN_SHORT_OR_SLOW_RESPONSE,       "LIN Short or Slow Response" },
157     { BLF_OBJTYPE_LIN_DISTURBANCE_EVENT,            "LIN Disturbance" },
158     { BLF_OBJTYPE_SERIAL_EVENT,                     "Serial" },
159     { BLF_OBJTYPE_OVERRUN_ERROR,                    "Overrun Error" },
160     { BLF_OBJTYPE_EVENT_COMMENT,                    "Comment" },
161     { BLF_OBJTYPE_WLAN_FRAME,                       "WLAN Frame" },
162     { BLF_OBJTYPE_WLAN_STATISTIC,                   "WLAN Statistics" },
163     { BLF_OBJTYPE_MOST_ECL,                         "MOST Electric Control Line" },
164     { BLF_OBJTYPE_GLOBAL_MARKER,                    "Global Marker" },
165     { BLF_OBJTYPE_AFDX_FRAME,                       "AFDX Frame" },
166     { BLF_OBJTYPE_AFDX_STATISTIC,                   "AFDX Statistics" },
167     { BLF_OBJTYPE_KLINE_STATUSEVENT,                "KLINE Status" },
168     { BLF_OBJTYPE_CAN_FD_MESSAGE,                   "CANFD Message" },
169     { BLF_OBJTYPE_CAN_FD_MESSAGE_64,                "CANFD Message 64" },
170     { BLF_OBJTYPE_ETHERNET_RX_ERROR,                "Ethernet RX Error" },
171     { BLF_OBJTYPE_ETHERNET_STATUS,                  "Ethernet Status" },
172     { BLF_OBJTYPE_CAN_FD_ERROR_64,                  "CANFD Error 64" },
173     { BLF_OBJTYPE_AFDX_STATUS,                      "AFDX Status" },
174     { BLF_OBJTYPE_AFDX_BUS_STATISTIC,               "AFDX Bus Statistics" },
175     { BLF_OBJTYPE_AFDX_ERROR_EVENT,                 "AFDX Error" },
176     { BLF_OBJTYPE_A429_ERROR,                       "A429 Error" },
177     { BLF_OBJTYPE_A429_STATUS,                      "A429 Status" },
178     { BLF_OBJTYPE_A429_BUS_STATISTIC,               "A429 Bus Statistics" },
179     { BLF_OBJTYPE_A429_MESSAGE,                     "A429 Message" },
180     { BLF_OBJTYPE_ETHERNET_STATISTIC,               "Ethernet Statistics" },
181     { BLF_OBJTYPE_TEST_STRUCTURE,                   "Test Structure" },
182     { BLF_OBJTYPE_DIAG_REQUEST_INTERPRETATION,      "Diagnostics Request Interpretation" },
183     { BLF_OBJTYPE_ETHERNET_FRAME_EX,                "Ethernet Frame Ext" },
184     { BLF_OBJTYPE_ETHERNET_FRAME_FORWARDED,         "Ethernet Frame Forwarded" },
185     { BLF_OBJTYPE_ETHERNET_ERROR_EX,                "Ethernet Error Ext" },
186     { BLF_OBJTYPE_ETHERNET_ERROR_FORWARDED,         "Ethernet Error Forwarded" },
187     { BLF_OBJTYPE_FUNCTION_BUS,                     "Function Bus" },
188     { BLF_OBJTYPE_DATA_LOST_BEGIN,                  "Data Lost Begin" },
189     { BLF_OBJTYPE_DATA_LOST_END,                    "Data Lost End" },
190     { BLF_OBJTYPE_WATER_MARK_EVENT,                 "Watermark" },
191     { BLF_OBJTYPE_TRIGGER_CONDITION,                "Trigger Condition" },
192     { BLF_OBJTYPE_CAN_SETTING_CHANGED,              "CAN Settings Changed" },
193     { BLF_OBJTYPE_DISTRIBUTED_OBJECT_MEMBER,        "Distributed Object Member" },
194     { BLF_OBJTYPE_ATTRIBUTE_EVENT,                  "Attribute Event" },
195     { 0, NULL }
196 };
197 
198 static const value_string application_names[] = {
199     { 0,    "Unknown" },
200     { 1,    "Vector CANalyzer" },
201     { 2,    "Vector CANoe" },
202     { 3,    "Vector CANstress" },
203     { 4,    "Vector CANlog" },
204     { 5,    "Vector CANape" },
205     { 6,    "Vector CANcaseXL log" },
206     { 7,    "Vector Logger Configurator" },
207     { 200,  "Porsche Logger" },
208     { 201,  "CAETEC Logger" },
209     { 202,  "Vector Network Simulator" },
210     { 203,  "IPETRONIK logger" },
211     { 204,  "RT PK" },
212     { 205,  "PikeTec" },
213     { 206,  "Sparks" },
214     { 0, NULL }
215 };
216 
217 
218 #define BLF_COMPRESSION_NONE    0
219 #define BLF_COMPRESSION_ZLIB    2
220 
221 static const value_string blf_compression_names[] = {
222     { BLF_COMPRESSION_NONE,     "No Compression" },
223     { BLF_COMPRESSION_ZLIB,     "Compression ZLIB" },
224     { 0, NULL }
225 };
226 
227 void proto_register_file_blf(void);
228 void proto_reg_handoff_file_blf(void);
229 static int dissect_blf_next_object(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset);
230 
231 #define MAGIC_NUMBER_SIZE 4
232 static const guint8 blf_file_magic[MAGIC_NUMBER_SIZE] = { 'L', 'O', 'G', 'G' };
233 static const guint8 blf_lobj_magic[MAGIC_NUMBER_SIZE] = { 'L', 'O', 'B', 'J' };
234 
235 
236 static proto_item *
dissect_blf_header_date(proto_tree * tree,int hf,tvbuff_t * tvb,gint offset,gint length)237 dissect_blf_header_date(proto_tree *tree, int hf, tvbuff_t *tvb, gint offset, gint length) {
238     static const value_string weekday_names[] = {
239     { 0,    "Sunday"},
240     { 1,    "Monday"},
241     { 2,    "Tuesday"},
242     { 3,    "Wednesday"},
243     { 4,    "Thursday"},
244     { 5,    "Friday"},
245     { 6,    "Saturday"},
246     { 0, NULL }
247     };
248 
249     guint16 year        = tvb_get_guint16(tvb, offset +  0, ENC_LITTLE_ENDIAN);
250     guint16 month       = tvb_get_guint16(tvb, offset +  2, ENC_LITTLE_ENDIAN);
251     guint16 day_of_week = tvb_get_guint16(tvb, offset +  4, ENC_LITTLE_ENDIAN);
252     guint16 day         = tvb_get_guint16(tvb, offset +  6, ENC_LITTLE_ENDIAN);
253     guint16 hour        = tvb_get_guint16(tvb, offset +  8, ENC_LITTLE_ENDIAN);
254     guint16 minute      = tvb_get_guint16(tvb, offset + 10, ENC_LITTLE_ENDIAN);
255     guint16 sec         = tvb_get_guint16(tvb, offset + 12, ENC_LITTLE_ENDIAN);
256     guint16 ms          = tvb_get_guint16(tvb, offset + 14, ENC_LITTLE_ENDIAN);
257 
258     header_field_info *hfinfo = proto_registrar_get_nth(hf);
259 
260     return proto_tree_add_bytes_format(tree, hf, tvb, offset, length, NULL,
261                                        "%s: %s %d-%02d-%02d %02d:%02d:%02d.%03d",
262                                        hfinfo->name,
263                                        val_to_str(day_of_week, weekday_names, "%d"),
264                                        year, month, day, hour, minute, sec, ms);
265 }
266 
267 static proto_item *
dissect_blf_api_version(proto_tree * tree,int hf,tvbuff_t * tvb,gint offset,gint length)268 dissect_blf_api_version(proto_tree *tree, int hf, tvbuff_t *tvb, gint offset, gint length) {
269     guint8 major = tvb_get_guint8(tvb, offset + 0);
270     guint8 minor = tvb_get_guint8(tvb, offset + 1);
271     guint8 build = tvb_get_guint8(tvb, offset + 2);
272     guint8 patch = tvb_get_guint8(tvb, offset + 3);
273 
274     header_field_info *hfinfo = proto_registrar_get_nth(hf);
275 
276     return proto_tree_add_bytes_format(tree, hf, tvb, offset, length, NULL, "%s: %d.%d.%d.%d",
277                                        hfinfo->name, major, minor, build, patch);
278 }
279 
280 static int
dissect_blf_lobj(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree,gint offset_orig)281 dissect_blf_lobj(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset_orig) {
282     proto_item    *ti_root = NULL;
283     proto_item    *ti = NULL;
284     proto_tree    *objtree = NULL;
285     proto_tree    *subtree = NULL;
286     volatile gint  offset = offset_orig;
287     tvbuff_t      *sub_tvb;
288 
289     guint          hdr_length = tvb_get_guint16(tvb, offset_orig + 4, ENC_LITTLE_ENDIAN);
290     guint          obj_length;
291     guint          obj_type;
292     guint32        comp_method;
293 
294     /* this should never happen since we should only be called with at least 16 Bytes present */
295     if (tvb_captured_length_remaining(tvb, offset_orig) < 16) {
296         return tvb_captured_length_remaining(tvb, offset_orig);
297     }
298 
299     ti_root = proto_tree_add_item(tree, hf_blf_lobj, tvb, offset, -1, ENC_NA);
300     objtree = proto_item_add_subtree(ti_root, ett_blf_obj);
301 
302     ti = proto_tree_add_item(objtree, hf_blf_lobj_hdr, tvb, offset, hdr_length, ENC_NA);
303     subtree = proto_item_add_subtree(ti, ett_blf_obj);
304 
305     proto_tree_add_item(subtree, hf_blf_lobj_magic, tvb, offset, 4, ENC_NA);
306     offset += 4;
307     proto_tree_add_item(subtree, hf_blf_lobj_hdr_len, tvb, offset, 2, ENC_LITTLE_ENDIAN);
308     offset += 2;
309     proto_tree_add_item(subtree, hf_blf_lobj_hdr_type, tvb, offset, 2, ENC_LITTLE_ENDIAN);
310     offset += 2;
311     proto_tree_add_item_ret_uint(subtree, hf_blf_lobj_obj_len, tvb, offset, 4, ENC_LITTLE_ENDIAN, &obj_length);
312     offset += 4;
313     proto_tree_add_item_ret_uint(subtree, hf_blf_lobj_obj_type, tvb, offset, 4, ENC_LITTLE_ENDIAN, &obj_type);
314     offset += 4;
315 
316     /* check if the whole object is present or if it was truncated */
317     if (tvb_captured_length_remaining(tvb, offset_orig) < (gint)obj_length) {
318         proto_item_set_end(ti_root, tvb, offset_orig + tvb_captured_length_remaining(tvb, offset_orig));
319         proto_item_append_text(ti_root, " TRUNCATED");
320         return tvb_captured_length_remaining(tvb, offset_orig);
321     }
322 
323     proto_item_set_end(ti_root, tvb, offset_orig + obj_length);
324     proto_item_append_text(ti_root, " (%s)", val_to_str(obj_type, blf_object_names, "%d"));
325 
326     switch (obj_type) {
327         case BLF_OBJTYPE_LOG_CONTAINER:
328             proto_tree_add_item_ret_uint(objtree, hf_blf_cont_comp_method, tvb, offset, 2, ENC_LITTLE_ENDIAN, &comp_method);
329             offset += 2;
330             proto_tree_add_item(objtree, hf_blf_cont_res1, tvb, offset, 2, ENC_LITTLE_ENDIAN);
331             offset += 2;
332             proto_tree_add_item(objtree, hf_blf_cont_res2, tvb, offset, 4, ENC_LITTLE_ENDIAN);
333             offset += 4;
334             proto_tree_add_item(objtree, hf_blf_cont_uncomp_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
335             offset += 4;
336             proto_tree_add_item(objtree, hf_blf_cont_res4, tvb, offset, 4, ENC_LITTLE_ENDIAN);
337             offset += 4;
338             if (comp_method == BLF_COMPRESSION_NONE) {
339                 sub_tvb = tvb_new_subset_length_caplen(tvb, offset, offset_orig + obj_length - offset, offset_orig + obj_length - offset);
340             } else {
341                 sub_tvb = tvb_child_uncompress(tvb, tvb, offset, offset_orig + obj_length - offset);
342                 if (sub_tvb) {
343                     add_new_data_source(pinfo, sub_tvb, "Decompressed Data");
344                 }
345             }
346 
347             /* TODO: actually the objects might overlap containers, which we do not consider here... */
348             if (sub_tvb) {
349                 guint offset_sub = 0;
350                 ti = proto_tree_add_item(objtree, hf_blf_cont_payload, sub_tvb, 0, offset_orig + obj_length - offset, ENC_NA);
351                 subtree = proto_item_add_subtree(ti, ett_blf_logcontainer_payload);
352 
353                 guint tmp = 42;
354                 while ((offset_sub + 16 <= offset_orig + obj_length - offset) && (tmp > 0)) {
355                     tmp = dissect_blf_next_object(sub_tvb, pinfo, subtree, offset_sub);
356                     offset_sub += tmp;
357                 }
358             }
359             break;
360         default:
361             if (offset - offset_orig < (gint)hdr_length) {
362                 proto_tree_add_item(subtree, hf_blf_lobj_hdr_remains, tvb, offset, hdr_length - (offset - offset_orig), ENC_NA);
363                 offset = offset_orig + hdr_length;
364             }
365 
366             proto_tree_add_item(objtree, hf_blf_lobj_payload, tvb, offset, obj_length - hdr_length, ENC_NA);
367             offset = offset_orig + obj_length;
368             break;
369     }
370 
371     return (gint)obj_length;
372 }
373 
374 static int
dissect_blf_next_object(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset)375 dissect_blf_next_object(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset) {
376     gint offset_orig = offset;
377 
378     while (tvb_captured_length_remaining(tvb, offset) >= 16) {
379         if (tvb_memeql(tvb, offset, blf_lobj_magic, MAGIC_NUMBER_SIZE) != 0) {
380             offset += 1;
381         } else {
382             int bytes_parsed = dissect_blf_lobj(tvb, pinfo, tree, offset);
383             if (bytes_parsed <= 0) {
384                 return 0;
385             } else {
386                 offset += bytes_parsed;
387             }
388         }
389     }
390 
391     return offset - offset_orig;
392 }
393 
394 
395 static int
dissect_blf(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)396 dissect_blf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
397     volatile gint    offset = 0;
398     proto_tree      *blf_tree;
399     proto_tree      *subtree;
400     proto_item      *ti;
401     guint            length;
402 
403     if (tvb_captured_length(tvb) < 8 || tvb_memeql(tvb, 0, blf_file_magic, MAGIC_NUMBER_SIZE) != 0) {
404         /* does not start with LOGG, so this is not BLF it seems */
405         return 0;
406     }
407 
408     ti = proto_tree_add_item(tree, proto_blf, tvb, offset, -1, ENC_NA);
409     blf_tree = proto_item_add_subtree(ti, ett_blf);
410     length = tvb_get_guint32(tvb, 4, ENC_LITTLE_ENDIAN);
411 
412     ti = proto_tree_add_item(blf_tree, hf_blf_file_header, tvb, offset, length, ENC_NA);
413     subtree = proto_item_add_subtree(ti, ett_blf_header);
414 
415     proto_tree_add_item(subtree, hf_blf_file_header_magic, tvb, offset, 4, ENC_NA);
416     offset += 4;
417     proto_tree_add_item(subtree, hf_blf_file_header_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
418     offset += 4;
419     dissect_blf_api_version(subtree, hf_blf_file_header_api, tvb, offset, 4);
420     offset += 4;
421     proto_tree_add_item(subtree, hf_blf_file_header_app, tvb, offset, 1, ENC_NA);
422     offset += 1;
423     proto_tree_add_item(subtree, hf_blf_file_header_comp_level, tvb, offset, 1, ENC_NA);
424     offset += 1;
425     proto_tree_add_item(subtree, hf_blf_file_header_app_major, tvb, offset, 1, ENC_NA);
426     offset += 1;
427     proto_tree_add_item(subtree, hf_blf_file_header_app_minor, tvb, offset, 1, ENC_NA);
428     offset += 1;
429     proto_tree_add_item(subtree, hf_blf_file_header_len_comp, tvb, offset, 8, ENC_LITTLE_ENDIAN);
430     offset += 8;
431     proto_tree_add_item(subtree, hf_blf_file_header_len_uncomp, tvb, offset, 8, ENC_LITTLE_ENDIAN);
432     offset += 8;
433     proto_tree_add_item(subtree, hf_blf_file_header_obj_count, tvb, offset, 4, ENC_LITTLE_ENDIAN);
434     offset += 4;
435     proto_tree_add_item(subtree, hf_blf_file_header_app_build, tvb, offset, 4, ENC_LITTLE_ENDIAN);
436     offset += 4;
437     dissect_blf_header_date(subtree, hf_blf_file_header_start_date, tvb, offset, 16);
438     offset += 16;
439     dissect_blf_header_date(subtree, hf_blf_file_header_end_date, tvb, offset, 16);
440     offset += 16;
441     proto_tree_add_item(subtree, hf_blf_file_header_restore_point_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN);
442     offset += 8;
443 
444     offset += dissect_blf_next_object(tvb, pinfo, blf_tree, offset);
445 
446     return offset;
447 }
448 
449 static gboolean
dissect_blf_heur(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)450 dissect_blf_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
451     return dissect_blf(tvb, pinfo, tree, NULL) > 0;
452 }
453 
454 void
proto_register_file_blf(void)455 proto_register_file_blf(void) {
456     static hf_register_info hf[] = {
457         { &hf_blf_file_header,
458             { "File Header", "blf.file_header", FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }},
459         { &hf_blf_file_header_magic,
460             { "Magic", "blf.file_header.magic", FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }},
461         { &hf_blf_file_header_length,
462             { "Header Length", "blf.file_header.length", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }},
463         { &hf_blf_file_header_api,
464             { "API Version", "blf.file_header.api", FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }},
465         { &hf_blf_file_header_app,
466             { "Application", "blf.file_header.application", FT_UINT8, BASE_DEC, VALS(application_names), 0x00, NULL, HFILL }},
467         { &hf_blf_file_header_comp_level,
468             { "Compression Level", "blf.file_header.compression_level", FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL }},
469         { &hf_blf_file_header_app_major,
470             { "Application Major Version", "blf.file_header.application_major", FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL }},
471         { &hf_blf_file_header_app_minor,
472             { "Application Minor Version", "blf.file_header.application_minor", FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL }},
473         { &hf_blf_file_header_len_comp,
474             { "Length (compressed)", "blf.file_header.length_compressed", FT_UINT64, BASE_DEC, NULL, 0x00, NULL, HFILL }},
475         { &hf_blf_file_header_len_uncomp,
476             { "Length (uncompressed)", "blf.file_header.length_uncompressed", FT_UINT64, BASE_DEC, NULL, 0x00, NULL, HFILL }},
477         { &hf_blf_file_header_obj_count,
478             { "Object Count", "blf.file_header.object_count", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }},
479         { &hf_blf_file_header_app_build,
480             { "Application Build", "blf.file_header.application_build", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }},
481         { &hf_blf_file_header_start_date,
482             { "Start Date", "blf.file_header.start_date", FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }},
483         { &hf_blf_file_header_end_date,
484             { "End Date", "blf.file_header.end_date", FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }},
485         { &hf_blf_file_header_restore_point_offset,
486             { "Restore Point Offset", "blf.file_header.restore_point_offset", FT_UINT64, BASE_DEC, NULL, 0x00, NULL, HFILL }},
487 
488         { &hf_blf_lobj,
489             { "Object", "blf.object", FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }},
490         { &hf_blf_lobj_hdr,
491             { "Object Header", "blf.object.header", FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }},
492         { &hf_blf_lobj_magic,
493             { "Magic", "blf.object.header.magic", FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }},
494         { &hf_blf_lobj_hdr_len,
495             { "Header Length", "blf.object.header.header_length", FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL }},
496         { &hf_blf_lobj_hdr_type,
497             { "Header Type", "blf.object.header.header_type", FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL }},
498         { &hf_blf_lobj_obj_len,
499             { "Object Length", "blf.object.header.object_length", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }},
500         { &hf_blf_lobj_obj_type,
501             { "Object Type", "blf.object.header.object_type", FT_UINT32, BASE_DEC, VALS(blf_object_names), 0x00, NULL, HFILL }},
502         { &hf_blf_lobj_hdr_remains,
503             { "Header unparsed", "blf.object.header.unparsed", FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }},
504         { &hf_blf_lobj_payload,
505             { "Payload", "blf.object.payload", FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }},
506 
507         { &hf_blf_cont_comp_method,
508             { "Compression Method", "blf.object.logcontainer.compression_method", FT_UINT16, BASE_HEX, VALS(blf_compression_names), 0x00, NULL, HFILL }},
509         { &hf_blf_cont_res1,
510             { "Reserved", "blf.object.logcontainer.res1", FT_UINT16, BASE_HEX, NULL, 0x00, NULL, HFILL }},
511         { &hf_blf_cont_res2,
512             { "Reserved", "blf.object.logcontainer.res2", FT_UINT32, BASE_HEX, NULL, 0x00, NULL, HFILL }},
513         { &hf_blf_cont_uncomp_size,
514             { "Uncompressed Length", "blf.object.logcontainer.uncompressed_length", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }},
515         { &hf_blf_cont_res4,
516             { "Reserved", "blf.object.logcontainer.res4", FT_UINT32, BASE_HEX, NULL, 0x00, NULL, HFILL }},
517         { &hf_blf_cont_payload,
518             { "Payload", "blf.object.logcontainer.payload", FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }},
519 
520     };
521 
522     static gint *ett[] = {
523         &ett_blf,
524         &ett_blf_header,
525         &ett_blf_obj,
526         &ett_blf_obj_header,
527         &ett_blf_logcontainer_payload,
528     };
529 
530     proto_blf = proto_register_protocol("BLF File Format", "File-BLF", "file-blf");
531     proto_register_field_array(proto_blf, hf, array_length(hf));
532     proto_register_subtree_array(ett, array_length(ett));
533 
534     register_dissector("file-blf", dissect_blf, proto_blf);
535 }
536 
537 void
proto_reg_handoff_file_blf(void)538 proto_reg_handoff_file_blf(void) {
539     heur_dissector_add("wtap_file", dissect_blf_heur, "BLF File", "blf_wtap", proto_blf, HEURISTIC_ENABLE);
540 }
541 
542 /*
543  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
544  *
545  * Local Variables:
546  * c-basic-offset: 4
547  * tab-width: 8
548  * indent-tabs-mode: nil
549  * End:
550  *
551  * ex: set shiftwidth=4 tabstop=8 expandtab:
552  * :indentSize=4:tabSize=8:noTabs=true:
553  */
554