Add a comment showing mapping to radiotap.
[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  /* upper 24 bits unused? */
97 #define TAG_PEEKTAGGED_CHANNEL                  0x0004
98 #define TAG_PEEKTAGGED_RATE                     0x0005  /* or MCS index for 802.11n */
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_CENTER_FREQUENCY         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_EXT_FLAGS                0x0015  /* Extended flags for 802.11n and beyond */
113
114 #define TAG_PEEKTAGGED_SLICE_LENGTH             0xffff
115
116 /*
117  * Flags.
118  *
119  * We're assuming here that the "remote Peek" flags from bug 9586 are
120  * the same as the "Peek tagged" flags.
121  */
122 #define FLAGS_CONTROL_FRAME     0x01    /* Frame is a control frame */
123 #define FLAGS_HAS_CRC_ERROR     0x02    /* Frame has a CRC error */
124 #define FLAGS_HAS_FRAME_ERROR   0x04    /* Frame has a frame error */
125
126 /*
127  * Status.
128  *
129  * Is this in the next 8 bits of the "flags and status" field?
130  */
131 #define STATUS_PROTECTED        0x0400  /* Frame is protected (encrypted) */
132 #define STATUS_DECRYPT_ERROR    0x0800  /* Error decrypting protected frame */
133 #define STATUS_SHORT_PREAMBLE   0x4000  /* Short preamble */
134
135 /*
136  * Extended flags.
137  *
138  * Some determined from bug 10637, some determined from bug 9586,
139  * and the ones present in both agree, so we're assuming that
140  * the "remote Peek" protocol and the "Peek tagged" file format
141  * use the same bits (which wouldn't be too surprising, as they
142  * both come from Wildpackets).
143  */
144 #define EXT_FLAG_20_MHZ_LOWER                   0x00000001
145 #define EXT_FLAG_20_MHZ_UPPER                   0x00000002
146 #define EXT_FLAG_40_MHZ                         0x00000004
147 #define EXT_FLAG_HALF_GI                        0x00000008
148 #define EXT_FLAG_FULL_GI                        0x00000010
149 #define EXT_FLAG_AMPDU                          0x00000020
150 #define EXT_FLAG_AMSDU                          0x00000040
151 #define EXT_FLAG_802_11ac                       0x00000080
152 #define EXT_FLAG_MCS_INDEX_USED                 0x00000100
153
154 /*
155  * XXX - mapping to radiotap, for fields that don't just map to wiretap
156  * fields:
157  *
158  * FLAGS_CONTROL_FRAME: no equivalent - is it useful?  Can just look at FC?
159  *
160  * FLAGS_HAS_CRC_ERROR: flags.{frame failed FCS check}
161  *
162  * FLAGS_HAS_FRAME_ERROR: no equivalent
163  *
164  * STATUS_PROTECTED: flags.{sent/received with WEP encryption}?
165  *
166  * STATUS_DECRYPT_ERROR: no equivalent
167  *
168  * STATUS_SHORT_PREAMBLE: flags.{sent/received with short preamble}
169  *
170  * TAG_PEEKTAGGED_CHANNEL: no equivalent, but could be mapped to Channel
171  *
172  * TAG_PEEKTAGGED_RATE: Rate if it's a data rate, MCS.mcs if it's an MCS
173  *   Does EXT_FLAG_MCS_INDEX_USED map to the "MCS known" bit ?
174  *
175  * TAG_PEEKTAGGED_SIGNAL_PERC: no equivalent
176  *
177  * TAG_PEEKTAGGED_SIGNAL_DBM: Antenna signal
178  *
179  * TAG_PEEKTAGGED_NOISE_PERC: no equivalent
180  *
181  * TAG_PEEKTAGGED_NOISE_DBM: Antenna noise
182  *
183  * TAG_PEEKTAGGED_CENTER_FREQUENCY: XChannel.freq
184  *
185  * TAG_PEEKTAGGED_UNKNOWN_0x000F - TAG_PEEKTAGGED_UNKNOWN_0x0013: no equivalent
186  *
187  * EXT_FLAG_20_MHZ_LOWER
188  * EXT_FLAG_20_MHZ_UPPER
189  * EXT_FLAG_40_MHZ:
190  *    mcs.bandwidth = 0: none of them set
191  *    mcs.bandwidth = 1: EXT_FLAG_40_MHZ set
192  *    mcs.bandwidth = 2: EXT_FLAG_20_MHZ_LOWER set
193  *    mcs.bandwidth = 3: EXT_FLAG_20_MHZ_UPPER set
194  *    anything else: ???
195  *
196  * EXT_FLAG_HALF_GI: mcs.{guard interval} = 1 (short GI)
197  *
198  * EXT_FLAG_FULL_GI: mcs.{guard interval} = 0 (long GI)
199  *
200  * EXT_FLAG_AMPDU: A-MPDU status present?  What about its value?
201  *
202  * EXT_FLAG_AMSDU: ???
203  *
204  * EXT_FLAG_802_11ac: nothing currently
205  *
206  * EXT_FLAG_MCS_INDEX_USED: see above?
207  */
208
209 /* 64-bit time in nanoseconds from the (Windows FILETIME) epoch */
210 typedef struct peektagged_utime {
211         guint32 upper;
212         guint32 lower;
213 } peektagged_utime;
214
215 typedef struct {
216         gboolean        has_fcs;
217 } peektagged_t;
218
219 static gboolean peektagged_read(wtap *wth, int *err, gchar **err_info,
220     gint64 *data_offset);
221 static gboolean peektagged_seek_read(wtap *wth, gint64 seek_off,
222     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
223
224 static int wtap_file_read_pattern (wtap *wth, const char *pattern, int *err,
225                                 gchar **err_info)
226 {
227     int c;
228     const char *cp;
229
230     cp = pattern;
231     while (*cp)
232     {
233         c = file_getc(wth->fh);
234         if (c == EOF)
235         {
236             *err = file_error(wth->fh, err_info);
237             if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
238                 return -1;      /* error */
239             return 0;   /* EOF */
240         }
241         if (c == *cp)
242             cp++;
243         else
244         {
245             if (c == pattern[0])
246                 cp = &pattern[1];
247             else
248                 cp = pattern;
249         }
250     }
251     return (*cp == '\0' ? 1 : 0);
252 }
253
254
255 static int wtap_file_read_till_separator (wtap *wth, char *buffer, int buflen,
256                                         const char *separators, int *err,
257                                         gchar **err_info)
258 {
259     int c;
260     char *cp;
261     int i;
262
263     for (cp = buffer, i = 0; i < buflen; i++, cp++)
264     {
265         c = file_getc(wth->fh);
266         if (c == EOF)
267         {
268             *err = file_error(wth->fh, err_info);
269             if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
270                 return -1;      /* error */
271             return 0;   /* EOF */
272         }
273         if (strchr (separators, c) != NULL)
274         {
275             *cp = '\0';
276             break;
277         }
278         else
279             *cp = c;
280     }
281     return i;
282 }
283
284
285 static int wtap_file_read_number (wtap *wth, guint32 *num, int *err,
286                                 gchar **err_info)
287 {
288     int ret;
289     char str_num[12];
290     unsigned long value;
291     char *p;
292
293     ret = wtap_file_read_till_separator (wth, str_num, sizeof (str_num)-1, "<",
294                                          err, err_info);
295     if (ret == 0 || ret == -1) {
296         /* 0 means EOF, which means "not a valid Peek tagged file";
297            -1 means error, and "err" has been set. */
298         return ret;
299     }
300     value = strtoul (str_num, &p, 10);
301     if (p == str_num || value > G_MAXUINT32)
302         return 0;
303     *num = (guint32)value;
304     return 1;
305 }
306
307
308 wtap_open_return_val peektagged_open(wtap *wth, int *err, gchar **err_info)
309 {
310     peektagged_section_header_t ap_hdr;
311     int ret;
312     guint32 fileVersion;
313     guint32 mediaType;
314     guint32 mediaSubType = 0;
315     int file_encap;
316     static const int peektagged_encap[] = {
317         WTAP_ENCAP_ETHERNET,
318         WTAP_ENCAP_IEEE_802_11_WITH_RADIO,
319         WTAP_ENCAP_IEEE_802_11_WITH_RADIO,
320         WTAP_ENCAP_IEEE_802_11_WITH_RADIO
321     };
322     #define NUM_PEEKTAGGED_ENCAPS (sizeof peektagged_encap / sizeof peektagged_encap[0])
323     peektagged_t *peektagged;
324
325     if (!wtap_read_bytes(wth->fh, &ap_hdr, (int)sizeof(ap_hdr), err, err_info)) {
326         if (*err != WTAP_ERR_SHORT_READ)
327             return WTAP_OPEN_ERROR;
328         return WTAP_OPEN_NOT_MINE;
329     }
330
331     if (memcmp (ap_hdr.section_id, "\177ver", sizeof(ap_hdr.section_id)) != 0)
332         return WTAP_OPEN_NOT_MINE;      /* doesn't begin with a "\177ver" section */
333
334     /*
335      * XXX - we should get the length of the "\177ver" section, check
336      * that it's followed by a little-endian 0x00000200, and then,
337      * when reading the XML, make sure we don't go past the end of
338      * that section, and skip to the end of that section when
339      * we have the file version (and possibly check to make sure all
340      * tags are properly opened and closed).
341      */
342     ret = wtap_file_read_pattern (wth, "<FileVersion>", err, err_info);
343     if (ret == -1)
344         return WTAP_OPEN_ERROR;
345     if (ret == 0) {
346         /* 0 means EOF, which means "not a valid Peek tagged file" */
347         return WTAP_OPEN_NOT_MINE;
348     }
349     ret = wtap_file_read_number (wth, &fileVersion, err, err_info);
350     if (ret == -1)
351         return WTAP_OPEN_ERROR;
352     if (ret == 0) {
353         /* 0 means EOF, which means "not a valid Peek tagged file" */
354         return WTAP_OPEN_NOT_MINE;
355     }
356
357     /* If we got this far, we assume it's a Peek tagged file. */
358     if (fileVersion != 9) {
359         /* We only support version 9. */
360         *err = WTAP_ERR_UNSUPPORTED;
361         *err_info = g_strdup_printf("peektagged: version %u unsupported",
362             fileVersion);
363         return WTAP_OPEN_ERROR;
364     }
365
366     /*
367      * XXX - once we've skipped the "\177ver" section, we should
368      * check for a "sess" section and fail if we don't see it.
369      * Then we should get the length of the "sess" section, check
370      * that it's followed by a little-endian 0x00000200, and then,
371      * when reading the XML, make sure we don't go past the end of
372      * that section, and skip to the end of the section when
373      * we have the file version (and possibly check to make sure all
374      * tags are properly opened and closed).
375      */
376     ret = wtap_file_read_pattern (wth, "<MediaType>", err, err_info);
377     if (ret == -1)
378         return WTAP_OPEN_ERROR;
379     if (ret == 0) {
380         *err = WTAP_ERR_BAD_FILE;
381         *err_info = g_strdup("peektagged: <MediaType> tag not found");
382         return WTAP_OPEN_ERROR;
383     }
384     /* XXX - this appears to be 0 in both the EtherPeek and AiroPeek
385        files we've seen; should we require it to be 0? */
386     ret = wtap_file_read_number (wth, &mediaType, err, err_info);
387     if (ret == -1)
388         return WTAP_OPEN_ERROR;
389     if (ret == 0) {
390         *err = WTAP_ERR_BAD_FILE;
391         *err_info = g_strdup("peektagged: <MediaType> value not found");
392         return WTAP_OPEN_ERROR;
393     }
394
395     ret = wtap_file_read_pattern (wth, "<MediaSubType>", err, err_info);
396     if (ret == -1)
397         return WTAP_OPEN_ERROR;
398     if (ret == 0) {
399         *err = WTAP_ERR_BAD_FILE;
400         *err_info = g_strdup("peektagged: <MediaSubType> tag not found");
401         return WTAP_OPEN_ERROR;
402     }
403     ret = wtap_file_read_number (wth, &mediaSubType, err, err_info);
404     if (ret == -1)
405         return WTAP_OPEN_ERROR;
406     if (ret == 0) {
407         *err = WTAP_ERR_BAD_FILE;
408         *err_info = g_strdup("peektagged: <MediaSubType> value not found");
409         return WTAP_OPEN_ERROR;
410     }
411     if (mediaSubType >= NUM_PEEKTAGGED_ENCAPS
412         || peektagged_encap[mediaSubType] == WTAP_ENCAP_UNKNOWN) {
413         *err = WTAP_ERR_UNSUPPORTED_ENCAP;
414         *err_info = g_strdup_printf("peektagged: network type %u unknown or unsupported",
415             mediaSubType);
416         return WTAP_OPEN_ERROR;
417     }
418
419     ret = wtap_file_read_pattern (wth, "pkts", err, err_info);
420     if (ret == -1)
421         return WTAP_OPEN_ERROR;
422     if (ret == 0) {
423         *err = WTAP_ERR_SHORT_READ;
424         return WTAP_OPEN_ERROR;
425     }
426
427     /* skip 8 zero bytes */
428     if (file_seek (wth->fh, 8L, SEEK_CUR, err) == -1)
429         return WTAP_OPEN_NOT_MINE;
430
431     /*
432      * This is an Peek tagged file.
433      */
434     file_encap = peektagged_encap[mediaSubType];
435
436     wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_PEEKTAGGED;
437     wth->file_encap = file_encap;
438     wth->subtype_read = peektagged_read;
439     wth->subtype_seek_read = peektagged_seek_read;
440     wth->file_tsprec = WTAP_TSPREC_NSEC;
441
442     peektagged = (peektagged_t *)g_malloc(sizeof(peektagged_t));
443     wth->priv = (void *)peektagged;
444     switch (mediaSubType) {
445
446     case PEEKTAGGED_NST_ETHERNET:
447     case PEEKTAGGED_NST_802_11:
448     case PEEKTAGGED_NST_802_11_2:
449         peektagged->has_fcs = FALSE;
450         break;
451
452     case PEEKTAGGED_NST_802_11_WITH_FCS:
453         peektagged->has_fcs = TRUE;
454         break;
455     }
456
457     wth->snapshot_length   = 0; /* not available in header */
458
459     return WTAP_OPEN_MINE;
460 }
461
462 typedef struct {
463     guint32 length;
464     guint32 sliceLength;
465     peektagged_utime timestamp;
466     struct ieee_802_11_phdr ieee_802_11;
467 } hdr_info_t;
468
469 /*
470  * Time stamps appear to be in nanoseconds since the Windows epoch
471  * as used in FILETIMEs, i.e. midnight, January 1, 1601.
472  *
473  * This magic number came from "nt_time_to_nstime()" in "packet-smb.c".
474  * 1970-1601 is 369; I'm not sure what the extra 3 days and 6 hours are
475  * that are being subtracted.
476  */
477 #define TIME_FIXUP_CONSTANT (369.0*365.25*24*60*60-(3.0*24*60*60+6.0*60*60))
478
479 /*
480  * Read the packet.
481  *
482  * XXX - we should supply the additional radio information;
483  * the pseudo-header should probably be supplied in a fashion
484  * similar to the radiotap radio header, so that the 802.11
485  * dissector can determine which, if any, information items
486  * are present.
487  */
488 static int
489 peektagged_read_packet(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr,
490                        Buffer *buf, int *err, gchar **err_info)
491 {
492     peektagged_t *peektagged = (peektagged_t *)wth->priv;
493     hdr_info_t hdr_info;
494     int header_len = 0;
495     guint8 tag_value[6];
496     guint16 tag;
497     gboolean saw_length = FALSE;
498     gboolean saw_timestamp_lower = FALSE;
499     gboolean saw_timestamp_upper = FALSE;
500     int skip_len = 0;
501     double  t;
502
503     memset(&hdr_info, 0, sizeof(hdr_info_t));
504
505     /* Extract the fields from the packet header */
506     do {
507         /* Get the tag and value.
508            XXX - this assumes all values are 4 bytes long. */
509         if (!wtap_read_bytes_or_eof(fh, tag_value, sizeof tag_value, err, err_info)) {
510             if (*err == 0) {
511                 /*
512                  * Short read if we've read something already;
513                  * just an EOF if we haven't.
514                  */
515                 if (header_len != 0)
516                     *err = WTAP_ERR_SHORT_READ;
517             }
518             return -1;
519         }
520         header_len += (int) sizeof(tag_value);
521         tag = pletoh16(&tag_value[0]);
522         switch (tag) {
523
524         case TAG_PEEKTAGGED_LENGTH:
525             if (saw_length) {
526                 *err = WTAP_ERR_BAD_FILE;
527                 *err_info = g_strdup("peektagged: record has two length fields");
528                 return -1;
529             }
530             hdr_info.length = pletoh32(&tag_value[2]);
531             saw_length = TRUE;
532             break;
533
534         case TAG_PEEKTAGGED_TIMESTAMP_LOWER:
535             if (saw_timestamp_lower) {
536                 *err = WTAP_ERR_BAD_FILE;
537                 *err_info = g_strdup("peektagged: record has two timestamp-lower fields");
538                 return -1;
539             }
540             hdr_info.timestamp.lower = pletoh32(&tag_value[2]);
541             saw_timestamp_lower = TRUE;
542             break;
543
544         case TAG_PEEKTAGGED_TIMESTAMP_UPPER:
545             if (saw_timestamp_upper) {
546                 *err = WTAP_ERR_BAD_FILE;
547                 *err_info = g_strdup("peektagged: record has two timestamp-upper fields");
548                 return -1;
549             }
550             hdr_info.timestamp.upper = pletoh32(&tag_value[2]);
551             saw_timestamp_upper = TRUE;
552             break;
553
554         case TAG_PEEKTAGGED_FLAGS_AND_STATUS:
555             /* XXX - not used yet */
556             break;
557
558         case TAG_PEEKTAGGED_CHANNEL:
559             hdr_info.ieee_802_11.channel = pletoh32(&tag_value[2]);
560             break;
561
562         case TAG_PEEKTAGGED_RATE:
563             hdr_info.ieee_802_11.data_rate = pletoh32(&tag_value[2]);
564             break;
565
566         case TAG_PEEKTAGGED_SIGNAL_PERC:
567             hdr_info.ieee_802_11.signal_level = pletoh32(&tag_value[2]);
568             break;
569
570         case TAG_PEEKTAGGED_SIGNAL_DBM:
571             /* XXX - not used yet */
572             break;
573
574         case TAG_PEEKTAGGED_NOISE_PERC:
575             /* XXX - not used yet */
576             break;
577
578         case TAG_PEEKTAGGED_NOISE_DBM:
579             /* XXX - not used yet */
580             break;
581
582         case TAG_PEEKTAGGED_UNKNOWN_0x000A:
583             /* XXX - seen in an OmniPeek 802.11n capture; value unknown */
584             break;
585
586         case TAG_PEEKTAGGED_CENTER_FREQUENCY:
587             /* XXX - also seen in an EtherPeek capture; value unknown */
588             break;
589
590         case TAG_PEEKTAGGED_UNKNOWN_0x000E:
591             /* XXX - seen in an AiroPeek/OmniPeek capture; value unknown */
592             break;
593
594         case TAG_PEEKTAGGED_UNKNOWN_0x000F:
595             /* XXX - seen in an AiroPeek/OmniPeek capture; dBm value? */
596             break;
597
598         case TAG_PEEKTAGGED_UNKNOWN_0x0010:
599             /* XXX - seen in an AiroPeek/OmniPeek capture; dBm value? */
600             break;
601
602         case TAG_PEEKTAGGED_UNKNOWN_0x0011:
603             /* XXX - seen in an AiroPeek/OmniPeek capture; dBm value? */
604             break;
605
606         case TAG_PEEKTAGGED_UNKNOWN_0x0012:
607             /* XXX - seen in an AiroPeek/OmniPeek capture; dBm value? */
608             break;
609
610         case TAG_PEEKTAGGED_UNKNOWN_0x0013:
611             /* XXX - seen in an AiroPeek/OmniPeek capture; dBm value? */
612             break;
613
614         case TAG_PEEKTAGGED_UNKNOWN_0x0014:
615             /* XXX - seen in an AiroPeek/OmniPeek capture; value unknown */
616             break;
617
618         case TAG_PEEKTAGGED_EXT_FLAGS:
619             break;
620
621         case TAG_PEEKTAGGED_SLICE_LENGTH:
622             hdr_info.sliceLength = pletoh32(&tag_value[2]);
623             break;
624
625         default:
626             break;
627         }
628     } while (tag != TAG_PEEKTAGGED_SLICE_LENGTH);       /* last tag */
629
630     if (!saw_length) {
631         *err = WTAP_ERR_BAD_FILE;
632         *err_info = g_strdup("peektagged: record has no length field");
633         return -1;
634     }
635     if (!saw_timestamp_lower) {
636         *err = WTAP_ERR_BAD_FILE;
637         *err_info = g_strdup("peektagged: record has no timestamp-lower field");
638         return -1;
639     }
640     if (!saw_timestamp_upper) {
641         *err = WTAP_ERR_BAD_FILE;
642         *err_info = g_strdup("peektagged: record has no timestamp-upper field");
643         return -1;
644     }
645
646     /*
647      * If sliceLength is 0, force it to be the actual length of the packet.
648      */
649     if (hdr_info.sliceLength == 0)
650         hdr_info.sliceLength = hdr_info.length;
651
652     if (hdr_info.sliceLength > WTAP_MAX_PACKET_SIZE) {
653         /*
654          * Probably a corrupt capture file; don't blow up trying
655          * to allocate space for an immensely-large packet.
656          */
657         *err = WTAP_ERR_BAD_FILE;
658         *err_info = g_strdup_printf("peektagged: File has %u-byte packet, bigger than maximum of %u",
659             hdr_info.sliceLength, WTAP_MAX_PACKET_SIZE);
660         return -1;
661     }
662
663     phdr->rec_type = REC_TYPE_PACKET;
664     phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
665     phdr->len    = hdr_info.length;
666     phdr->caplen = hdr_info.sliceLength;
667
668     /* calculate and fill in packet time stamp */
669     t =  (double) hdr_info.timestamp.lower +
670          (double) hdr_info.timestamp.upper * 4294967296.0;
671     t *= 1.0e-9;
672     t -= TIME_FIXUP_CONSTANT;
673     phdr->ts.secs  = (time_t) t;
674     phdr->ts.nsecs = (guint32) ((t - phdr->ts.secs)*1000000000);
675
676     switch (wth->file_encap) {
677
678     case WTAP_ENCAP_IEEE_802_11_WITH_RADIO:
679         phdr->pseudo_header.ieee_802_11 = hdr_info.ieee_802_11;
680         if (peektagged->has_fcs)
681             phdr->pseudo_header.ieee_802_11.fcs_len = 4;
682         else {
683             if (phdr->len < 4 || phdr->caplen < 4) {
684                 *err = WTAP_ERR_BAD_FILE;
685                 *err_info = g_strdup_printf("peektagged: 802.11 packet has length < 4");
686                 return FALSE;
687             }
688             phdr->pseudo_header.ieee_802_11.fcs_len = 0;
689             phdr->len -= 4;
690             phdr->caplen -= 4;
691             skip_len = 4;
692         }
693         phdr->pseudo_header.ieee_802_11.decrypted = FALSE;
694         break;
695
696     case WTAP_ENCAP_ETHERNET:
697         /*
698          * The last 4 bytes appear to be 0 in the captures I've seen;
699          * are there any captures where it's an FCS?
700          */
701         if (phdr->len < 4 || phdr->caplen < 4) {
702             *err = WTAP_ERR_BAD_FILE;
703             *err_info = g_strdup_printf("peektagged: Ethernet packet has length < 4");
704             return FALSE;
705         }
706         phdr->pseudo_header.eth.fcs_len = 0;
707         phdr->len -= 4;
708         phdr->caplen -= 4;
709         skip_len = 4;
710         break;
711     }
712
713     /* Read the packet data. */
714     if (!wtap_read_packet_bytes(fh, buf, phdr->caplen, err, err_info))
715         return -1;
716
717     return skip_len;
718 }
719
720 static gboolean peektagged_read(wtap *wth, int *err, gchar **err_info,
721     gint64 *data_offset)
722 {
723     int skip_len;
724
725     *data_offset = file_tell(wth->fh);
726
727     /* Read the packet. */
728     skip_len = peektagged_read_packet(wth, wth->fh, &wth->phdr,
729                                       wth->frame_buffer, err, err_info);
730     if (skip_len == -1)
731         return FALSE;
732
733     if (skip_len != 0) {
734         /* Skip extra junk at the end of the packet data. */
735         if (!file_skip(wth->fh, skip_len, err))
736             return FALSE;
737     }
738
739     return TRUE;
740 }
741
742 static gboolean
743 peektagged_seek_read(wtap *wth, gint64 seek_off,
744     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
745 {
746     if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
747         return FALSE;
748
749     /* Read the packet. */
750     if (peektagged_read_packet(wth, wth->random_fh, phdr, buf, err, err_info) == -1) {
751         if (*err == 0)
752             *err = WTAP_ERR_SHORT_READ;
753         return FALSE;
754     }
755     return TRUE;
756 }