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).
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
18 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
20 * This program is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU General Public License
22 * as published by the Free Software Foundation; either version 2
23 * of the License, or (at your option) any later version.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
40 #include "file_wrappers.h"
42 #include "peektagged.h"
46 * This file decoder could not have been writen without examining
47 * http://www.varsanofiev.com/inside/airopeekv9.htm, the help from
48 * Martin Regner and Guy Harris, and the etherpeek.c file (as it
49 * was called before renaming it to peekclassic.c).
55 * A Peek tagged file consists of multiple sections, each of which begins
56 * with a header in the following format.
58 * The section ID is a 4-character string saying what type of section
59 * it is. The section length is a little-endian field giving the
60 * length of the section, in bytes, including the section header
61 * itself. The other field of the section header is a little-endian
62 * constant that always appears to be 0x00000200.
64 * Files we've seen have the following sections, in order:
66 * "\177vers" - version information. The contents are XML, giving
67 * the file format version and application version information.
69 * "sess" - capture session information. The contents are XML, giving
70 * various information about the capture session.
72 * "pkts" - captured packets. The contents are binary records, one for
73 * each packet, with the record being a list of tagged values followed
74 * by the raw packet data.
76 typedef struct peektagged_section_header
{
77 gint8 section_id
[4]; /* string identifying the section */
78 guint32 section_len
; /* little-endian section length */
79 guint32 section_const
; /* little-endian 0x00000200 */
80 } peektagged_section_header_t
;
83 * Network subtype values.
85 * XXX - do different network subtype values for 802.11 indicate different
86 * network adapter types, with some adapters supplying the FCS and others
87 * not supplying the FCS?
89 #define PEEKTAGGED_NST_ETHERNET 0
90 #define PEEKTAGGED_NST_802_11 1 /* 802.11 with 0's at the end */
91 #define PEEKTAGGED_NST_802_11_2 2 /* 802.11 with 0's at the end */
92 #define PEEKTAGGED_NST_802_11_WITH_FCS 3 /* 802.11 with FCS at the end */
94 /* tags for fields in packet header */
95 #define TAG_PEEKTAGGED_LENGTH 0x0000
96 #define TAG_PEEKTAGGED_TIMESTAMP_LOWER 0x0001
97 #define TAG_PEEKTAGGED_TIMESTAMP_UPPER 0x0002
98 #define TAG_PEEKTAGGED_FLAGS_AND_STATUS 0x0003
99 #define TAG_PEEKTAGGED_CHANNEL 0x0004
100 #define TAG_PEEKTAGGED_RATE 0x0005
101 #define TAG_PEEKTAGGED_SIGNAL_PERC 0x0006
102 #define TAG_PEEKTAGGED_SIGNAL_DBM 0x0007
103 #define TAG_PEEKTAGGED_NOISE_PERC 0x0008
104 #define TAG_PEEKTAGGED_NOISE_DBM 0x0009
105 #define TAG_PEEKTAGGED_UNKNOWN_0x000D 0x000D
106 #define TAG_PEEKTAGGED_SLICE_LENGTH 0xffff
108 /* 64-bit time in nanoseconds from the (Windows FILETIME) epoch */
109 typedef struct peektagged_utime
{
118 static gboolean
peektagged_read(wtap
*wth
, int *err
, gchar
**err_info
,
119 gint64
*data_offset
);
120 static gboolean
peektagged_seek_read(wtap
*wth
, gint64 seek_off
,
121 struct wtap_pkthdr
*phdr
, Buffer
*buf
, int length
,
122 int *err
, gchar
**err_info
);
124 static int wtap_file_read_pattern (wtap
*wth
, const char *pattern
, int *err
,
133 c
= file_getc(wth
->fh
);
136 *err
= file_error(wth
->fh
, err_info
);
137 if (*err
!= 0 && *err
!= WTAP_ERR_SHORT_READ
)
138 return -1; /* error */
151 return (*cp
== '\0' ? 1 : 0);
155 static int wtap_file_read_till_separator (wtap
*wth
, char *buffer
, int buflen
,
156 const char *separators
, int *err
,
163 for (cp
= buffer
, i
= 0; i
< buflen
; i
++, cp
++)
165 c
= file_getc(wth
->fh
);
168 *err
= file_error(wth
->fh
, err_info
);
169 if (*err
!= 0 && *err
!= WTAP_ERR_SHORT_READ
)
170 return -1; /* error */
173 if (strchr (separators
, c
) != NULL
)
185 static int wtap_file_read_number (wtap
*wth
, guint32
*num
, int *err
,
193 ret
= wtap_file_read_till_separator (wth
, str_num
, sizeof (str_num
)-1, "<",
196 /* 0 means EOF, which means "not a valid Peek tagged file";
197 -1 means error, and "err" has been set. */
200 value
= strtoul (str_num
, &p
, 10);
201 if (p
== str_num
|| value
> G_MAXUINT32
)
203 *num
= (guint32
)value
;
208 int peektagged_open(wtap
*wth
, int *err
, gchar
**err_info
)
210 peektagged_section_header_t ap_hdr
;
215 guint32 mediaSubType
= 0;
217 static const int peektagged_encap
[] = {
219 WTAP_ENCAP_IEEE_802_11_WITH_RADIO
,
220 WTAP_ENCAP_IEEE_802_11_WITH_RADIO
,
221 WTAP_ENCAP_IEEE_802_11_WITH_RADIO
223 #define NUM_PEEKTAGGED_ENCAPS (sizeof peektagged_encap / sizeof peektagged_encap[0])
224 peektagged_t
*peektagged
;
226 bytes_read
= file_read(&ap_hdr
, (int)sizeof(ap_hdr
), wth
->fh
);
227 if (bytes_read
!= (int)sizeof(ap_hdr
)) {
228 *err
= file_error(wth
->fh
, err_info
);
229 if (*err
!= 0 && *err
!= WTAP_ERR_SHORT_READ
)
234 if (memcmp (ap_hdr
.section_id
, "\177ver", sizeof(ap_hdr
.section_id
)) != 0)
235 return 0; /* doesn't begin with a "\177ver" section */
238 * XXX - we should get the length of the "\177ver" section, check
239 * that it's followed by a little-endian 0x00000200, and then,
240 * when reading the XML, make sure we don't go past the end of
241 * that section, and skip to the end of that section when
242 * we have the file version (and possibly check to make sure all
243 * tags are properly opened and closed).
245 ret
= wtap_file_read_pattern (wth
, "<FileVersion>", err
, err_info
);
247 /* 0 means EOF, which means "not a valid Peek tagged file";
248 -1 means error, and "err" has been set. */
251 ret
= wtap_file_read_number (wth
, &fileVersion
, err
, err_info
);
253 /* 0 means EOF, which means "not a valid Peek tagged file";
254 -1 means error, and "err" has been set. */
258 /* If we got this far, we assume it's a Peek tagged file. */
259 if (fileVersion
!= 9) {
260 /* We only support version 9. */
261 *err
= WTAP_ERR_UNSUPPORTED
;
262 *err_info
= g_strdup_printf("peektagged: version %u unsupported",
268 * XXX - once we've skipped the "\177ver" section, we should
269 * check for a "sess" section and fail if we don't see it.
270 * Then we should get the length of the "sess" section, check
271 * that it's followed by a little-endian 0x00000200, and then,
272 * when reading the XML, make sure we don't go past the end of
273 * that section, and skip to the end of the section when
274 * we have the file version (and possibly check to make sure all
275 * tags are properly opened and closed).
277 ret
= wtap_file_read_pattern (wth
, "<MediaType>", err
, err_info
);
281 *err
= WTAP_ERR_BAD_FILE
;
282 *err_info
= g_strdup("peektagged: <MediaType> tag not found");
285 /* XXX - this appears to be 0 in both the EtherPeek and AiroPeek
286 files we've seen; should we require it to be 0? */
287 ret
= wtap_file_read_number (wth
, &mediaType
, err
, err_info
);
291 *err
= WTAP_ERR_BAD_FILE
;
292 *err_info
= g_strdup("peektagged: <MediaType> value not found");
296 ret
= wtap_file_read_pattern (wth
, "<MediaSubType>", err
, err_info
);
300 *err
= WTAP_ERR_BAD_FILE
;
301 *err_info
= g_strdup("peektagged: <MediaSubType> tag not found");
304 ret
= wtap_file_read_number (wth
, &mediaSubType
, err
, err_info
);
308 *err
= WTAP_ERR_BAD_FILE
;
309 *err_info
= g_strdup("peektagged: <MediaSubType> value not found");
312 if (mediaSubType
>= NUM_PEEKTAGGED_ENCAPS
313 || peektagged_encap
[mediaSubType
] == WTAP_ENCAP_UNKNOWN
) {
314 *err
= WTAP_ERR_UNSUPPORTED_ENCAP
;
315 *err_info
= g_strdup_printf("peektagged: network type %u unknown or unsupported",
320 ret
= wtap_file_read_pattern (wth
, "pkts", err
, err_info
);
324 *err
= WTAP_ERR_SHORT_READ
;
328 /* skip 8 zero bytes */
329 if (file_seek (wth
->fh
, 8L, SEEK_CUR
, err
) == -1)
333 * This is an Peek tagged file.
335 file_encap
= peektagged_encap
[mediaSubType
];
337 wth
->file_type_subtype
= WTAP_FILE_TYPE_SUBTYPE_PEEKTAGGED
;
338 wth
->file_encap
= file_encap
;
339 wth
->subtype_read
= peektagged_read
;
340 wth
->subtype_seek_read
= peektagged_seek_read
;
341 wth
->tsprecision
= WTAP_FILE_TSPREC_NSEC
;
343 peektagged
= (peektagged_t
*)g_malloc(sizeof(peektagged_t
));
344 wth
->priv
= (void *)peektagged
;
345 switch (mediaSubType
) {
347 case PEEKTAGGED_NST_ETHERNET
:
348 case PEEKTAGGED_NST_802_11
:
349 case PEEKTAGGED_NST_802_11_2
:
350 peektagged
->has_fcs
= FALSE
;
353 case PEEKTAGGED_NST_802_11_WITH_FCS
:
354 peektagged
->has_fcs
= TRUE
;
358 wth
->snapshot_length
= 0; /* not available in header */
366 peektagged_utime timestamp
;
367 struct ieee_802_11_phdr ieee_802_11
;
371 * Time stamps appear to be in nanoseconds since the Windows epoch
372 * as used in FILETIMEs, i.e. midnight, January 1, 1601.
374 * This magic number came from "nt_time_to_nstime()" in "packet-smb.c".
375 * 1970-1601 is 369; I'm not sure what the extra 3 days and 6 hours are
376 * that are being subtracted.
378 #define TIME_FIXUP_CONSTANT (369.0*365.25*24*60*60-(3.0*24*60*60+6.0*60*60))
383 * XXX - we should supply the additional radio information;
384 * the pseudo-header should probably be supplied in a fashion
385 * similar to the radiotap radio header, so that the 802.11
386 * dissector can determine which, if any, information items
390 peektagged_read_packet(wtap
*wth
, FILE_T fh
, struct wtap_pkthdr
*phdr
,
391 Buffer
*buf
, int *err
, gchar
**err_info
)
393 peektagged_t
*peektagged
= (peektagged_t
*)wth
->priv
;
399 gboolean saw_length
= FALSE
;
400 gboolean saw_timestamp_lower
= FALSE
;
401 gboolean saw_timestamp_upper
= FALSE
;
405 memset(&hdr_info
, 0, sizeof(hdr_info_t
));
407 /* Extract the fields from the packet header */
409 /* Get the tag and value.
410 XXX - this assumes all values are 4 bytes long. */
411 bytes_read
= file_read(tag_value
, sizeof tag_value
, fh
);
412 if (bytes_read
!= (int) sizeof tag_value
) {
413 *err
= file_error(fh
, err_info
);
416 *err
= WTAP_ERR_SHORT_READ
;
417 else if (bytes_read
== 0) {
419 * Short read if we've read something already;
420 * just an EOF if we haven't.
423 *err
= WTAP_ERR_SHORT_READ
;
428 header_len
+= (int) sizeof(tag_value
);
429 tag
= pletohs(&tag_value
[0]);
432 case TAG_PEEKTAGGED_LENGTH
:
434 *err
= WTAP_ERR_BAD_FILE
;
435 *err_info
= g_strdup("peektagged: record has two length fields");
438 hdr_info
.length
= pletohl(&tag_value
[2]);
442 case TAG_PEEKTAGGED_TIMESTAMP_LOWER
:
443 if (saw_timestamp_lower
) {
444 *err
= WTAP_ERR_BAD_FILE
;
445 *err_info
= g_strdup("peektagged: record has two timestamp-lower fields");
448 hdr_info
.timestamp
.lower
= pletohl(&tag_value
[2]);
449 saw_timestamp_lower
= TRUE
;
452 case TAG_PEEKTAGGED_TIMESTAMP_UPPER
:
453 if (saw_timestamp_upper
) {
454 *err
= WTAP_ERR_BAD_FILE
;
455 *err_info
= g_strdup("peektagged: record has two timestamp-upper fields");
458 hdr_info
.timestamp
.upper
= pletohl(&tag_value
[2]);
459 saw_timestamp_upper
= TRUE
;
462 case TAG_PEEKTAGGED_FLAGS_AND_STATUS
:
463 /* XXX - not used yet */
466 case TAG_PEEKTAGGED_CHANNEL
:
467 hdr_info
.ieee_802_11
.channel
= pletohl(&tag_value
[2]);
470 case TAG_PEEKTAGGED_RATE
:
471 hdr_info
.ieee_802_11
.data_rate
= pletohl(&tag_value
[2]);
474 case TAG_PEEKTAGGED_SIGNAL_PERC
:
475 hdr_info
.ieee_802_11
.signal_level
= pletohl(&tag_value
[2]);
478 case TAG_PEEKTAGGED_SIGNAL_DBM
:
479 /* XXX - not used yet */
482 case TAG_PEEKTAGGED_NOISE_PERC
:
483 /* XXX - not used yet */
486 case TAG_PEEKTAGGED_NOISE_DBM
:
487 /* XXX - not used yet */
490 case TAG_PEEKTAGGED_UNKNOWN_0x000D
:
491 /* XXX - seen in an EtherPeek capture; value unknown */
494 case TAG_PEEKTAGGED_SLICE_LENGTH
:
495 hdr_info
.sliceLength
= pletohl(&tag_value
[2]);
501 } while (tag
!= TAG_PEEKTAGGED_SLICE_LENGTH
); /* last tag */
504 *err
= WTAP_ERR_BAD_FILE
;
505 *err_info
= g_strdup("peektagged: record has no length field");
508 if (!saw_timestamp_lower
) {
509 *err
= WTAP_ERR_BAD_FILE
;
510 *err_info
= g_strdup("peektagged: record has no timestamp-lower field");
513 if (!saw_timestamp_upper
) {
514 *err
= WTAP_ERR_BAD_FILE
;
515 *err_info
= g_strdup("peektagged: record has no timestamp-upper field");
520 * If sliceLength is 0, force it to be the actual length of the packet.
522 if (hdr_info
.sliceLength
== 0)
523 hdr_info
.sliceLength
= hdr_info
.length
;
525 if (hdr_info
.sliceLength
> WTAP_MAX_PACKET_SIZE
) {
527 * Probably a corrupt capture file; don't blow up trying
528 * to allocate space for an immensely-large packet.
530 *err
= WTAP_ERR_BAD_FILE
;
531 *err_info
= g_strdup_printf("peektagged: File has %u-byte packet, bigger than maximum of %u",
532 hdr_info
.sliceLength
, WTAP_MAX_PACKET_SIZE
);
536 phdr
->presence_flags
= WTAP_HAS_TS
|WTAP_HAS_CAP_LEN
;
537 phdr
->len
= hdr_info
.length
;
538 phdr
->caplen
= hdr_info
.sliceLength
;
540 /* calculate and fill in packet time stamp */
541 t
= (double) hdr_info
.timestamp
.lower
+
542 (double) hdr_info
.timestamp
.upper
* 4294967296.0;
544 t
-= TIME_FIXUP_CONSTANT
;
545 phdr
->ts
.secs
= (time_t) t
;
546 phdr
->ts
.nsecs
= (guint32
) ((t
- phdr
->ts
.secs
)*1000000000);
548 switch (wth
->file_encap
) {
550 case WTAP_ENCAP_IEEE_802_11_WITH_RADIO
:
551 phdr
->pseudo_header
.ieee_802_11
= hdr_info
.ieee_802_11
;
552 if (peektagged
->has_fcs
)
553 phdr
->pseudo_header
.ieee_802_11
.fcs_len
= 4;
555 if (phdr
->len
< 4 || phdr
->caplen
< 4) {
556 *err
= WTAP_ERR_BAD_FILE
;
557 *err_info
= g_strdup_printf("peektagged: 802.11 packet has length < 4");
560 phdr
->pseudo_header
.ieee_802_11
.fcs_len
= 0;
565 phdr
->pseudo_header
.ieee_802_11
.decrypted
= FALSE
;
568 case WTAP_ENCAP_ETHERNET
:
570 * The last 4 bytes appear to be 0 in the captures I've seen;
571 * are there any captures where it's an FCS?
573 if (phdr
->len
< 4 || phdr
->caplen
< 4) {
574 *err
= WTAP_ERR_BAD_FILE
;
575 *err_info
= g_strdup_printf("peektagged: Ethernet packet has length < 4");
578 phdr
->pseudo_header
.eth
.fcs_len
= 0;
585 /* Read the packet data. */
586 if (!wtap_read_packet_bytes(fh
, buf
, phdr
->caplen
, err
, err_info
))
592 static gboolean
peektagged_read(wtap
*wth
, int *err
, gchar
**err_info
,
597 *data_offset
= file_tell(wth
->fh
);
599 /* Read the packet. */
600 skip_len
= peektagged_read_packet(wth
, wth
->fh
, &wth
->phdr
,
601 wth
->frame_buffer
, err
, err_info
);
606 /* Skip extra junk at the end of the packet data. */
607 if (!file_skip(wth
->fh
, skip_len
, err
))
615 peektagged_seek_read(wtap
*wth
, gint64 seek_off
,
616 struct wtap_pkthdr
*phdr
, Buffer
*buf
, int length _U_
,
617 int *err
, gchar
**err_info
)
619 if (file_seek(wth
->random_fh
, seek_off
, SEEK_SET
, err
) == -1)
622 /* Read the packet. */
623 if (peektagged_read_packet(wth
, wth
->random_fh
, phdr
, buf
, err
, err_info
) == -1) {
625 *err
= WTAP_ERR_SHORT_READ
;