d436d60871b28014c713f9fba66fd069f59592d1
[metze/wireshark/wip.git] / wiretap / peektagged.c
1 /* peektagged.c
2  * Routines for opening files in what WildPackets calls the tagged file
3  * format in the description of their "PeekRdr Sample Application" (C++
4  * source code to read their capture files, downloading of which requires
5  * a maintenance contract, so it's not free as in beer and probably not
6  * as in speech, either).
7  *
8  * As that description says, it's used by AiroPeek and AiroPeek NX 2.0
9  * and later, EtherPeek 6.0 and later, EtherPeek NX 3.0 and later,
10  * EtherPeek VX 1.0 and later, GigaPeek NX 1.0 and later, Omni3 1.0
11  * and later (both OmniPeek and the Remote Engine), and WANPeek NX
12  * 1.0 and later.  They also say it'll be used by future WildPackets
13  * products.
14  *
15  * Wiretap Library
16  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
17  *
18  * This program is free software; you can redistribute it and/or
19  * modify it under the terms of the GNU General Public License
20  * as published by the Free Software Foundation; either version 2
21  * of the License, or (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with this program; if not, write to the Free Software
30  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31  */
32
33 #include "config.h"
34 #include <errno.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include "wtap-int.h"
38 #include "file_wrappers.h"
39 #include <wsutil/buffer.h>
40 #include "peektagged.h"
41
42 /* CREDITS
43  *
44  * This file decoder could not have been writen without examining
45  * http://www.varsanofiev.com/inside/airopeekv9.htm, the help from
46  * Martin Regner and Guy Harris, and the etherpeek.c file (as it
47  * was called before renaming it to peekclassic.c).
48  */
49
50 /*
51  * Section header.
52  *
53  * A Peek tagged file consists of multiple sections, each of which begins
54  * with a header in the following format.
55  *
56  * The section ID is a 4-character string saying what type of section
57  * it is.  The section length is a little-endian field giving the
58  * length of the section, in bytes, including the section header
59  * itself.  The other field of the section header is a little-endian
60  * constant that always appears to be 0x00000200.
61  *
62  * Files we've seen have the following sections, in order:
63  *
64  * "\177vers" - version information.  The contents are XML, giving
65  * the file format version and application version information.
66  *
67  * "sess" - capture session information.  The contents are XML, giving
68  * various information about the capture session.
69  *
70  * "pkts" - captured packets.  The contents are binary records, one for
71  * each packet, with the record being a list of tagged values followed
72  * by the raw packet data.
73  */
74 typedef struct peektagged_section_header {
75         gint8   section_id[4];          /* string identifying the section */
76         guint32 section_len;            /* little-endian section length */
77         guint32 section_const;          /* little-endian 0x00000200 */
78 } peektagged_section_header_t;
79
80 /*
81  * Network subtype values.
82  *
83  * XXX - do different network subtype values for 802.11 indicate different
84  * network adapter types, with some adapters supplying the FCS and others
85  * not supplying the FCS?
86  */
87 #define PEEKTAGGED_NST_ETHERNET         0
88 #define PEEKTAGGED_NST_802_11           1       /* 802.11 with 0's at the end */
89 #define PEEKTAGGED_NST_802_11_2         2       /* 802.11 with 0's at the end */
90 #define PEEKTAGGED_NST_802_11_WITH_FCS  3       /* 802.11 with FCS at the end */
91
92 /* tags for fields in packet header */
93 #define TAG_PEEKTAGGED_LENGTH                   0x0000
94 #define TAG_PEEKTAGGED_TIMESTAMP_LOWER          0x0001
95 #define TAG_PEEKTAGGED_TIMESTAMP_UPPER          0x0002
96 #define TAG_PEEKTAGGED_FLAGS_AND_STATUS         0x0003
97 #define TAG_PEEKTAGGED_CHANNEL                  0x0004
98 #define TAG_PEEKTAGGED_RATE                     0x0005
99 #define TAG_PEEKTAGGED_SIGNAL_PERC              0x0006
100 #define TAG_PEEKTAGGED_SIGNAL_DBM               0x0007
101 #define TAG_PEEKTAGGED_NOISE_PERC               0x0008
102 #define TAG_PEEKTAGGED_NOISE_DBM                0x0009
103 #define TAG_PEEKTAGGED_UNKNOWN_0x000A           0x000A
104 #define TAG_PEEKTAGGED_UNKNOWN_0x000D           0x000D  /* frequency? */
105 #define TAG_PEEKTAGGED_UNKNOWN_0x000E           0x000E
106 #define TAG_PEEKTAGGED_UNKNOWN_0x000F           0x000F  /* 000F-0013 - dBm values? */
107 #define TAG_PEEKTAGGED_UNKNOWN_0x0010           0x0010
108 #define TAG_PEEKTAGGED_UNKNOWN_0x0011           0x0011
109 #define TAG_PEEKTAGGED_UNKNOWN_0x0012           0x0012
110 #define TAG_PEEKTAGGED_UNKNOWN_0x0013           0x0013
111 #define TAG_PEEKTAGGED_UNKNOWN_0x0014           0x0014
112 #define TAG_PEEKTAGGED_UNKNOWN_0x0015           0x0015
113
114 #define TAG_PEEKTAGGED_SLICE_LENGTH             0xffff
115
116 /* 64-bit time in nanoseconds from the (Windows FILETIME) epoch */
117 typedef struct peektagged_utime {
118         guint32 upper;
119         guint32 lower;
120 } peektagged_utime;
121
122 typedef struct {
123         gboolean        has_fcs;
124 } peektagged_t;
125
126 static gboolean peektagged_read(wtap *wth, int *err, gchar **err_info,
127     gint64 *data_offset);
128 static gboolean peektagged_seek_read(wtap *wth, gint64 seek_off,
129     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
130
131 static int wtap_file_read_pattern (wtap *wth, const char *pattern, int *err,
132                                 gchar **err_info)
133 {
134     int c;
135     const char *cp;
136
137     cp = pattern;
138     while (*cp)
139     {
140         c = file_getc(wth->fh);
141         if (c == EOF)
142         {
143             *err = file_error(wth->fh, err_info);
144             if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
145                 return -1;      /* error */
146             return 0;   /* EOF */
147         }
148         if (c == *cp)
149             cp++;
150         else
151         {
152             if (c == pattern[0])
153                 cp = &pattern[1];
154             else
155                 cp = pattern;
156         }
157     }
158     return (*cp == '\0' ? 1 : 0);
159 }
160
161
162 static int wtap_file_read_till_separator (wtap *wth, char *buffer, int buflen,
163                                         const char *separators, int *err,
164                                         gchar **err_info)
165 {
166     int c;
167     char *cp;
168     int i;
169
170     for (cp = buffer, i = 0; i < buflen; i++, cp++)
171     {
172         c = file_getc(wth->fh);
173         if (c == EOF)
174         {
175             *err = file_error(wth->fh, err_info);
176             if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
177                 return -1;      /* error */
178             return 0;   /* EOF */
179         }
180         if (strchr (separators, c) != NULL)
181         {
182             *cp = '\0';
183             break;
184         }
185         else
186             *cp = c;
187     }
188     return i;
189 }
190
191
192 static int wtap_file_read_number (wtap *wth, guint32 *num, int *err,
193                                 gchar **err_info)
194 {
195     int ret;
196     char str_num[12];
197     unsigned long value;
198     char *p;
199
200     ret = wtap_file_read_till_separator (wth, str_num, sizeof (str_num)-1, "<",
201                                          err, err_info);
202     if (ret != 1) {
203         /* 0 means EOF, which means "not a valid Peek tagged file";
204            -1 means error, and "err" has been set. */
205         return ret;
206     }
207     value = strtoul (str_num, &p, 10);
208     if (p == str_num || value > G_MAXUINT32)
209         return 0;
210     *num = (guint32)value;
211     return 1;
212 }
213
214
215 int peektagged_open(wtap *wth, int *err, gchar **err_info)
216 {
217     peektagged_section_header_t ap_hdr;
218     int ret;
219     guint32 fileVersion;
220     guint32 mediaType;
221     guint32 mediaSubType = 0;
222     int file_encap;
223     static const int peektagged_encap[] = {
224         WTAP_ENCAP_ETHERNET,
225         WTAP_ENCAP_IEEE_802_11_WITH_RADIO,
226         WTAP_ENCAP_IEEE_802_11_WITH_RADIO,
227         WTAP_ENCAP_IEEE_802_11_WITH_RADIO
228     };
229     #define NUM_PEEKTAGGED_ENCAPS (sizeof peektagged_encap / sizeof peektagged_encap[0])
230     peektagged_t *peektagged;
231
232     if (!wtap_read_bytes(wth->fh, &ap_hdr, (int)sizeof(ap_hdr), err, err_info)) {
233         if (*err != WTAP_ERR_SHORT_READ)
234             return -1;
235         return 0;
236     }
237
238     if (memcmp (ap_hdr.section_id, "\177ver", sizeof(ap_hdr.section_id)) != 0)
239         return 0;       /* doesn't begin with a "\177ver" section */
240
241     /*
242      * XXX - we should get the length of the "\177ver" section, check
243      * that it's followed by a little-endian 0x00000200, and then,
244      * when reading the XML, make sure we don't go past the end of
245      * that section, and skip to the end of that section when
246      * we have the file version (and possibly check to make sure all
247      * tags are properly opened and closed).
248      */
249     ret = wtap_file_read_pattern (wth, "<FileVersion>", err, err_info);
250     if (ret != 1) {
251         /* 0 means EOF, which means "not a valid Peek tagged file";
252            -1 means error, and "err" has been set. */
253         return ret;
254     }
255     ret = wtap_file_read_number (wth, &fileVersion, err, err_info);
256     if (ret != 1) {
257         /* 0 means EOF, which means "not a valid Peek tagged file";
258            -1 means error, and "err" has been set. */
259         return ret;
260     }
261
262     /* If we got this far, we assume it's a Peek tagged file. */
263     if (fileVersion != 9) {
264         /* We only support version 9. */
265         *err = WTAP_ERR_UNSUPPORTED;
266         *err_info = g_strdup_printf("peektagged: version %u unsupported",
267             fileVersion);
268         return -1;
269     }
270
271     /*
272      * XXX - once we've skipped the "\177ver" section, we should
273      * check for a "sess" section and fail if we don't see it.
274      * Then we should get the length of the "sess" section, check
275      * that it's followed by a little-endian 0x00000200, and then,
276      * when reading the XML, make sure we don't go past the end of
277      * that section, and skip to the end of the section when
278      * we have the file version (and possibly check to make sure all
279      * tags are properly opened and closed).
280      */
281     ret = wtap_file_read_pattern (wth, "<MediaType>", err, err_info);
282     if (ret == -1)
283         return -1;
284     if (ret == 0) {
285         *err = WTAP_ERR_BAD_FILE;
286         *err_info = g_strdup("peektagged: <MediaType> tag not found");
287         return -1;
288     }
289     /* XXX - this appears to be 0 in both the EtherPeek and AiroPeek
290        files we've seen; should we require it to be 0? */
291     ret = wtap_file_read_number (wth, &mediaType, err, err_info);
292     if (ret == -1)
293         return -1;
294     if (ret == 0) {
295         *err = WTAP_ERR_BAD_FILE;
296         *err_info = g_strdup("peektagged: <MediaType> value not found");
297         return -1;
298     }
299
300     ret = wtap_file_read_pattern (wth, "<MediaSubType>", err, err_info);
301     if (ret == -1)
302         return -1;
303     if (ret == 0) {
304         *err = WTAP_ERR_BAD_FILE;
305         *err_info = g_strdup("peektagged: <MediaSubType> tag not found");
306         return -1;
307     }
308     ret = wtap_file_read_number (wth, &mediaSubType, err, err_info);
309     if (ret == -1)
310         return -1;
311     if (ret == 0) {
312         *err = WTAP_ERR_BAD_FILE;
313         *err_info = g_strdup("peektagged: <MediaSubType> value not found");
314         return -1;
315     }
316     if (mediaSubType >= NUM_PEEKTAGGED_ENCAPS
317         || peektagged_encap[mediaSubType] == WTAP_ENCAP_UNKNOWN) {
318         *err = WTAP_ERR_UNSUPPORTED_ENCAP;
319         *err_info = g_strdup_printf("peektagged: network type %u unknown or unsupported",
320             mediaSubType);
321         return -1;
322     }
323
324     ret = wtap_file_read_pattern (wth, "pkts", err, err_info);
325     if (ret == -1)
326         return -1;
327     if (ret == 0) {
328         *err = WTAP_ERR_SHORT_READ;
329         return -1;
330     }
331
332     /* skip 8 zero bytes */
333     if (file_seek (wth->fh, 8L, SEEK_CUR, err) == -1)
334         return 0;
335
336     /*
337      * This is an Peek tagged file.
338      */
339     file_encap = peektagged_encap[mediaSubType];
340
341     wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_PEEKTAGGED;
342     wth->file_encap = file_encap;
343     wth->subtype_read = peektagged_read;
344     wth->subtype_seek_read = peektagged_seek_read;
345     wth->file_tsprec = WTAP_TSPREC_NSEC;
346
347     peektagged = (peektagged_t *)g_malloc(sizeof(peektagged_t));
348     wth->priv = (void *)peektagged;
349     switch (mediaSubType) {
350
351     case PEEKTAGGED_NST_ETHERNET:
352     case PEEKTAGGED_NST_802_11:
353     case PEEKTAGGED_NST_802_11_2:
354         peektagged->has_fcs = FALSE;
355         break;
356
357     case PEEKTAGGED_NST_802_11_WITH_FCS:
358         peektagged->has_fcs = TRUE;
359         break;
360     }
361
362     wth->snapshot_length   = 0; /* not available in header */
363
364     return 1;
365 }
366
367 typedef struct {
368     guint32 length;
369     guint32 sliceLength;
370     peektagged_utime timestamp;
371     struct ieee_802_11_phdr ieee_802_11;
372 } hdr_info_t;
373
374 /*
375  * Time stamps appear to be in nanoseconds since the Windows epoch
376  * as used in FILETIMEs, i.e. midnight, January 1, 1601.
377  *
378  * This magic number came from "nt_time_to_nstime()" in "packet-smb.c".
379  * 1970-1601 is 369; I'm not sure what the extra 3 days and 6 hours are
380  * that are being subtracted.
381  */
382 #define TIME_FIXUP_CONSTANT (369.0*365.25*24*60*60-(3.0*24*60*60+6.0*60*60))
383
384 /*
385  * Read the packet.
386  *
387  * XXX - we should supply the additional radio information;
388  * the pseudo-header should probably be supplied in a fashion
389  * similar to the radiotap radio header, so that the 802.11
390  * dissector can determine which, if any, information items
391  * are present.
392  */
393 static int
394 peektagged_read_packet(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr,
395                        Buffer *buf, int *err, gchar **err_info)
396 {
397     peektagged_t *peektagged = (peektagged_t *)wth->priv;
398     hdr_info_t hdr_info;
399     int header_len = 0;
400     guint8 tag_value[6];
401     guint16 tag;
402     gboolean saw_length = FALSE;
403     gboolean saw_timestamp_lower = FALSE;
404     gboolean saw_timestamp_upper = FALSE;
405     int skip_len = 0;
406     double  t;
407
408     memset(&hdr_info, 0, sizeof(hdr_info_t));
409
410     /* Extract the fields from the packet header */
411     do {
412         /* Get the tag and value.
413            XXX - this assumes all values are 4 bytes long. */
414         if (!wtap_read_bytes_or_eof(fh, tag_value, sizeof tag_value, err, err_info)) {
415             if (*err == 0) {
416                 /*
417                  * Short read if we've read something already;
418                  * just an EOF if we haven't.
419                  */
420                 if (header_len != 0)
421                     *err = WTAP_ERR_SHORT_READ;
422             }
423             return -1;
424         }
425         header_len += (int) sizeof(tag_value);
426         tag = pletoh16(&tag_value[0]);
427         switch (tag) {
428
429         case TAG_PEEKTAGGED_LENGTH:
430             if (saw_length) {
431                 *err = WTAP_ERR_BAD_FILE;
432                 *err_info = g_strdup("peektagged: record has two length fields");
433                 return -1;
434             }
435             hdr_info.length = pletoh32(&tag_value[2]);
436             saw_length = TRUE;
437             break;
438
439         case TAG_PEEKTAGGED_TIMESTAMP_LOWER:
440             if (saw_timestamp_lower) {
441                 *err = WTAP_ERR_BAD_FILE;
442                 *err_info = g_strdup("peektagged: record has two timestamp-lower fields");
443                 return -1;
444             }
445             hdr_info.timestamp.lower = pletoh32(&tag_value[2]);
446             saw_timestamp_lower = TRUE;
447             break;
448
449         case TAG_PEEKTAGGED_TIMESTAMP_UPPER:
450             if (saw_timestamp_upper) {
451                 *err = WTAP_ERR_BAD_FILE;
452                 *err_info = g_strdup("peektagged: record has two timestamp-upper fields");
453                 return -1;
454             }
455             hdr_info.timestamp.upper = pletoh32(&tag_value[2]);
456             saw_timestamp_upper = TRUE;
457             break;
458
459         case TAG_PEEKTAGGED_FLAGS_AND_STATUS:
460             /* XXX - not used yet */
461             break;
462
463         case TAG_PEEKTAGGED_CHANNEL:
464             hdr_info.ieee_802_11.channel = pletoh32(&tag_value[2]);
465             break;
466
467         case TAG_PEEKTAGGED_RATE:
468             hdr_info.ieee_802_11.data_rate = pletoh32(&tag_value[2]);
469             break;
470
471         case TAG_PEEKTAGGED_SIGNAL_PERC:
472             hdr_info.ieee_802_11.signal_level = pletoh32(&tag_value[2]);
473             break;
474
475         case TAG_PEEKTAGGED_SIGNAL_DBM:
476             /* XXX - not used yet */
477             break;
478
479         case TAG_PEEKTAGGED_NOISE_PERC:
480             /* XXX - not used yet */
481             break;
482
483         case TAG_PEEKTAGGED_NOISE_DBM:
484             /* XXX - not used yet */
485             break;
486
487         case TAG_PEEKTAGGED_UNKNOWN_0x000A:
488             /* XXX - seen in an OmniPeek 802.11n capture; value unknown */
489             break;
490
491         case TAG_PEEKTAGGED_UNKNOWN_0x000D:
492             /* XXX - seen in an EtherPeek capture; value unknown */
493             /* XXX - seen in an AiroPeek/OmniPeek capture; frequency? */
494             break;
495
496         case TAG_PEEKTAGGED_UNKNOWN_0x000E:
497             /* XXX - seen in an AiroPeek/OmniPeek capture; value unknown */
498             break;
499
500         case TAG_PEEKTAGGED_UNKNOWN_0x000F:
501             /* XXX - seen in an AiroPeek/OmniPeek capture; dBm value? */
502             break;
503
504         case TAG_PEEKTAGGED_UNKNOWN_0x0010:
505             /* XXX - seen in an AiroPeek/OmniPeek capture; dBm value? */
506             break;
507
508         case TAG_PEEKTAGGED_UNKNOWN_0x0011:
509             /* XXX - seen in an AiroPeek/OmniPeek capture; dBm value? */
510             break;
511
512         case TAG_PEEKTAGGED_UNKNOWN_0x0012:
513             /* XXX - seen in an AiroPeek/OmniPeek capture; dBm value? */
514             break;
515
516         case TAG_PEEKTAGGED_UNKNOWN_0x0013:
517             /* XXX - seen in an AiroPeek/OmniPeek capture; dBm value? */
518             break;
519
520         case TAG_PEEKTAGGED_UNKNOWN_0x0014:
521             /* XXX - seen in an AiroPeek/OmniPeek capture; value unknown */
522             break;
523
524         case TAG_PEEKTAGGED_UNKNOWN_0x0015:
525             /* XXX - seen in an AiroPeek/OmniPeek capture; value unknown */
526             break;
527
528         case TAG_PEEKTAGGED_SLICE_LENGTH:
529             hdr_info.sliceLength = pletoh32(&tag_value[2]);
530             break;
531
532         default:
533             break;
534         }
535     } while (tag != TAG_PEEKTAGGED_SLICE_LENGTH);       /* last tag */
536
537     if (!saw_length) {
538         *err = WTAP_ERR_BAD_FILE;
539         *err_info = g_strdup("peektagged: record has no length field");
540         return -1;
541     }
542     if (!saw_timestamp_lower) {
543         *err = WTAP_ERR_BAD_FILE;
544         *err_info = g_strdup("peektagged: record has no timestamp-lower field");
545         return -1;
546     }
547     if (!saw_timestamp_upper) {
548         *err = WTAP_ERR_BAD_FILE;
549         *err_info = g_strdup("peektagged: record has no timestamp-upper field");
550         return -1;
551     }
552
553     /*
554      * If sliceLength is 0, force it to be the actual length of the packet.
555      */
556     if (hdr_info.sliceLength == 0)
557         hdr_info.sliceLength = hdr_info.length;
558
559     if (hdr_info.sliceLength > WTAP_MAX_PACKET_SIZE) {
560         /*
561          * Probably a corrupt capture file; don't blow up trying
562          * to allocate space for an immensely-large packet.
563          */
564         *err = WTAP_ERR_BAD_FILE;
565         *err_info = g_strdup_printf("peektagged: File has %u-byte packet, bigger than maximum of %u",
566             hdr_info.sliceLength, WTAP_MAX_PACKET_SIZE);
567         return -1;
568     }
569
570     phdr->rec_type = REC_TYPE_PACKET;
571     phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
572     phdr->len    = hdr_info.length;
573     phdr->caplen = hdr_info.sliceLength;
574
575     /* calculate and fill in packet time stamp */
576     t =  (double) hdr_info.timestamp.lower +
577          (double) hdr_info.timestamp.upper * 4294967296.0;
578     t *= 1.0e-9;
579     t -= TIME_FIXUP_CONSTANT;
580     phdr->ts.secs  = (time_t) t;
581     phdr->ts.nsecs = (guint32) ((t - phdr->ts.secs)*1000000000);
582
583     switch (wth->file_encap) {
584
585     case WTAP_ENCAP_IEEE_802_11_WITH_RADIO:
586         phdr->pseudo_header.ieee_802_11 = hdr_info.ieee_802_11;
587         if (peektagged->has_fcs)
588             phdr->pseudo_header.ieee_802_11.fcs_len = 4;
589         else {
590             if (phdr->len < 4 || phdr->caplen < 4) {
591                 *err = WTAP_ERR_BAD_FILE;
592                 *err_info = g_strdup_printf("peektagged: 802.11 packet has length < 4");
593                 return FALSE;
594             }
595             phdr->pseudo_header.ieee_802_11.fcs_len = 0;
596             phdr->len -= 4;
597             phdr->caplen -= 4;
598             skip_len = 4;
599         }
600         phdr->pseudo_header.ieee_802_11.decrypted = FALSE;
601         break;
602
603     case WTAP_ENCAP_ETHERNET:
604         /*
605          * The last 4 bytes appear to be 0 in the captures I've seen;
606          * are there any captures where it's an FCS?
607          */
608         if (phdr->len < 4 || phdr->caplen < 4) {
609             *err = WTAP_ERR_BAD_FILE;
610             *err_info = g_strdup_printf("peektagged: Ethernet packet has length < 4");
611             return FALSE;
612         }
613         phdr->pseudo_header.eth.fcs_len = 0;
614         phdr->len -= 4;
615         phdr->caplen -= 4;
616         skip_len = 4;
617         break;
618     }
619
620     /* Read the packet data. */
621     if (!wtap_read_packet_bytes(fh, buf, phdr->caplen, err, err_info))
622         return -1;
623
624     return skip_len;
625 }
626
627 static gboolean peektagged_read(wtap *wth, int *err, gchar **err_info,
628     gint64 *data_offset)
629 {
630     int skip_len;
631
632     *data_offset = file_tell(wth->fh);
633
634     /* Read the packet. */
635     skip_len = peektagged_read_packet(wth, wth->fh, &wth->phdr,
636                                       wth->frame_buffer, err, err_info);
637     if (skip_len == -1)
638         return FALSE;
639
640     if (skip_len != 0) {
641         /* Skip extra junk at the end of the packet data. */
642         if (!file_skip(wth->fh, skip_len, err))
643             return FALSE;
644     }
645
646     return TRUE;
647 }
648
649 static gboolean
650 peektagged_seek_read(wtap *wth, gint64 seek_off,
651     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
652 {
653     if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
654         return FALSE;
655
656     /* Read the packet. */
657     if (peektagged_read_packet(wth, wth->random_fh, phdr, buf, err, err_info) == -1) {
658         if (*err == 0)
659             *err = WTAP_ERR_SHORT_READ;
660         return FALSE;
661     }
662     return TRUE;
663 }