/* airopeek9.c
* Routines for opening EtherPeek and AiroPeek V9 files
*
- * $Id: airopeek9.c,v 1.7 2004/02/06 03:12:21 guy Exp $
+ * $Id$
*
* Wiretap Library
* Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
guint32 section_const;
} airopeek_section_header_t;
+/* network subtype values */
+#define AIROPEEK_V9_NST_ETHERNET 0
+#define AIROPEEK_V9_NST_802_11 1 /* 802.11 with 0's at the end */
+#define AIROPEEK_V9_NST_802_11_WITH_FCS 3 /* 802.11 with FCS at the end */
+
+/* tags for fields in packet header */
#define TAG_AIROPEEK_V9_LENGTH 0x0000
#define TAG_AIROPEEK_V9_TIMESTAMP_LOWER 0x0001
#define TAG_AIROPEEK_V9_TIMESTAMP_UPPER 0x0002
#define TAG_AIROPEEK_V9_UNKNOWN_0x000D 0x000D
#define TAG_AIROPEEK_V9_SLICE_LENGTH 0xffff
-/* 64-bit time in nano seconds from the (Mac) epoch */
+/* 64-bit time in nanoseconds from the (Windows FILETIME) epoch */
typedef struct airopeek_utime {
guint32 upper;
guint32 lower;
} airopeek_utime;
-static const unsigned int mac2unix = 2082844800u;
-
static gboolean airopeekv9_read(wtap *wth, int *err, gchar **err_info,
- long *data_offset);
-static gboolean airopeekv9_seek_read(wtap *wth, long seek_off,
+ gint64 *data_offset);
+static gboolean airopeekv9_seek_read(wtap *wth, gint64 seek_off,
union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
int *err, gchar **err_info);
+static void airopeekv9_close(wtap *wth);
-static int wtap_file_read_pattern (wtap *wth, char *pattern, int *err)
+static int wtap_file_read_pattern (wtap *wth, const char *pattern, int *err)
{
int c;
- char *cp;
+ const char *cp;
cp = pattern;
while (*cp)
static int wtap_file_read_till_separator (wtap *wth, char *buffer, int buflen,
- char *separators, int *err)
+ const char *separators, int *err)
{
int c;
char *cp;
int file_encap;
static const int airopeek9_encap[] = {
WTAP_ENCAP_ETHERNET,
- WTAP_ENCAP_UNKNOWN,
+ WTAP_ENCAP_IEEE_802_11_WITH_RADIO,
WTAP_ENCAP_UNKNOWN,
WTAP_ENCAP_IEEE_802_11_WITH_RADIO
};
* XXX - we should get the length of the "\177ver" section, check
* that it's followed by a little-endian 0x00000200, and then,
* when reading the XML, make sure we don't go past the end of
- * that section, and skip to the end of tha section when
+ * that section, and skip to the end of that section when
* we have the file version (and possibly check to make sure all
* tags are properly opened and closed).
*/
/* If we got this far, we assume it's an AiroPeek V9 file. */
if (fileVersion != 9) {
- /* We only support version 9 and later. */
+ /* We only support version 9. */
*err = WTAP_ERR_UNSUPPORTED;
*err_info = g_strdup_printf("airopeekv9: version %u unsupported",
fileVersion);
return 0;
/*
- * This is an AiroPeek V9 file.
+ * This is an EtherPeek or AiroPeek V9 file.
*/
-
wth->data_offset = file_tell (wth->fh);
file_encap = airopeek9_encap[mediaSubType];
wth->file_encap = file_encap;
wth->subtype_read = airopeekv9_read;
wth->subtype_seek_read = airopeekv9_seek_read;
+ wth->subtype_close = airopeekv9_close;
+ wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
+
+ wth->capture.airopeek9 = g_malloc(sizeof(airopeek9_t));
+ switch (mediaSubType) {
+
+ case AIROPEEK_V9_NST_ETHERNET:
+ case AIROPEEK_V9_NST_802_11:
+ wth->capture.airopeek9->has_fcs = FALSE;
+ break;
+
+ case AIROPEEK_V9_NST_802_11_WITH_FCS:
+ wth->capture.airopeek9->has_fcs = TRUE;
+ break;
+ }
wth->snapshot_length = 0; /* not available in header */
* are present.
*/
static int
-airopeekv9_process_header(FILE_T fh, hdr_info_t *hdr_info, int *err)
+airopeekv9_process_header(FILE_T fh, hdr_info_t *hdr_info, int *err,
+ gchar **err_info)
{
long header_len = 0;
int bytes_read;
guint8 tag_value[6];
guint16 tag;
-
- hdr_info->ieee_802_11.fcs_len = 0; /* assume no FCS for 802.11 */
+ gboolean saw_length = FALSE;
+ gboolean saw_timestamp_lower = FALSE;
+ gboolean saw_timestamp_upper = FALSE;
/* Extract the fields from the packet header */
do {
switch (tag) {
case TAG_AIROPEEK_V9_LENGTH:
+ if (saw_length) {
+ *err = WTAP_ERR_BAD_RECORD;
+ *err_info = g_strdup("airopeekv9: record has two length fields");
+ return FALSE;
+ }
hdr_info->length = pletohl(&tag_value[2]);
+ saw_length = TRUE;
break;
case TAG_AIROPEEK_V9_TIMESTAMP_LOWER:
+ if (saw_timestamp_lower) {
+ *err = WTAP_ERR_BAD_RECORD;
+ *err_info = g_strdup("airopeekv9: record has two timestamp-lower fields");
+ return FALSE;
+ }
hdr_info->timestamp.lower = pletohl(&tag_value[2]);
+ saw_timestamp_lower = TRUE;
break;
case TAG_AIROPEEK_V9_TIMESTAMP_UPPER:
+ if (saw_timestamp_upper) {
+ *err = WTAP_ERR_BAD_RECORD;
+ *err_info = g_strdup("airopeekv9: record has two timestamp-upper fields");
+ return FALSE;
+ }
hdr_info->timestamp.upper = pletohl(&tag_value[2]);
+ saw_timestamp_upper = TRUE;
break;
case TAG_AIROPEEK_V9_FLAGS_AND_STATUS:
}
} while (tag != TAG_AIROPEEK_V9_SLICE_LENGTH); /* last tag */
+ if (!saw_length) {
+ *err = WTAP_ERR_BAD_RECORD;
+ *err_info = g_strdup("airopeekv9: record has no length field");
+ return FALSE;
+ }
+ if (!saw_timestamp_lower) {
+ *err = WTAP_ERR_BAD_RECORD;
+ *err_info = g_strdup("airopeekv9: record has no timestamp-lower field");
+ return FALSE;
+ }
+ if (!saw_timestamp_upper) {
+ *err = WTAP_ERR_BAD_RECORD;
+ *err_info = g_strdup("airopeekv9: record has no timestamp-upper field");
+ return FALSE;
+ }
+
return header_len;
}
-static gboolean airopeekv9_read(wtap *wth, int *err, gchar **err_info _U_,
- long *data_offset)
+/*
+ * Time stamps appear to be in nanoseconds since the Windows epoch
+ * as used in FILETIMEs, i.e. midnight, January 1, 1601.
+ *
+ * This magic number came from "nt_time_to_nstime()" in "packet-smb.c".
+ * 1970-1601 is 369; I'm not sure what the extra 3 days and 6 hours are
+ * that are being subtracted.
+ */
+#define TIME_FIXUP_CONSTANT (369.0*365.25*24*60*60-(3.0*24*60*60+6.0*60*60))
+
+static gboolean airopeekv9_read(wtap *wth, int *err, gchar **err_info,
+ gint64 *data_offset)
{
hdr_info_t hdr_info;
int hdrlen;
*data_offset = wth->data_offset;
/* Process the packet header. */
- hdrlen = airopeekv9_process_header(wth->fh, &hdr_info, err);
+ hdrlen = airopeekv9_process_header(wth->fh, &hdr_info, err, err_info);
if (hdrlen == -1)
return FALSE;
wth->data_offset += hdrlen;
wth->phdr.len = hdr_info.length;
wth->phdr.caplen = hdr_info.sliceLength;
- switch (wth->file_encap) {
-
- case WTAP_ENCAP_IEEE_802_11_WITH_RADIO:
- wth->pseudo_header.ieee_802_11 = hdr_info.ieee_802_11;
- break;
-
- case WTAP_ENCAP_ETHERNET:
- wth->pseudo_header.eth.fcs_len = 0; /* XXX - always? */
- break;
- }
-
/* read the frame data */
buffer_assure_space(wth->frame_buffer, hdr_info.sliceLength);
wtap_file_read_expected_bytes(buffer_start_ptr(wth->frame_buffer),
t = (double) hdr_info.timestamp.lower +
(double) hdr_info.timestamp.upper * 4294967296.0;
- t = t / 1000.0; /* nano seconds -> micro seconds */
- t -= (double) mac2unix * 1000000.0;
- wth->phdr.ts.tv_sec = (time_t) (t/1000000.0);
- wth->phdr.ts.tv_usec = (guint32) (t - (double) wth->phdr.ts.tv_sec *
- 1000000.0);
+ t *= 1.0e-9;
+ t -= TIME_FIXUP_CONSTANT;
+ wth->phdr.ts.secs = (time_t) t;
+ wth->phdr.ts.nsecs = (guint32) ((t - wth->phdr.ts.secs)*1000000000);
switch (wth->file_encap) {
* whether it's an FCS or not, we should use that to determine
* whether to supply it as an FCS or discard it.
*/
- wth->phdr.len -= 4;
- wth->phdr.caplen -= 4;
+ wth->pseudo_header.ieee_802_11 = hdr_info.ieee_802_11;
+ if (wth->capture.airopeek9->has_fcs)
+ wth->pseudo_header.ieee_802_11.fcs_len = 4;
+ else {
+ wth->pseudo_header.ieee_802_11.fcs_len = 0;
+ wth->phdr.len -= 4;
+ wth->phdr.caplen -= 4;
+ }
break;
case WTAP_ENCAP_ETHERNET:
* The last 4 bytes appear to be 0 in the captures I've seen;
* are there any captures where it's an FCS?
*/
+ wth->pseudo_header.eth.fcs_len = 0;
wth->phdr.len -= 4;
wth->phdr.caplen -= 4;
break;
}
- wth->phdr.pkt_encap = wth->file_encap;
return TRUE;
}
static gboolean
-airopeekv9_seek_read(wtap *wth, long seek_off,
+airopeekv9_seek_read(wtap *wth, gint64 seek_off,
union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
- int *err, gchar **err_info _U_)
+ int *err, gchar **err_info)
{
hdr_info_t hdr_info;
return FALSE;
/* Process the packet header. */
- if (airopeekv9_process_header(wth->random_fh, &hdr_info, err) == -1)
+ if (airopeekv9_process_header(wth->random_fh, &hdr_info, err, err_info) == -1)
return FALSE;
switch (wth->file_encap) {
case WTAP_ENCAP_IEEE_802_11_WITH_RADIO:
pseudo_header->ieee_802_11 = hdr_info.ieee_802_11;
+ if (wth->capture.airopeek9->has_fcs)
+ pseudo_header->ieee_802_11.fcs_len = 4;
+ else
+ pseudo_header->ieee_802_11.fcs_len = 0;
break;
case WTAP_ENCAP_ETHERNET:
- pseudo_header->eth.fcs_len = 0; /* XXX - always? */
+ pseudo_header->eth.fcs_len = 0;
break;
}
wtap_file_read_expected_bytes(pd, length, wth->random_fh, err);
return TRUE;
}
+
+static void
+airopeekv9_close(wtap *wth)
+{
+ g_free(wth->capture.airopeek9);
+}