diff options
Diffstat (limited to 'wiretap/peekclassic.c')
-rw-r--r-- | wiretap/peekclassic.c | 746 |
1 files changed, 746 insertions, 0 deletions
diff --git a/wiretap/peekclassic.c b/wiretap/peekclassic.c new file mode 100644 index 0000000..18b926d --- /dev/null +++ b/wiretap/peekclassic.c @@ -0,0 +1,746 @@ +/* peekclassic.c + * Routines for opening files in what Savvius (formerly WildPackets) calls + * the classic file format in the description of their "PeekRdr Sample + * Application" (C++ source code to read their capture files, downloading + * of which requires a maintenance contract, so it's not free as in beer + * and probably not as in speech, either). + * + * As that description says, it's used by AiroPeek and AiroPeek NX prior + * to 2.0, EtherPeek prior to 6.0, and EtherPeek NX prior to 3.0. It + * was probably also used by TokenPeek. + * + * This handles versions 5, 6, and 7 of that format (the format version + * number is what appears in the file, and is distinct from the application + * version number). + * + * Copyright (c) 2001, Daniel Thompson <d.thompson@gmx.net> + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" +#include <string.h> + +#include <wsutil/epochs.h> +#include <wsutil/802_11-utils.h> +#include <wsutil/ws_assert.h> + +#include "wtap-int.h" +#include "file_wrappers.h" +#include "peekclassic.h" + +/* CREDITS + * + * This file decoder could not have been written without examining how + * tcptrace (http://www.tcptrace.org/) handles EtherPeek files. + */ + +/* master header */ +typedef struct peekclassic_master_header { + guint8 version; + guint8 status; +} peekclassic_master_header_t; +#define PEEKCLASSIC_MASTER_HDR_SIZE 2 + +/* secondary header (V5,V6,V7) */ +typedef struct peekclassic_v567_header { + guint32 filelength; + guint32 numPackets; + guint32 timeDate; + guint32 timeStart; + guint32 timeStop; + guint32 mediaType; /* Media Type Ethernet=0 Token Ring = 1 */ + guint32 physMedium; /* Physical Medium native=0 802.1=1 */ + guint32 appVers; /* App Version Number Maj.Min.Bug.Build */ + guint32 linkSpeed; /* Link Speed Bits/sec */ + guint32 reserved[3]; +} peekclassic_v567_header_t; +#define PEEKCLASSIC_V567_HDR_SIZE 48 + +/* full header */ +typedef struct peekclassic_header { + peekclassic_master_header_t master; + union { + peekclassic_v567_header_t v567; + } secondary; +} peekclassic_header_t; + +/* + * Packet header (V5, V6). + * + * NOTE: the time stamp, although it's a 32-bit number, is only aligned + * on a 16-bit boundary. (Does this date back to 68K Macs? The 68000 + * only required 16-bit alignment of 32-bit quantities, as did the 68010, + * and the 68020/68030/68040 required no alignment.) + * + * As such, we cannot declare this as a C structure, as compilers on + * most platforms will put 2 bytes of padding before the time stamp to + * align it on a 32-bit boundary. + * + * So, instead, we #define numbers as the offsets of the fields. + */ +#define PEEKCLASSIC_V56_LENGTH_OFFSET 0 +#define PEEKCLASSIC_V56_SLICE_LENGTH_OFFSET 2 +#define PEEKCLASSIC_V56_FLAGS_OFFSET 4 +#define PEEKCLASSIC_V56_STATUS_OFFSET 5 +#define PEEKCLASSIC_V56_TIMESTAMP_OFFSET 6 +#define PEEKCLASSIC_V56_DESTNUM_OFFSET 10 +#define PEEKCLASSIC_V56_SRCNUM_OFFSET 12 +#define PEEKCLASSIC_V56_PROTONUM_OFFSET 14 +#define PEEKCLASSIC_V56_PROTOSTR_OFFSET 16 +#define PEEKCLASSIC_V56_FILTERNUM_OFFSET 24 +#define PEEKCLASSIC_V56_PKT_SIZE 26 + +/* 64-bit time in micro seconds from the (Mac) epoch */ +typedef struct peekclassic_utime { + guint32 upper; + guint32 lower; +} peekclassic_utime; + +/* + * Packet header (V7). + * + * This doesn't have the same alignment problem, but we do it with + * #defines anyway. + */ +#define PEEKCLASSIC_V7_PROTONUM_OFFSET 0 +#define PEEKCLASSIC_V7_LENGTH_OFFSET 2 +#define PEEKCLASSIC_V7_SLICE_LENGTH_OFFSET 4 +#define PEEKCLASSIC_V7_FLAGS_OFFSET 6 +#define PEEKCLASSIC_V7_STATUS_OFFSET 7 +#define PEEKCLASSIC_V7_TIMESTAMP_OFFSET 8 +#define PEEKCLASSIC_V7_PKT_SIZE 16 + +/* + * Flag bits. + */ +#define FLAGS_CONTROL_FRAME 0x01 /* Frame is a control frame */ +#define FLAGS_HAS_CRC_ERROR 0x02 /* Frame has a CRC error */ +#define FLAGS_HAS_FRAME_ERROR 0x04 /* Frame has a frame error */ +#define FLAGS_ROUTE_INFO 0x08 /* Frame has token ring routing information */ +#define FLAGS_FRAME_TOO_LONG 0x10 /* Frame too long */ +#define FLAGS_FRAME_TOO_SHORT 0x20 /* Frame too short (runt) */ +#define FLAGS_TRIGGER 0x40 /* Trigger packet (?) */ +#define FLAGS_SNAP 0x80 /* SNAP packet (SNAP header?) */ + +/* + * Status bits. + */ +#define STATUS_SELECTED 0x01 /* Selected (in the *Peek GUI?) */ +#define STATUS_TRUNCATED 0x02 /* Truncated (?) */ +#define STATUS_APPLEPEEK 0x10 /* ApplePeek packet (?) */ +#define STATUS_SLICED 0x20 /* Sliced (cut short by snaplen?) */ +#define STATUS_HIDDEN 0x80 /* Hidden (in the *Peek GUI?) */ + +typedef struct { + time_t reference_time; +} peekclassic_t; + +static gboolean peekclassic_read_v7(wtap *wth, wtap_rec *rec, Buffer *buf, + int *err, gchar **err_info, gint64 *data_offset); +static gboolean peekclassic_seek_read_v7(wtap *wth, gint64 seek_off, + wtap_rec *rec, Buffer *buf, int *err, gchar **err_info); +static int peekclassic_read_packet_v7(wtap *wth, FILE_T fh, + wtap_rec *rec, Buffer *buf, int *err, gchar **err_info); +static gboolean peekclassic_read_v56(wtap *wth, wtap_rec *rec, Buffer *buf, + int *err, gchar **err_info, gint64 *data_offset); +static gboolean peekclassic_seek_read_v56(wtap *wth, gint64 seek_off, + wtap_rec *rec, Buffer *buf, int *err, gchar **err_info); +static gboolean peekclassic_read_packet_v56(wtap *wth, FILE_T fh, + wtap_rec *rec, Buffer *buf, int *err, gchar **err_info); + +static int peekclassic_v56_file_type_subtype = -1; +static int peekclassic_v7_file_type_subtype = -1; + +void register_peekclassic(void); + +wtap_open_return_val peekclassic_open(wtap *wth, int *err, gchar **err_info) +{ + peekclassic_header_t ep_hdr; + time_t reference_time; + int file_encap; + peekclassic_t *peekclassic; + + /* Peek classic files do not start with a magic value large enough + * to be unique; hence we use the following algorithm to determine + * the type of an unknown file: + * - populate the master header and reject file if there is no match + * - populate the secondary header and check that the reserved space + * is zero, and check some other fields; this isn't perfect, + * and we may have to add more checks at some point. + */ + ws_assert(sizeof(ep_hdr.master) == PEEKCLASSIC_MASTER_HDR_SIZE); + if (!wtap_read_bytes(wth->fh, &ep_hdr.master, + (int)sizeof(ep_hdr.master), err, err_info)) { + if (*err != WTAP_ERR_SHORT_READ) + return WTAP_OPEN_ERROR; + return WTAP_OPEN_NOT_MINE; + } + + /* + * It appears that EtherHelp (a free application from WildPackets + * that did blind capture, saving to a file, so that you could + * give the resulting file to somebody with EtherPeek) saved + * captures in EtherPeek format except that it ORed the 0x80 + * bit on in the version number. + * + * We therefore strip off the 0x80 bit in the version number. + * Perhaps there's some reason to care whether the capture + * came from EtherHelp; if we discover one, we should check + * that bit. + */ + ep_hdr.master.version &= ~0x80; + + /* switch on the file version */ + switch (ep_hdr.master.version) { + + case 5: + case 6: + case 7: + /* get the secondary header */ + ws_assert(sizeof(ep_hdr.secondary.v567) == + PEEKCLASSIC_V567_HDR_SIZE); + if (!wtap_read_bytes(wth->fh, &ep_hdr.secondary.v567, + (int)sizeof(ep_hdr.secondary.v567), err, err_info)) { + if (*err != WTAP_ERR_SHORT_READ) + return WTAP_OPEN_ERROR; + return WTAP_OPEN_NOT_MINE; + } + + if ((0 != ep_hdr.secondary.v567.reserved[0]) || + (0 != ep_hdr.secondary.v567.reserved[1]) || + (0 != ep_hdr.secondary.v567.reserved[2])) { + /* still unknown */ + return WTAP_OPEN_NOT_MINE; + } + + /* + * Check the mediaType and physMedium fields. + * We assume it's not a Peek classic file if + * these aren't values we know, rather than + * reporting them as invalid Peek classic files, + * as, given the lack of a magic number, we need + * all the checks we can get. + */ + ep_hdr.secondary.v567.mediaType = + g_ntohl(ep_hdr.secondary.v567.mediaType); + ep_hdr.secondary.v567.physMedium = + g_ntohl(ep_hdr.secondary.v567.physMedium); + + switch (ep_hdr.secondary.v567.physMedium) { + + case 0: + /* + * "Native" format, presumably meaning + * Ethernet or Token Ring. + */ + switch (ep_hdr.secondary.v567.mediaType) { + + case 0: + file_encap = WTAP_ENCAP_ETHERNET; + break; + + case 1: + file_encap = WTAP_ENCAP_TOKEN_RING; + break; + + default: + /* + * Assume this isn't a Peek classic file. + */ + return WTAP_OPEN_NOT_MINE; + } + break; + + case 1: + switch (ep_hdr.secondary.v567.mediaType) { + + case 0: + /* + * 802.11, with a private header giving + * some radio information. Presumably + * this is from AiroPeek. + */ + file_encap = WTAP_ENCAP_IEEE_802_11_WITH_RADIO; + break; + + default: + /* + * Assume this isn't a Peek classic file. + */ + return WTAP_OPEN_NOT_MINE; + } + break; + + default: + /* + * Assume this isn't a Peek classic file. + */ + return WTAP_OPEN_NOT_MINE; + } + + + /* + * Assume this is a V5, V6 or V7 Peek classic file, and + * byte swap the rest of the fields in the secondary header. + * + * XXX - we could check the file length if the file were + * uncompressed, but it might be compressed. + */ + ep_hdr.secondary.v567.filelength = + g_ntohl(ep_hdr.secondary.v567.filelength); + ep_hdr.secondary.v567.numPackets = + g_ntohl(ep_hdr.secondary.v567.numPackets); + ep_hdr.secondary.v567.timeDate = + g_ntohl(ep_hdr.secondary.v567.timeDate); + ep_hdr.secondary.v567.timeStart = + g_ntohl(ep_hdr.secondary.v567.timeStart); + ep_hdr.secondary.v567.timeStop = + g_ntohl(ep_hdr.secondary.v567.timeStop); + ep_hdr.secondary.v567.appVers = + g_ntohl(ep_hdr.secondary.v567.appVers); + ep_hdr.secondary.v567.linkSpeed = + g_ntohl(ep_hdr.secondary.v567.linkSpeed); + + /* Get the reference time as a time_t */ + reference_time = ep_hdr.secondary.v567.timeDate - EPOCH_DELTA_1904_01_01_00_00_00_UTC; + break; + + default: + /* + * Assume this isn't a Peek classic file. + */ + return WTAP_OPEN_NOT_MINE; + } + + /* + * This is a Peek classic file. + * + * At this point we have recognised the file type and have populated + * the whole ep_hdr structure in host byte order. + */ + peekclassic = g_new(peekclassic_t, 1); + wth->priv = (void *)peekclassic; + peekclassic->reference_time = reference_time; + wth->file_encap = file_encap; + switch (ep_hdr.master.version) { + + case 5: + case 6: + wth->file_type_subtype = peekclassic_v56_file_type_subtype; + wth->subtype_read = peekclassic_read_v56; + wth->subtype_seek_read = peekclassic_seek_read_v56; + break; + + case 7: + wth->file_type_subtype = peekclassic_v7_file_type_subtype; + wth->subtype_read = peekclassic_read_v7; + wth->subtype_seek_read = peekclassic_seek_read_v7; + break; + + default: + /* this is impossible */ + ws_assert_not_reached(); + } + + wth->snapshot_length = 0; /* not available in header */ + wth->file_tsprec = WTAP_TSPREC_USEC; + + /* + * Add an IDB; we don't know how many interfaces were + * involved, so we just say one interface, about which + * we only know the link-layer type, snapshot length, + * and time stamp resolution. + */ + wtap_add_generated_idb(wth); + + return WTAP_OPEN_MINE; +} + +static gboolean peekclassic_read_v7(wtap *wth, wtap_rec *rec, Buffer *buf, + int *err, gchar **err_info, gint64 *data_offset) +{ + int sliceLength; + + *data_offset = file_tell(wth->fh); + + /* Read the packet. */ + sliceLength = peekclassic_read_packet_v7(wth, wth->fh, rec, buf, + err, err_info); + if (sliceLength < 0) + return FALSE; + + /* Skip extra ignored data at the end of the packet. */ + if ((guint32)sliceLength > rec->rec_header.packet_header.caplen) { + if (!wtap_read_bytes(wth->fh, NULL, sliceLength - rec->rec_header.packet_header.caplen, + err, err_info)) + return FALSE; + } + + /* Records are padded to an even length, so if the slice length + is odd, read the padding byte. */ + if (sliceLength & 0x01) { + if (!wtap_read_bytes(wth->fh, NULL, 1, err, err_info)) + return FALSE; + } + + return TRUE; +} + +static gboolean peekclassic_seek_read_v7(wtap *wth, gint64 seek_off, + wtap_rec *rec, Buffer *buf, int *err, gchar **err_info) +{ + if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) + return FALSE; + + /* Read the packet. */ + if (peekclassic_read_packet_v7(wth, wth->random_fh, rec, buf, + err, err_info) == -1) { + if (*err == 0) + *err = WTAP_ERR_SHORT_READ; + return FALSE; + } + return TRUE; +} + +#define RADIO_INFO_SIZE 4 + +static int peekclassic_read_packet_v7(wtap *wth, FILE_T fh, + wtap_rec *rec, Buffer *buf, int *err, gchar **err_info) +{ + guint8 ep_pkt[PEEKCLASSIC_V7_PKT_SIZE]; +#if 0 + guint16 protoNum; +#endif + guint16 length; + guint16 sliceLength; + guint8 flags; + guint8 status; + guint64 timestamp; + time_t tsecs; + guint32 tusecs; + guint32 pack_flags; + guint8 radio_info[RADIO_INFO_SIZE]; + + if (!wtap_read_bytes_or_eof(fh, ep_pkt, sizeof(ep_pkt), err, err_info)) + return -1; + + /* Extract the fields from the packet */ +#if 0 + protoNum = pntoh16(&ep_pkt[PEEKCLASSIC_V7_PROTONUM_OFFSET]); +#endif + length = pntoh16(&ep_pkt[PEEKCLASSIC_V7_LENGTH_OFFSET]); + sliceLength = pntoh16(&ep_pkt[PEEKCLASSIC_V7_SLICE_LENGTH_OFFSET]); + flags = ep_pkt[PEEKCLASSIC_V7_FLAGS_OFFSET]; + status = ep_pkt[PEEKCLASSIC_V7_STATUS_OFFSET]; + timestamp = pntoh64(&ep_pkt[PEEKCLASSIC_V7_TIMESTAMP_OFFSET]); + + /* force sliceLength to be the actual length of the packet */ + if (0 == sliceLength) { + sliceLength = length; + } + /* + * The maximum value of sliceLength and length are 65535, which + * are less than WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't + * need to check them. + */ + + /* fill in packet header values */ + rec->rec_type = REC_TYPE_PACKET; + rec->block = wtap_block_create(WTAP_BLOCK_PACKET); + rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN; + tsecs = (time_t) (timestamp/1000000); + tusecs = (guint32) (timestamp - tsecs*1000000); + rec->ts.secs = tsecs - EPOCH_DELTA_1904_01_01_00_00_00_UTC; + rec->ts.nsecs = tusecs * 1000; + rec->rec_header.packet_header.len = length; + rec->rec_header.packet_header.caplen = sliceLength; + pack_flags = 0; + if (flags & FLAGS_HAS_CRC_ERROR) + pack_flags |= PACK_FLAGS_CRC_ERROR; + if (flags & FLAGS_FRAME_TOO_LONG) + pack_flags |= PACK_FLAGS_PACKET_TOO_LONG; + if (flags & FLAGS_FRAME_TOO_SHORT) + pack_flags |= PACK_FLAGS_PACKET_TOO_SHORT; + wtap_block_add_uint32_option(rec->block, OPT_PKT_FLAGS, pack_flags); + + switch (wth->file_encap) { + + case WTAP_ENCAP_IEEE_802_11_WITH_RADIO: + memset(&rec->rec_header.packet_header.pseudo_header.ieee_802_11, 0, sizeof(rec->rec_header.packet_header.pseudo_header.ieee_802_11)); + rec->rec_header.packet_header.pseudo_header.ieee_802_11.fcs_len = 0; /* no FCS */ + rec->rec_header.packet_header.pseudo_header.ieee_802_11.decrypted = FALSE; + rec->rec_header.packet_header.pseudo_header.ieee_802_11.datapad = FALSE; + rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_UNKNOWN; + + /* + * Now process the radio information pseudo-header. + * It's a 4-byte pseudo-header, consisting of: + * + * 1 byte of data rate, in units of 500 kb/s; + * + * 1 byte of channel number; + * + * 1 byte of signal strength as a percentage of + * the maximum, i.e. (RXVECTOR RSSI/RXVECTOR RSSI_Max)*100, + * or, at least, that's what I infer it is, given what + * the WildPackets note "Converting Signal Strength + * Percentage to dBm Values" says (it also says that + * the conversion the percentage to a dBm value is + * an adapter-dependent process, so, as we don't know + * what type of adapter was used to do the capture, + * we can't do the conversion); + * + * 1 byte of unknown content (padding?). + */ + if (rec->rec_header.packet_header.len < RADIO_INFO_SIZE || rec->rec_header.packet_header.caplen < RADIO_INFO_SIZE) { + *err = WTAP_ERR_BAD_FILE; + *err_info = ws_strdup_printf("peekclassic: 802.11 packet has length < 4"); + return -1; + } + rec->rec_header.packet_header.len -= RADIO_INFO_SIZE; + rec->rec_header.packet_header.caplen -= RADIO_INFO_SIZE; + sliceLength -= RADIO_INFO_SIZE; + + /* read the pseudo-header */ + if (!wtap_read_bytes(fh, radio_info, RADIO_INFO_SIZE, err, err_info)) + return -1; + + rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_data_rate = TRUE; + rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate = radio_info[0]; + + rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_channel = TRUE; + rec->rec_header.packet_header.pseudo_header.ieee_802_11.channel = radio_info[1]; + + rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_signal_percent = TRUE; + rec->rec_header.packet_header.pseudo_header.ieee_802_11.signal_percent = radio_info[2]; + + /* + * We don't know they PHY, but we do have the data rate; + * try to guess it based on the data rate and channel. + */ + if (RATE_IS_DSSS(rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate)) { + /* 11b */ + rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11B; + rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11b.has_short_preamble = FALSE; + } else if (RATE_IS_OFDM(rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate)) { + /* 11a or 11g, depending on the band. */ + if (CHAN_IS_BG(rec->rec_header.packet_header.pseudo_header.ieee_802_11.channel)) { + /* 11g */ + rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11G; + rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11g.has_mode = FALSE; + } else { + /* 11a */ + rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11A; + rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11a.has_channel_type = FALSE; + rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11a.has_turbo_type = FALSE; + } + } + + /* + * The last 4 bytes appear to be random data - the length + * might include the FCS - so we reduce the length by 4. + * + * Or maybe this is just the same kind of random 4 bytes + * of junk at the end you get in Wireless Sniffer + * captures. + */ + if (rec->rec_header.packet_header.len < 4 || rec->rec_header.packet_header.caplen < 4) { + *err = WTAP_ERR_BAD_FILE; + *err_info = ws_strdup_printf("peekclassic: 802.11 packet has length < 8"); + return -1; + } + rec->rec_header.packet_header.len -= 4; + rec->rec_header.packet_header.caplen -= 4; + break; + + case WTAP_ENCAP_ETHERNET: + /* XXX - it appears that if the low-order bit of + "status" is 0, there's an FCS in this frame, + and if it's 1, there's 4 bytes of 0. */ + rec->rec_header.packet_header.pseudo_header.eth.fcs_len = (status & 0x01) ? 0 : 4; + break; + } + + /* read the packet data */ + if (!wtap_read_packet_bytes(fh, buf, rec->rec_header.packet_header.caplen, err, err_info)) + return -1; + + return sliceLength; +} + +static gboolean peekclassic_read_v56(wtap *wth, wtap_rec *rec, Buffer *buf, + int *err, gchar **err_info, gint64 *data_offset) +{ + *data_offset = file_tell(wth->fh); + + /* read the packet */ + if (!peekclassic_read_packet_v56(wth, wth->fh, rec, buf, + err, err_info)) + return FALSE; + + /* + * XXX - is the captured packet data padded to a multiple + * of 2 bytes? + */ + return TRUE; +} + +static gboolean peekclassic_seek_read_v56(wtap *wth, gint64 seek_off, + wtap_rec *rec, Buffer *buf, int *err, gchar **err_info) +{ + if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) + return FALSE; + + /* read the packet */ + if (!peekclassic_read_packet_v56(wth, wth->random_fh, rec, buf, + err, err_info)) { + if (*err == 0) + *err = WTAP_ERR_SHORT_READ; + return FALSE; + } + return TRUE; +} + +static gboolean peekclassic_read_packet_v56(wtap *wth, FILE_T fh, + wtap_rec *rec, Buffer *buf, int *err, gchar **err_info) +{ + peekclassic_t *peekclassic = (peekclassic_t *)wth->priv; + guint8 ep_pkt[PEEKCLASSIC_V56_PKT_SIZE]; + guint16 length; + guint16 sliceLength; + guint8 flags; +#if 0 + guint8 status; +#endif + guint32 timestamp; +#if 0 + guint16 destNum; + guint16 srcNum; +#endif +#if 0 + guint16 protoNum; + char protoStr[8]; +#endif + guint32 pack_flags; + + if (!wtap_read_bytes_or_eof(fh, ep_pkt, sizeof(ep_pkt), err, err_info)) + return FALSE; + + /* Extract the fields from the packet */ + length = pntoh16(&ep_pkt[PEEKCLASSIC_V56_LENGTH_OFFSET]); + sliceLength = pntoh16(&ep_pkt[PEEKCLASSIC_V56_SLICE_LENGTH_OFFSET]); + flags = ep_pkt[PEEKCLASSIC_V56_FLAGS_OFFSET]; +#if 0 + status = ep_pkt[PEEKCLASSIC_V56_STATUS_OFFSET]; +#endif + timestamp = pntoh32(&ep_pkt[PEEKCLASSIC_V56_TIMESTAMP_OFFSET]); +#if 0 + destNum = pntoh16(&ep_pkt[PEEKCLASSIC_V56_DESTNUM_OFFSET]); + srcNum = pntoh16(&ep_pkt[PEEKCLASSIC_V56_SRCNUM_OFFSET]); + protoNum = pntoh16(&ep_pkt[PEEKCLASSIC_V56_PROTONUM_OFFSET]); + memcpy(protoStr, &ep_pkt[PEEKCLASSIC_V56_PROTOSTR_OFFSET], + sizeof protoStr); +#endif + + /* + * XXX - is the captured packet data padded to a multiple + * of 2 bytes? + */ + + /* force sliceLength to be the actual length of the packet */ + if (0 == sliceLength) { + sliceLength = length; + } + /* + * The maximum value of sliceLength and length are 65535, which + * are less than WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't + * need to check them. + */ + + /* fill in packet header values */ + rec->rec_type = REC_TYPE_PACKET; + rec->block = wtap_block_create(WTAP_BLOCK_PACKET); + rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN; + /* timestamp is in milliseconds since reference_time */ + rec->ts.secs = peekclassic->reference_time + (timestamp / 1000); + rec->ts.nsecs = 1000 * (timestamp % 1000) * 1000; + rec->rec_header.packet_header.len = length; + rec->rec_header.packet_header.caplen = sliceLength; + pack_flags = 0; + if (flags & FLAGS_HAS_CRC_ERROR) + pack_flags |= PACK_FLAGS_CRC_ERROR; + if (flags & FLAGS_FRAME_TOO_LONG) + pack_flags |= PACK_FLAGS_PACKET_TOO_LONG; + if (flags & FLAGS_FRAME_TOO_SHORT) + pack_flags |= PACK_FLAGS_PACKET_TOO_SHORT; + wtap_block_add_uint32_option(rec->block, OPT_PKT_FLAGS, pack_flags); + + switch (wth->file_encap) { + + case WTAP_ENCAP_ETHERNET: + /* We assume there's no FCS in this frame. */ + rec->rec_header.packet_header.pseudo_header.eth.fcs_len = 0; + break; + } + + /* read the packet data */ + return wtap_read_packet_bytes(fh, buf, sliceLength, err, err_info); +} + +static const struct supported_block_type peekclassic_v56_blocks_supported[] = { + /* + * We support packet blocks, with no comments or other options. + */ + { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED } +}; + +static const struct file_type_subtype_info peekclassic_v56_info = { + "Savvius classic (V5 and V6)", "peekclassic56", "pkt", "tpc;apc;wpz", + FALSE, BLOCKS_SUPPORTED(peekclassic_v56_blocks_supported), + NULL, NULL, NULL +}; + +static const struct supported_block_type peekclassic_v7_blocks_supported[] = { + /* + * We support packet blocks, with no comments or other options. + */ + { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED } +}; + +static const struct file_type_subtype_info peekclassic_v7_info = { + "Savvius classic (V7)", "peekclassic7", "pkt", "tpc;apc;wpz", + FALSE, BLOCKS_SUPPORTED(peekclassic_v7_blocks_supported), + NULL, NULL, NULL +}; + +void register_peekclassic(void) +{ + peekclassic_v56_file_type_subtype = wtap_register_file_type_subtype(&peekclassic_v56_info); + peekclassic_v7_file_type_subtype = wtap_register_file_type_subtype(&peekclassic_v7_info); + + /* + * Register names for backwards compatibility with the + * wtap_filetypes table in Lua. + */ + wtap_register_backwards_compatibility_lua_name("PEEKCLASSIC_V56", + peekclassic_v56_file_type_subtype); + wtap_register_backwards_compatibility_lua_name("PEEKCLASSIC_V7", + peekclassic_v7_file_type_subtype); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ |