/* ngsniffer.c
*
- * $Id: ngsniffer.c,v 1.75 2002/03/05 05:58:40 guy Exp $
+ * $Id$
*
* Wiretap Library
* Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
- *
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "wtap-int.h"
#include "file_wrappers.h"
#include "buffer.h"
+#include "atm.h"
#include "ngsniffer.h"
/* Magic number in Sniffer files. */
/*
* Sniffer type 2 data record format - followed by frame data.
+ *
+ * The manual at
+ *
+ * http://download.nai.com/products/media/sniffer/support/sdos/operation.pdf
+ *
+ * documents some of the values used in "fs" and "flags". "flags" don't
+ * look as if they'd be of much interest to us, as those are internal
+ * flags for state used by the Sniffer, but "fs" gives various status
+ * bits including error indications *and*:
+ *
+ * ISDN channel information for ISDN;
+ *
+ * PPP vs. SLIP information for Async.
+ *
+ * In that section it also refers to "FDDI analyzers using the NPI PCI
+ * FDDI adapter" and "FDDI analyzers using the NPI ISA FDDI adapter",
+ * referring to the first as "F1SNIFF" and the second as "FDSNIFF";
+ * those sound as if they *could* be replacements for "TRSNIFF" in
+ * the file header, but that manual says, earlier, that the header
+ * starts with "TRSNIFF data, no matter where the frames were
+ * collected".
+ *
+ * It also says that "time_high" is really "tstamp_high" and "tstamp_day";
+ * did some older manual have it as a 16-bit "tstamp_high", so that perhaps
+ * it depends on the version number in the file, or is it "tstamp_high"
+ * plus "tstamp_day" in all versions? (I forget whether this came purely
+ * from tcpview, or if I saw any of it in an NAI document.)
*/
struct frame2_rec {
guint16 time_low; /* low part of time stamp */
/*
* Sniffer type 4 data record format - followed by frame data.
*
- * XXX - the manual says that the "flags" field holds "buffer flags;
- * BF_xxxx", but doesn't say what the BF_xxxx flags are.
+ * The ATM Sniffer manual says that the "flags" field holds "buffer flags;
+ * BF_xxxx", but doesn't say what the BF_xxxx flags are. They may
+ * be the same as they are in a type 2 record, in which case they're
+ * probably not of much interest to us.
*
* XXX - the manual also says there's an 8-byte "ATMTimeStamp" driver
* time stamp at the end of "ATMSaveInfo", but, from an ATM Sniffer capture
typedef struct _ATM_AAL5Trailer {
guint16 aal5t_u2u; /* user-to-user indicator */
guint16 aal5t_len; /* length of the packet */
- guint32 aal5t_chksum; /* checksum for AAL5 packet */
+ guint32 aal5t_chksum; /* checksum for AAL5 packet */
} ATM_AAL5Trailer;
typedef struct _ATMTimeStamp {
gint8 time_high; /* high part of time stamp */
gint8 time_day; /* time in days since start of capture */
gint16 size; /* number of bytes of data */
- gint8 fs; /* frame error status bits */
- gint8 flags; /* buffer flags */
+ guint8 fs; /* frame error status bits */
+ guint8 flags; /* buffer flags */
gint16 true_size; /* size of original frame, in bytes */
guint8 chemical_x[22]; /* ? */
};
/*
- * Network type values in type 7 records.
+ * Network type values in some type 7 records.
+ *
+ * Captures with a major version number of 2 appear to have type 7
+ * records with text in them (at least one I have does).
+ *
+ * Captures with a major version of 4, and at least some captures with
+ * a major version of 5, have type 7 records with those values in the
+ * 5th byte.
+ *
+ * However, some captures with a major version number of 5 appear not to
+ * have type 7 records at all (at least one I have doesn't), but do appear
+ * to put non-zero values in the "rsvd" field of the version header (at
+ * least one I have does) - at least some other captures with smaller version
+ * numbers appear to put 0 there, so *maybe* that's where the network
+ * (sub)type is hidden in those captures. The version 5 captures I've seen
+ * that *do* have type 7 records put 0 there, so it's not as if *all* V5
+ * captures have something in the "rsvd" field, however.
+ *
+ * The semantics of these network types is inferred from the Sniffer
+ * documentation, as they correspond to types described in the UI;
+ * in particular, see
+ *
+ * http://download.nai.com/products/media/sniffer/support/sdos/operation.pdf
+ *
+ * starting at page 3-10 (56 of 496).
+ *
+ * XXX - I've seen X.25 captures with NET_ROUTER, and I've seen bridge/
+ * router captures with NET_HDLC. Sigh....
*/
-#define NET_SDLC 0
-#define NET_HDLC 1
+#define NET_SDLC 0 /* Probably "SDLC then SNA" */
+#define NET_HDLC 1 /* Used for X.25; is it used for other
+ things as well, or is it "HDLC then
+ X.25", as referred to by the document
+ cited above, and only used for X.25? */
#define NET_FRAME_RELAY 2
-#define NET_ROUTER 3 /* what's this? */
-#define NET_PPP 4
-#define NET_SMDS 5
+#define NET_ROUTER 3 /* Probably "Router/Bridge", for various
+ point-to-point protocols for use between
+ bridges and routers, including PPP as well
+ as various proprietary protocols; also
+ used for ISDN, for reasons not obvious
+ to me, given that a Sniffer knows
+ whether it's using a WAN or an ISDN pod */
+#define NET_PPP 4 /* "Asynchronous", which includes SLIP too */
+#define NET_SMDS 5 /* Not mentioned in the document, but
+ that's a document for version 5.50 of
+ the Sniffer, and that version might use
+ version 5 in the file format and thus
+ might not be using type 7 records */
/* values for V.timeunit */
#define NUM_NGSNIFF_TIMEUNITS 7
static double Usec[] = { 15.0, 0.838096, 15.0, 0.5, 2.0, 1.0, 0.1 };
-static int skip_header_records(wtap *wth, int *err, gint16 version);
-static gboolean ngsniffer_read(wtap *wth, int *err, long *data_offset);
-static int ngsniffer_seek_read(wtap *wth, long seek_off,
- union wtap_pseudo_header *pseudo_header, u_char *pd, int packet_size,
- int *err);
+static int process_header_records(wtap *wth, int *err, gchar **err_info,
+ gint16 maj_vers);
+static int process_rec_header2_v2(wtap *wth, unsigned char *buffer,
+ guint16 length, int *err, gchar **err_info);
+static int process_rec_header2_v145(wtap *wth, unsigned char *buffer,
+ guint16 length, gint16 maj_vers, int *err, gchar **err_info);
+static gboolean ngsniffer_read(wtap *wth, int *err, gchar **err_info,
+ long *data_offset);
+static gboolean ngsniffer_seek_read(wtap *wth, long seek_off,
+ union wtap_pseudo_header *pseudo_header, guchar *pd, int packet_size,
+ int *err, gchar **err_info);
static int ngsniffer_read_rec_header(wtap *wth, gboolean is_random,
guint16 *typep, guint16 *lengthp, int *err);
-static int ngsniffer_read_frame2(wtap *wth, gboolean is_random,
+static gboolean ngsniffer_read_frame2(wtap *wth, gboolean is_random,
struct frame2_rec *frame2, int *err);
-static void set_pseudo_header_frame2(union wtap_pseudo_header *pseudo_header,
- struct frame2_rec *frame2);
-static int ngsniffer_read_frame4(wtap *wth, gboolean is_random,
+static void set_pseudo_header_frame2(wtap *wth,
+ union wtap_pseudo_header *pseudo_header, struct frame2_rec *frame2);
+static gboolean ngsniffer_read_frame4(wtap *wth, gboolean is_random,
struct frame4_rec *frame4, int *err);
static void set_pseudo_header_frame4(union wtap_pseudo_header *pseudo_header,
struct frame4_rec *frame4);
-static int ngsniffer_read_frame6(wtap *wth, gboolean is_random,
+static gboolean ngsniffer_read_frame6(wtap *wth, gboolean is_random,
struct frame6_rec *frame6, int *err);
-static void set_pseudo_header_frame6(union wtap_pseudo_header *pseudo_header,
- struct frame6_rec *frame6);
-static int ngsniffer_read_rec_data(wtap *wth, gboolean is_random, u_char *pd,
- int length, int *err);
-static void fix_pseudo_header(wtap *wth,
+static void set_pseudo_header_frame6(wtap *wth,
+ union wtap_pseudo_header *pseudo_header, struct frame6_rec *frame6);
+static gboolean ngsniffer_read_rec_data(wtap *wth, gboolean is_random,
+ guchar *pd, int length, int *err);
+static int infer_pkt_encap(const guint8 *pd, int len);
+static int fix_pseudo_header(int encap, const guint8 *pd, int len,
union wtap_pseudo_header *pseudo_header);
static void ngsniffer_sequential_close(wtap *wth);
static void ngsniffer_close(wtap *wth);
static gboolean ngsniffer_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
- const union wtap_pseudo_header *pseudo_header, const u_char *pd, int *err);
+ const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err);
static gboolean ngsniffer_dump_close(wtap_dumper *wdh, int *err);
static int SnifferDecompress( unsigned char * inbuf, size_t inlen,
unsigned char * outbuf, size_t outlen, int *err );
static long ng_file_seek_seq(wtap *wth, long offset, int whence, int *err);
static long ng_file_seek_rand(wtap *wth, long offset, int whence, int *err);
-int ngsniffer_open(wtap *wth, int *err)
+int ngsniffer_open(wtap *wth, int *err, gchar **err_info)
{
int bytes_read;
char magic[sizeof ngsniffer_magic];
the last 2 are "reserved" and are thrown away */
guint16 type, length;
struct vers_rec version;
+ guint16 maj_vers;
guint16 start_date;
guint16 start_time;
static const int sniffer_encap[] = {
WTAP_ENCAP_UNKNOWN, /* PC Network broadband */
WTAP_ENCAP_UNKNOWN, /* LocalTalk */
WTAP_ENCAP_UNKNOWN, /* Znet */
- WTAP_ENCAP_UNKNOWN, /* Internetwork analyzer (synchronous) */
- WTAP_ENCAP_UNKNOWN, /* Internetwork analyzer (asynchronous) */
+ WTAP_ENCAP_PER_PACKET, /* Internetwork analyzer (synchronous) */
+ WTAP_ENCAP_PER_PACKET, /* Internetwork analyzer (asynchronous) */
WTAP_ENCAP_FDDI_BITSWAPPED,
- WTAP_ENCAP_ATM_SNIFFER
+ WTAP_ENCAP_ATM_PDUS
};
#define NUM_NGSNIFF_ENCAPS (sizeof sniffer_encap / sizeof sniffer_encap[0])
struct tm tm;
length = pletohs(record_length);
if (type != REC_VERS) {
- g_message("ngsniffer: Sniffer file doesn't start with a version record");
*err = WTAP_ERR_BAD_RECORD;
+ *err_info = g_strdup_printf("ngsniffer: Sniffer file doesn't start with a version record");
return -1;
}
}
wth->data_offset += sizeof version;
- /* Check the data link type.
- If "version.network" is 7, that's "Internetwork analyzer";
- Sniffers appear to write out LAPB, LAPD and PPP captures
- (and perhaps other types of captures) in that fashion,
- and, so far, the only way we know of distinguishing them
- is to look at the first byte of the packet - if it's 0xFF,
- it's PPP, otherwise if it's odd, it's LAPB else it's LAPD.
- Therefore, we treat it as WTAP_ENCAP_UNKNOWN for now, but
- don't treat that as an error.
-
- In one PPP capture, the two 16-bit words of the "rsvd" field
- were 1 and 3, respectively, and in one X.25 capture, they
- were both 0. That's too small a sample from which to
- conclude anything, however.... */
+ /* Check the data link type. */
if (version.network >= NUM_NGSNIFF_ENCAPS
- || (sniffer_encap[version.network] == WTAP_ENCAP_UNKNOWN
- && version.network != 7)) {
- g_message("ngsniffer: network type %u unknown or unsupported",
- version.network);
+ || sniffer_encap[version.network] == WTAP_ENCAP_UNKNOWN) {
*err = WTAP_ERR_UNSUPPORTED_ENCAP;
+ *err_info = g_strdup_printf("ngsniffer: network type %u unknown or unsupported",
+ version.network);
return -1;
}
/* Check the time unit */
if (version.timeunit >= NUM_NGSNIFF_TIMEUNITS) {
- g_message("ngsniffer: Unknown timeunit %u", version.timeunit);
*err = WTAP_ERR_UNSUPPORTED;
+ *err_info = g_strdup_printf("ngsniffer: Unknown timeunit %u", version.timeunit);
return -1;
}
* so we just skip them - except for REC_HEADER2 records, which
* we look at, for "Internetwork analyzer" captures, to attempt to
* determine what the link-layer encapsulation is.
+ *
+ * XXX - in some version 1.16 internetwork analyzer files
+ * generated by the Windows Sniffer when saving Windows
+ * Sniffer files as DOS Sniffer files, there's no REC_HEADER2
+ * record, but the first "rsvd" word is 1 for PRI ISDN files, 2
+ * for BRI ISDN files, and 0 for non-ISDN files; is that something
+ * the DOS Sniffer understands?
*/
- if (skip_header_records(wth, err, version.maj_vers) < 0)
+ maj_vers = pletohs(&version.maj_vers);
+ if (process_header_records(wth, err, err_info, maj_vers) < 0)
return -1;
+ if (wth->file_encap == WTAP_ENCAP_PER_PACKET) {
+ /*
+ * Well, we haven't determined the internetwork analyzer
+ * subtype yet...
+ */
+ switch (maj_vers) {
+
+ case 1:
+ /*
+ * ... and this is a version 1 capture; look
+ * at the first "rsvd" word.
+ */
+ switch (pletohs(&version.rsvd[0])) {
+
+ case 1:
+ case 2:
+ wth->file_encap = WTAP_ENCAP_ISDN;
+ break;
+ }
+ break;
+
+ case 3:
+ /*
+ * ...and this is a version 3 capture; we've
+ * seen nothing in those that obviously
+ * indicates the capture type, but the only
+ * one we've seen is a Frame Relay capture,
+ * so mark it as Frame Relay for now.
+ */
+ wth->file_encap = WTAP_ENCAP_FRELAY_WITH_PHDR;
+ break;
+ }
+ }
/*
* Now, if we have a random stream open, position it to the same
* "ngsniffer_read()".
*/
if (wth->random_fh != NULL) {
- if (file_seek(wth->random_fh, wth->data_offset, SEEK_SET) == -1) {
- *err = file_error(wth->random_fh);
+ if (file_seek(wth->random_fh, wth->data_offset, SEEK_SET, err) == -1)
return -1;
- }
}
/* This is a ngsniffer file */
wth->capture.ngsniffer = g_malloc(sizeof(ngsniffer_t));
+ wth->capture.ngsniffer->maj_vers = maj_vers;
+ wth->capture.ngsniffer->min_vers = pletohs(&version.min_vers);
/* We haven't allocated any uncompression buffers yet. */
wth->capture.ngsniffer->seq.buf = NULL;
wth->snapshot_length = 0; /* not available in header, only in frame */
wth->capture.ngsniffer->timeunit = Usec[version.timeunit];
wth->capture.ngsniffer->is_atm =
- (wth->file_encap == WTAP_ENCAP_ATM_SNIFFER);
+ (wth->file_encap == WTAP_ENCAP_ATM_PDUS);
/* Get capture start time */
start_time = pletohs(&version.time);
}
static int
-skip_header_records(wtap *wth, int *err, gint16 version)
+process_header_records(wtap *wth, int *err, gchar **err_info, gint16 maj_vers)
{
int bytes_read;
char record_type[2];
the last 2 are "reserved" and are thrown away */
guint16 type, length;
int bytes_to_read;
- unsigned char buffer[32];
+ unsigned char buffer[256];
for (;;) {
errno = WTAP_ERR_CANT_READ;
&& (type != REC_HEADER3) && (type != REC_HEADER4)
&& (type != REC_HEADER5) && (type != REC_HEADER6)
&& (type != REC_HEADER7)
- && ((type != REC_V2DESC) || (version > 2)) ) {
+ && ((type != REC_V2DESC) || (maj_vers > 2)) ) {
/*
* Well, this is either some unknown header type
* (we ignore this case), an uncompressed data
* which implies data. Seek backwards over the
* two bytes we read, and return.
*/
- if (file_seek(wth->fh, -2, SEEK_CUR) == -1) {
- *err = file_error(wth->fh);
+ if (file_seek(wth->fh, -2, SEEK_CUR, err) == -1)
return -1;
- }
return 0;
}
length = pletohs(record_length);
/*
- * Is this a REC_HEADER2 record, and do we not yet know
- * the encapsulation type (i.e., is this is an
- * "Internetwork analyzer" capture?
+ * Do we not yet know the encapsulation type (i.e., is
+ * this is an "Internetwork analyzer" capture?), and
+ * is this a REC_HEADER2 record?
*
- * If so, the 5th byte of the record appears to specify
- * the particular type of network we're on.
+ * If so, it appears to specify the particular type
+ * of network we're on.
*/
- if (type == REC_HEADER2 &&
- wth->file_encap == WTAP_ENCAP_UNKNOWN) {
+ if (wth->file_encap == WTAP_ENCAP_PER_PACKET &&
+ type == REC_HEADER2) {
/*
- * Yes, get the first 32 bytes of the record
- * data.
+ * Yes, get the first up-to-256 bytes of the
+ * record data.
*/
bytes_to_read = MIN(length, sizeof buffer);
bytes_read = file_read(buffer, 1, bytes_to_read,
return -1;
}
}
+
+ switch (maj_vers) {
+
+ case 2:
+ if (process_rec_header2_v2(wth, buffer,
+ length, err, err_info) < 0)
+ return -1;
+ break;
+
+ case 1:
+ case 4:
+ case 5:
+ if (process_rec_header2_v145(wth, buffer,
+ length, maj_vers, err, err_info) < 0)
+ return -1;
+ break;
+ }
+
/*
* Skip the rest of the record.
*/
if (length > sizeof buffer) {
if (file_seek(wth->fh, length - sizeof buffer,
- SEEK_CUR) == -1) {
- *err = file_error(wth->fh);
+ SEEK_CUR, err) == -1)
return -1;
- }
}
+ } else {
+ /* Nope, just skip over the data. */
+ if (file_seek(wth->fh, length, SEEK_CUR, err) == -1)
+ return -1;
+ }
+ wth->data_offset += length;
+ }
+}
- /*
- * XXX - what about LAPB and LAPD? At least one
- * X.25 capture has a type of NET_HDLC, but one
- * might also consider LAPD to be an HDLC
- * variant; if it also has a type of NET_HDLC,
- * we'd have to look at some other data to
- * distinguish them.
- *
- * I have no LAPD captures, so I can't check
- * various fields of this record (and I'd
- * need multiple captures of both LAPB/X.25
- * and LAPD/ISDN to be reasonable certain
- * where the magic key is).
- *
- * So, for now, we don't set the encapsulation
- * for NET_HDLC.
- */
- switch (buffer[4]) {
+static int
+process_rec_header2_v2(wtap *wth, unsigned char *buffer, guint16 length,
+ int *err, gchar **err_info)
+{
+ static const char x_25_str[] = "HDLC\nX.25\n";
- case NET_FRAME_RELAY:
- wth->file_encap = WTAP_ENCAP_FRELAY;
- break;
+ /*
+ * There appears to be a string in a REC_HEADER2 record, with
+ * a list of protocols. In one X.25 capture I've seen, the
+ * string was "HDLC\nX.25\nCLNP\nISO_TP\nSESS\nPRES\nVTP\nACSE".
+ * Presumably CLNP and everything else is per-packet, but
+ * we assume "HDLC\nX.25\n" indicates that it's an X.25 capture.
+ */
+ if (length < sizeof x_25_str - 1) {
+ /*
+ * There's not enough data to compare.
+ */
+ *err = WTAP_ERR_UNSUPPORTED_ENCAP;
+ *err_info = g_strdup_printf("ngsniffer: WAN capture has too-short protocol list");
+ return -1;
+ }
- case NET_PPP:
- wth->file_encap = WTAP_ENCAP_PPP;
- break;
- }
+ if (strncmp((char *)buffer, x_25_str, sizeof x_25_str - 1) == 0) {
+ /*
+ * X.25.
+ */
+ wth->file_encap = WTAP_ENCAP_LAPB;
+ } else {
+ *err = WTAP_ERR_UNSUPPORTED_ENCAP;
+ *err_info = g_strdup_printf("ngsniffer: WAN capture protocol string %.*s unknown",
+ length, buffer);
+ return -1;
+ }
+ return 0;
+}
- } else {
- /* Nope, just skip over the data. */
- if (file_seek(wth->fh, length, SEEK_CUR) == -1) {
- *err = file_error(wth->fh);
+static int
+process_rec_header2_v145(wtap *wth, unsigned char *buffer, guint16 length,
+ gint16 maj_vers, int *err, gchar **err_info)
+{
+ /*
+ * The 5th byte of the REC_HEADER2 record appears to be a
+ * network type.
+ */
+ if (length < 5) {
+ /*
+ * There is no 5th byte; give up.
+ */
+ *err = WTAP_ERR_UNSUPPORTED_ENCAP;
+ *err_info = g_strdup("ngsniffer: WAN capture has no network subtype");
+ return -1;
+ }
+
+ /*
+ * The X.25 captures I've seen have a type of NET_HDLC, and the
+ * Sniffer documentation seems to imply that it's used for
+ * X.25, although it could be used for other purposes as well.
+ *
+ * NET_ROUTER is used for all sorts of point-to-point protocols,
+ * including ISDN. It appears, from the documentation, that the
+ * Sniffer attempts to infer the particular protocol by looking
+ * at the traffic; it's not clear whether it stores in the file
+ * an indication of the protocol it inferred was being used.
+ *
+ * Unfortunately, it also appears that NET_HDLC is used for
+ * stuff other than X.25 as well, so we can't just interpret
+ * it unconditionally as X.25.
+ *
+ * For now, we interpret both NET_HDLC and NET_ROUTER as "per-packet
+ * encapsulation". We remember that we saw NET_ROUTER, though,
+ * as it appears that we can infer whether a packet is PPP or
+ * ISDN based on the channel number subfield of the frame error
+ * status bits - if it's 0, it's PPP, otherwise it's ISDN and
+ * the channel number indicates which channel it is. We assume
+ * NET_HDLC isn't used for ISDN.
+ */
+ switch (buffer[4]) {
+
+ case NET_SDLC:
+ wth->file_encap = WTAP_ENCAP_SDLC;
+ break;
+
+ case NET_HDLC:
+ wth->file_encap = WTAP_ENCAP_PER_PACKET;
+ break;
+
+ case NET_FRAME_RELAY:
+ wth->file_encap = WTAP_ENCAP_FRELAY_WITH_PHDR;
+ break;
+
+ case NET_ROUTER:
+ /*
+ * For most of the version 4 capture files I've seen,
+ * 0xfa in buffer[1] means the file is an ISDN capture,
+ * but there's one PPP file with 0xfa there; does that
+ * mean that the 0xfa has nothing to do with ISDN,
+ * or is that just an ISDN file with no D channel
+ * packets? (The channel number is not 0 in any
+ * of the packets, so perhaps it is.)
+ *
+ * For one version 5 ISDN capture I've seen, there's
+ * a 0x01 in buffer[6]; none of the non-ISDN version
+ * 5 captures have it.
+ */
+ wth->file_encap = WTAP_ENCAP_PER_PACKET;
+ switch (maj_vers) {
+
+ case 4:
+ if (buffer[1] == 0xfa)
+ wth->file_encap = WTAP_ENCAP_ISDN;
+ break;
+
+ case 5:
+ if (length < 7) {
+ /*
+ * There is no 5th byte; give up.
+ */
+ *err = WTAP_ERR_UNSUPPORTED_ENCAP;
+ *err_info = g_strdup("ngsniffer: WAN bridge/router capture has no ISDN flag");
return -1;
}
+ if (buffer[6] == 0x01)
+ wth->file_encap = WTAP_ENCAP_ISDN;
+ break;
}
- wth->data_offset += length;
+ break;
+
+ case NET_PPP:
+ wth->file_encap = WTAP_ENCAP_PPP_WITH_PHDR;
+ break;
+
+ default:
+ /*
+ * Reject these until we can figure them out.
+ */
+ *err = WTAP_ERR_UNSUPPORTED_ENCAP;
+ *err_info = g_strdup_printf("ngsniffer: WAN network subtype %u unknown or unsupported",
+ buffer[4]);
+ return -1;
}
+ return 0;
}
/* Read the next packet */
-static gboolean ngsniffer_read(wtap *wth, int *err, long *data_offset)
+static gboolean ngsniffer_read(wtap *wth, int *err, gchar **err_info,
+ long *data_offset)
{
int ret;
guint16 type, length;
struct frame6_rec frame6;
double t;
guint16 time_low, time_med, time_high, true_size, size;
- u_char *pd;
+ guchar *pd;
for (;;) {
/*
* We shouldn't get a frame2 record in
* an ATM capture.
*/
- g_message("ngsniffer: REC_FRAME2 record in an ATM Sniffer file");
*err = WTAP_ERR_BAD_RECORD;
+ *err_info = g_strdup("ngsniffer: REC_FRAME2 record in an ATM Sniffer file");
return FALSE;
}
/* Read the f_frame2_struct */
- ret = ngsniffer_read_frame2(wth, FALSE, &frame2, err);
- if (ret < 0) {
+ if (!ngsniffer_read_frame2(wth, FALSE, &frame2, err)) {
/* Read error */
return FALSE;
}
t = (double)time_low+(double)(time_med)*65536.0 +
(double)time_high*4294967296.0;
- set_pseudo_header_frame2(&wth->pseudo_header, &frame2);
+ set_pseudo_header_frame2(wth, &wth->pseudo_header,
+ &frame2);
goto found;
case REC_FRAME4:
* We shouldn't get a frame2 record in
* a non-ATM capture.
*/
- g_message("ngsniffer: REC_FRAME4 record in a non-ATM Sniffer file");
*err = WTAP_ERR_BAD_RECORD;
+ *err_info = g_strdup("ngsniffer: REC_FRAME4 record in a non-ATM Sniffer file");
return FALSE;
}
/* Read the f_frame4_struct */
- ret = ngsniffer_read_frame4(wth, FALSE, &frame4, err);
+ if (!ngsniffer_read_frame4(wth, FALSE, &frame4, err)) {
+ /* Read error */
+ return FALSE;
+ }
wth->data_offset += sizeof frame4;
time_low = pletohs(&frame4.time_low);
time_med = pletohs(&frame4.time_med);
size = pletohs(&frame4.size);
true_size = pletohs(&frame4.true_size);
- length -= sizeof frame4; /* we already read that much */
+ /*
+ * XXX - it looks as if version 4 captures have
+ * a bogus record length, based on the assumption
+ * that the record is a frame2 record.
+ */
+ if (wth->capture.ngsniffer->maj_vers >= 5)
+ length -= sizeof frame4; /* we already read that much */
+ else {
+ if (wth->capture.ngsniffer->min_vers >= 95)
+ length -= sizeof frame2;
+ else
+ length -= sizeof frame4;
+ }
/*
* XXX - use the "time_day" field? Is that for captures
goto found;
case REC_FRAME6:
- /* XXX - Is this test valid? */
- if (wth->capture.ngsniffer->is_atm) {
- g_message("ngsniffer: REC_FRAME6 record in an ATM Sniffer file");
- *err = WTAP_ERR_BAD_RECORD;
+ /* Read the f_frame6_struct */
+ if (!ngsniffer_read_frame6(wth, FALSE, &frame6, err)) {
+ /* Read error */
return FALSE;
}
-
- /* Read the f_frame6_struct */
- ret = ngsniffer_read_frame6(wth, FALSE, &frame6, err);
wth->data_offset += sizeof frame6;
time_low = pletohs(&frame6.time_low);
time_med = pletohs(&frame6.time_med);
t = (double)time_low+(double)(time_med)*65536.0 +
(double)time_high*4294967296.0;
- set_pseudo_header_frame6(&wth->pseudo_header, &frame6);
+ set_pseudo_header_frame6(wth, &wth->pseudo_header,
+ &frame6);
goto found;
case REC_EOF:
/*
* Yes - treat this as an error.
*/
- g_message("ngsniffer: Record length is less than packet size");
*err = WTAP_ERR_BAD_RECORD;
+ *err_info = g_strdup("ngsniffer: Record length is less than packet size");
return FALSE;
}
*/
buffer_assure_space(wth->frame_buffer, length);
pd = buffer_start_ptr(wth->frame_buffer);
- if (ngsniffer_read_rec_data(wth, FALSE, pd, length, err) < 0)
+ if (!ngsniffer_read_rec_data(wth, FALSE, pd, length, err))
return FALSE; /* Read error */
wth->data_offset += length;
- if (wth->file_encap == WTAP_ENCAP_UNKNOWN) {
- /*
- * OK, this is from an "Internetwork analyzer", and
- * we either didn't see a type 7 record or it had
- * a network type such as NET_HDLC that doesn't
- * tell us which *particular* HDLC derivative this
- * is; let's look at the first byte of the packet,
- * and figure out whether it's LAPB, LAPD, PPP, or
- * Frame Relay.
- */
- if (pd[0] == 0xFF) {
- /*
- * PPP.
- */
- wth->file_encap = WTAP_ENCAP_PPP;
- } else if (pd[0] == 0x34 || pd[0] == 0x28) {
- /*
- * Frame Relay.
- */
- wth->file_encap = WTAP_ENCAP_FRELAY;
- } else if (pd[0] & 1) {
- /*
- * LAPB.
- */
- wth->file_encap = WTAP_ENCAP_LAPB;
- } else {
- /*
- * LAPD.
- */
- wth->file_encap = WTAP_ENCAP_LAPD;
- }
- }
-
- /*
- * Fix up the pseudo-header; we may have set "x25.flags",
- * but, for some traffic, we should set "p2p.sent" instead.
- */
- fix_pseudo_header(wth, &wth->pseudo_header);
+ wth->phdr.pkt_encap = fix_pseudo_header(wth->file_encap, pd, length,
+ &wth->pseudo_header);
t = t/1000000.0 * wth->capture.ngsniffer->timeunit; /* t = # of secs */
t += wth->capture.ngsniffer->start;
wth->phdr.ts.tv_sec = (long)t;
wth->phdr.ts.tv_usec = (unsigned long)((t-(double)(wth->phdr.ts.tv_sec))
*1.0e6);
- wth->phdr.pkt_encap = wth->file_encap;
return TRUE;
}
-static int ngsniffer_seek_read(wtap *wth, long seek_off,
- union wtap_pseudo_header *pseudo_header, u_char *pd, int packet_size,
- int *err)
+static gboolean ngsniffer_seek_read(wtap *wth, long seek_off,
+ union wtap_pseudo_header *pseudo_header, guchar *pd, int packet_size,
+ int *err, gchar **err_info _U_)
{
int ret;
guint16 type, length;
struct frame6_rec frame6;
if (ng_file_seek_rand(wth, seek_off, SEEK_SET, err) == -1)
- return -1;
+ return FALSE;
ret = ngsniffer_read_rec_header(wth, TRUE, &type, &length, err);
if (ret <= 0) {
/* EOF means "short read" in random-access mode */
*err = WTAP_ERR_SHORT_READ;
}
- return -1;
+ return FALSE;
}
switch (type) {
case REC_FRAME2:
/* Read the f_frame2_struct */
- ret = ngsniffer_read_frame2(wth, TRUE, &frame2, err);
- if (ret < 0) {
+ if (!ngsniffer_read_frame2(wth, TRUE, &frame2, err)) {
/* Read error */
- return ret;
+ return FALSE;
}
length -= sizeof frame2; /* we already read that much */
- set_pseudo_header_frame2(pseudo_header, &frame2);
+ set_pseudo_header_frame2(wth, pseudo_header, &frame2);
break;
case REC_FRAME4:
/* Read the f_frame4_struct */
- ret = ngsniffer_read_frame4(wth, TRUE, &frame4, err);
+ if (!ngsniffer_read_frame4(wth, TRUE, &frame4, err)) {
+ /* Read error */
+ return FALSE;
+ }
length -= sizeof frame4; /* we already read that much */
case REC_FRAME6:
/* Read the f_frame6_struct */
- ret = ngsniffer_read_frame6(wth, TRUE, &frame6, err);
+ if (!ngsniffer_read_frame6(wth, TRUE, &frame6, err)) {
+ /* Read error */
+ return FALSE;
+ }
length -= sizeof frame6; /* we already read that much */
- set_pseudo_header_frame6(pseudo_header, &frame6);
+ set_pseudo_header_frame6(wth, pseudo_header, &frame6);
break;
default:
* "Can't happen".
*/
g_assert_not_reached();
- return -1;
+ return FALSE;
}
- /*
- * Fix up the pseudo-header; we may have set "x25.flags",
- * but, for some traffic, we should set "p2p.sent" instead.
- */
- fix_pseudo_header(wth, pseudo_header);
-
/*
* Got the pseudo-header (if any), now get the data.
*/
- return ngsniffer_read_rec_data(wth, TRUE, pd, packet_size, err);
+ if (!ngsniffer_read_rec_data(wth, TRUE, pd, packet_size, err))
+ return FALSE;
+
+ fix_pseudo_header(wth->file_encap, pd, packet_size, pseudo_header);
+
+ return TRUE;
}
static int ngsniffer_read_rec_header(wtap *wth, gboolean is_random,
return 1; /* success */
}
-static int ngsniffer_read_frame2(wtap *wth, gboolean is_random,
+static gboolean ngsniffer_read_frame2(wtap *wth, gboolean is_random,
struct frame2_rec *frame2, int *err)
{
int bytes_read;
if (bytes_read != sizeof *frame2) {
if (*err == 0)
*err = WTAP_ERR_SHORT_READ;
- return -1;
+ return FALSE;
}
- return 0;
+ return TRUE;
}
-static void set_pseudo_header_frame2(union wtap_pseudo_header *pseudo_header,
- struct frame2_rec *frame2)
+static void set_pseudo_header_frame2(wtap *wth,
+ union wtap_pseudo_header *pseudo_header, struct frame2_rec *frame2)
{
/*
- * In one PPP "Internetwork analyzer" capture,
- * the only bit seen in "fs" is the 0x80 bit,
- * which probably indicates the packet's
- * direction; all other bits were zero.
- * All bits in "frame2.flags" were zero.
+ * In one PPP "Internetwork analyzer" capture:
+ *
+ * The only bit seen in "frame2.fs" is the 0x80 bit, which
+ * probably indicates the packet's direction; all other
+ * bits were zero. The Expert Sniffer Network Analyzer
+ * 5.50 Operations manual says that bit is the FS_DTE bit
+ * for async/PPP data. The other bits are error bits
+ * plus bits indicating whether the frame is PPP or SLIP,
+ * but the PPP bit isn't set.
+ *
+ * All bits in "frame2.flags" were zero.
+ *
+ * In one X.25 "Internetwork analyzer" capture:
+ *
+ * The only bit seen in "frame2.fs" is the 0x80 bit, which
+ * probably indicates the packet's direction; all other
+ * bits were zero.
+ *
+ * "frame2.flags" was always 0x18; however, the Sniffer
+ * manual says that just means that a display filter was
+ * calculated for the frame, and it should be displayed,
+ * so perhaps that's just a quirk of that particular capture.
*
- * In one X.25 "Interenetwork analyzer" capture,
- * the only bit seen in "fs" is the 0x80 bit,
- * which probably indicates the packet's
- * direction; all other bits were zero.
- * "frame2.flags" was always 0x18.
+ * In one Ethernet capture:
*
- * In one Ethernet capture, "fs" was always 0,
- * and "flags" was either 0 or 0x18, with no
- * obvious correlation with anything.
+ * "frame2.fs" was always 0; the Sniffer manual says they're
+ * error bits of various sorts.
*
- * In one Token Ring capture, "fs" was either 0
- * or 0xcc, and "flags" was either 0 or 0x18,
- * with no obvious correlation with anything.
+ * "frame2.flags" was either 0 or 0x18, with no obvious
+ * correlation with anything. See previous comment
+ * about display filters.
+ *
+ * In one Token Ring capture:
+ *
+ * "frame2.fs" was either 0 or 0xcc; the Sniffer manual says
+ * nothing about those bits for Token Ring captures.
+ *
+ * "frame2.flags" was either 0 or 0x18, with no obvious
+ * correlation with anything. See previous comment
+ * about display filters.
*/
- pseudo_header->x25.flags = (frame2->fs & 0x80) ? 0x00 : 0x80;
+ switch (wth->file_encap) {
+
+ case WTAP_ENCAP_ETHERNET:
+ /*
+ * XXX - do we ever have an FCS? If not, why do we often
+ * have 4 extra bytes of stuff at the end? Do some
+ * PC Ethernet interfaces report the length including the
+ * FCS but not store the FCS in the packet, or do some
+ * Ethernet drivers work that way?
+ */
+ pseudo_header->eth.fcs_len = 0;
+ break;
+
+ case WTAP_ENCAP_PPP_WITH_PHDR:
+ case WTAP_ENCAP_SDLC:
+ pseudo_header->p2p.sent = (frame2->fs & 0x80) ? TRUE : FALSE;
+ break;
+
+ case WTAP_ENCAP_LAPB:
+ case WTAP_ENCAP_FRELAY_WITH_PHDR:
+ case WTAP_ENCAP_PER_PACKET:
+ pseudo_header->x25.flags = (frame2->fs & 0x80) ? 0x00 : FROM_DCE;
+ break;
+
+ case WTAP_ENCAP_ISDN:
+ pseudo_header->isdn.uton = (frame2->fs & 0x80) ? FALSE : TRUE;
+ switch (frame2->fs & 0x18) {
+
+ case 0x18:
+ pseudo_header->isdn.channel = 0; /* D-channel */
+ break;
+
+ case 0x08:
+ pseudo_header->isdn.channel = 1; /* B1-channel */
+ break;
+
+ case 0x10:
+ pseudo_header->isdn.channel = 2; /* B1-channel */
+ break;
+
+ default:
+ pseudo_header->isdn.channel = 30; /* XXX */
+ break;
+ }
+ }
}
-static int ngsniffer_read_frame4(wtap *wth, gboolean is_random,
+static gboolean ngsniffer_read_frame4(wtap *wth, gboolean is_random,
struct frame4_rec *frame4, int *err)
{
int bytes_read;
if (bytes_read != sizeof *frame4) {
if (*err == 0)
*err = WTAP_ERR_SHORT_READ;
- return -1;
+ return FALSE;
}
- return 0;
+ return TRUE;
}
static void set_pseudo_header_frame4(union wtap_pseudo_header *pseudo_header,
struct frame4_rec *frame4)
{
- pseudo_header->ngsniffer_atm.AppTrafType = frame4->atm_info.AppTrafType;
- pseudo_header->ngsniffer_atm.AppHLType = frame4->atm_info.AppHLType;
- pseudo_header->ngsniffer_atm.Vpi = pletohs(&frame4->atm_info.Vpi);
- pseudo_header->ngsniffer_atm.Vci = pletohs(&frame4->atm_info.Vci);
- pseudo_header->ngsniffer_atm.channel = pletohs(&frame4->atm_info.channel);
- pseudo_header->ngsniffer_atm.cells = pletohs(&frame4->atm_info.cells);
- pseudo_header->ngsniffer_atm.aal5t_u2u = pletohs(&frame4->atm_info.Trailer.aal5t_u2u);
- pseudo_header->ngsniffer_atm.aal5t_len = pletohs(&frame4->atm_info.Trailer.aal5t_len);
- pseudo_header->ngsniffer_atm.aal5t_chksum = pletohl(&frame4->atm_info.Trailer.aal5t_chksum);
+ guint32 StatusWord;
+ guint8 aal_type, hl_type;
+ guint16 vpi, vci;
+
+ /*
+ * Map flags from frame4.atm_info.StatusWord.
+ */
+ pseudo_header->atm.flags = 0;
+ StatusWord = pletohl(&frame4->atm_info.StatusWord);
+ if (StatusWord & SW_RAW_CELL)
+ pseudo_header->atm.flags |= ATM_RAW_CELL;
+
+ aal_type = frame4->atm_info.AppTrafType & ATT_AALTYPE;
+ hl_type = frame4->atm_info.AppTrafType & ATT_HLTYPE;
+ vpi = pletohs(&frame4->atm_info.Vpi);
+ vci = pletohs(&frame4->atm_info.Vci);
+
+ switch (aal_type) {
+
+ case ATT_AAL_UNKNOWN:
+ /*
+ * Map ATT_AAL_UNKNOWN on VPI 0, VCI 5 to ATT_AAL_SIGNALLING,
+ * as that's the VPCI used for signalling.
+ *
+ * XXX - is this necessary, or will frames to 0/5 always
+ * have ATT_AAL_SIGNALLING?
+ */
+ if (vpi == 0 && vci == 5)
+ pseudo_header->atm.aal = AAL_SIGNALLING;
+ else
+ pseudo_header->atm.aal = AAL_UNKNOWN;
+ pseudo_header->atm.type = TRAF_UNKNOWN;
+ pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
+ break;
+
+ case ATT_AAL1:
+ pseudo_header->atm.aal = AAL_1;
+ pseudo_header->atm.type = TRAF_UNKNOWN;
+ pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
+ break;
+
+ case ATT_AAL3_4:
+ pseudo_header->atm.aal = AAL_3_4;
+ pseudo_header->atm.type = TRAF_UNKNOWN;
+ pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
+ break;
+
+ case ATT_AAL5:
+ pseudo_header->atm.aal = AAL_5;
+ switch (hl_type) {
+
+ case ATT_HL_UNKNOWN:
+ pseudo_header->atm.type = TRAF_UNKNOWN;
+ pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
+ break;
+
+ case ATT_HL_LLCMX:
+ pseudo_header->atm.type = TRAF_LLCMX;
+ pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
+ break;
+
+ case ATT_HL_VCMX:
+ pseudo_header->atm.type = TRAF_VCMX;
+ switch (frame4->atm_info.AppHLType) {
+
+ case AHLT_UNKNOWN:
+ pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
+ break;
+
+ case AHLT_VCMX_802_3_FCS:
+ pseudo_header->atm.subtype =
+ TRAF_ST_VCMX_802_3_FCS;
+ break;
+
+ case AHLT_VCMX_802_4_FCS:
+ pseudo_header->atm.subtype =
+ TRAF_ST_VCMX_802_4_FCS;
+ break;
+
+ case AHLT_VCMX_802_5_FCS:
+ pseudo_header->atm.subtype =
+ TRAF_ST_VCMX_802_5_FCS;
+ break;
+
+ case AHLT_VCMX_FDDI_FCS:
+ pseudo_header->atm.subtype =
+ TRAF_ST_VCMX_FDDI_FCS;
+ break;
+
+ case AHLT_VCMX_802_6_FCS:
+ pseudo_header->atm.subtype =
+ TRAF_ST_VCMX_802_6_FCS;
+ break;
+
+ case AHLT_VCMX_802_3:
+ pseudo_header->atm.subtype = TRAF_ST_VCMX_802_3;
+ break;
+
+ case AHLT_VCMX_802_4:
+ pseudo_header->atm.subtype = TRAF_ST_VCMX_802_4;
+ break;
+
+ case AHLT_VCMX_802_5:
+ pseudo_header->atm.subtype = TRAF_ST_VCMX_802_5;
+ break;
+
+ case AHLT_VCMX_FDDI:
+ pseudo_header->atm.subtype = TRAF_ST_VCMX_FDDI;
+ break;
+
+ case AHLT_VCMX_802_6:
+ pseudo_header->atm.subtype = TRAF_ST_VCMX_802_6;
+ break;
+
+ case AHLT_VCMX_FRAGMENTS:
+ pseudo_header->atm.subtype =
+ TRAF_ST_VCMX_FRAGMENTS;
+ break;
+
+ case AHLT_VCMX_BPDU:
+ pseudo_header->atm.subtype = TRAF_ST_VCMX_BPDU;
+ break;
+
+ default:
+ pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
+ break;
+ }
+ break;
+
+ case ATT_HL_LANE:
+ pseudo_header->atm.type = TRAF_LANE;
+ switch (frame4->atm_info.AppHLType) {
+
+ case AHLT_UNKNOWN:
+ pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
+ break;
+
+ case AHLT_LANE_LE_CTRL:
+ pseudo_header->atm.subtype =
+ TRAF_ST_LANE_LE_CTRL;
+ break;
+
+ case AHLT_LANE_802_3:
+ pseudo_header->atm.subtype = TRAF_ST_LANE_802_3;
+ break;
+
+ case AHLT_LANE_802_5:
+ pseudo_header->atm.subtype = TRAF_ST_LANE_802_5;
+ break;
+
+ case AHLT_LANE_802_3_MC:
+ pseudo_header->atm.subtype =
+ TRAF_ST_LANE_802_3_MC;
+ break;
+
+ case AHLT_LANE_802_5_MC:
+ pseudo_header->atm.subtype =
+ TRAF_ST_LANE_802_5_MC;
+ break;
+
+ default:
+ pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
+ break;
+ }
+ break;
+
+ case ATT_HL_ILMI:
+ pseudo_header->atm.type = TRAF_ILMI;
+ pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
+ break;
+
+ case ATT_HL_FRMR:
+ pseudo_header->atm.type = TRAF_FR;
+ pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
+ break;
+
+ case ATT_HL_SPANS:
+ pseudo_header->atm.type = TRAF_SPANS;
+ pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
+ break;
+
+ case ATT_HL_IPSILON:
+ pseudo_header->atm.type = TRAF_IPSILON;
+ switch (frame4->atm_info.AppHLType) {
+
+ case AHLT_UNKNOWN:
+ pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
+ break;
+
+ case AHLT_IPSILON_FT0:
+ pseudo_header->atm.subtype =
+ TRAF_ST_IPSILON_FT0;
+ break;
+
+ case AHLT_IPSILON_FT1:
+ pseudo_header->atm.subtype =
+ TRAF_ST_IPSILON_FT1;
+ break;
+
+ case AHLT_IPSILON_FT2:
+ pseudo_header->atm.subtype =
+ TRAF_ST_IPSILON_FT2;
+ break;
+
+ default:
+ pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
+ break;
+ }
+ break;
+
+ default:
+ pseudo_header->atm.type = TRAF_UNKNOWN;
+ pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
+ break;
+ }
+ break;
+
+ case ATT_AAL_USER:
+ pseudo_header->atm.aal = AAL_USER;
+ pseudo_header->atm.type = TRAF_UNKNOWN;
+ pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
+ break;
+
+ case ATT_AAL_SIGNALLING:
+ pseudo_header->atm.aal = AAL_SIGNALLING;
+ pseudo_header->atm.type = TRAF_UNKNOWN;
+ pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
+ break;
+
+ case ATT_OAMCELL:
+ pseudo_header->atm.aal = AAL_OAMCELL;
+ pseudo_header->atm.type = TRAF_UNKNOWN;
+ pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
+ break;
+
+ default:
+ pseudo_header->atm.aal = AAL_UNKNOWN;
+ pseudo_header->atm.type = TRAF_UNKNOWN;
+ pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
+ break;
+ }
+ pseudo_header->atm.vpi = vpi;
+ pseudo_header->atm.vci = vci;
+ pseudo_header->atm.channel = pletohs(&frame4->atm_info.channel);
+ pseudo_header->atm.cells = pletohs(&frame4->atm_info.cells);
+ pseudo_header->atm.aal5t_u2u = pletohs(&frame4->atm_info.Trailer.aal5t_u2u);
+ pseudo_header->atm.aal5t_len = pletohs(&frame4->atm_info.Trailer.aal5t_len);
+ pseudo_header->atm.aal5t_chksum = pntohl(&frame4->atm_info.Trailer.aal5t_chksum);
}
-static int ngsniffer_read_frame6(wtap *wth, gboolean is_random,
+static gboolean ngsniffer_read_frame6(wtap *wth, gboolean is_random,
struct frame6_rec *frame6, int *err)
{
int bytes_read;
if (bytes_read != sizeof *frame6) {
if (*err == 0)
*err = WTAP_ERR_SHORT_READ;
- return -1;
+ return FALSE;
}
- return 0;
+ return TRUE;
}
-static void set_pseudo_header_frame6(
- union wtap_pseudo_header *pseudo_header _U_,
+static void set_pseudo_header_frame6(wtap *wth,
+ union wtap_pseudo_header *pseudo_header,
struct frame6_rec *frame6 _U_)
{
/* XXX - Once the frame format is divined, something will most likely go here */
+
+ switch (wth->file_encap) {
+
+ case WTAP_ENCAP_ETHERNET:
+ /* XXX - is there an FCS? */
+ pseudo_header->eth.fcs_len = -1;
+ break;
+ }
}
-static int ngsniffer_read_rec_data(wtap *wth, gboolean is_random, u_char *pd,
- int length, int *err)
+static gboolean ngsniffer_read_rec_data(wtap *wth, gboolean is_random,
+ guchar *pd, int length, int *err)
{
int bytes_read;
if (bytes_read != length) {
if (*err == 0)
*err = WTAP_ERR_SHORT_READ;
- return -1;
+ return FALSE;
}
- return 0;
+ return TRUE;
}
-static void fix_pseudo_header(wtap *wth,
+/*
+ * OK, this capture is from an "Internetwork analyzer", and we either
+ * didn't see a type 7 record or it had a network type such as NET_HDLC
+ * that doesn't tell us which *particular* HDLC derivative this is;
+ * let's look at the first few bytes of the packet, a pointer to which
+ * was passed to us as an argument, and see whether it looks like PPP,
+ * Frame Relay, Wellfleet HDLC, Cisco HDLC, or LAPB - or, if it's none
+ * of those, assume it's LAPD.
+ *
+ * (XXX - are there any "Internetwork analyzer" captures that don't
+ * have type 7 records? If so, is there some other field that will
+ * tell us what type of capture it is?)
+ */
+static int infer_pkt_encap(const guint8 *pd, int len)
+{
+ int i;
+
+ if (len <= 0) {
+ /*
+ * Nothing to infer, but it doesn't matter how you
+ * dissect an empty packet. Let's just say PPP.
+ */
+ return WTAP_ENCAP_PPP_WITH_PHDR;
+ }
+
+ if (pd[0] == 0xFF) {
+ /*
+ * PPP. (XXX - check for 0xFF 0x03?)
+ */
+ return WTAP_ENCAP_PPP_WITH_PHDR;
+ }
+
+ if (len >= 2) {
+ if (pd[0] == 0x07 && pd[1] == 0x03) {
+ /*
+ * Wellfleet HDLC.
+ */
+ return WTAP_ENCAP_WFLEET_HDLC;
+ } else if ((pd[0] == 0x0F && pd[1] == 0x00) ||
+ (pd[0] == 0x8F && pd[1] == 0x00)) {
+ /*
+ * Cisco HDLC.
+ */
+ return WTAP_ENCAP_CHDLC_WITH_PHDR;
+ }
+
+ /*
+ * Check for Frame Relay. Look for packets with at least
+ * 3 bytes of header - 2 bytes of DLCI followed by 1 byte
+ * of control, which, for now, we require to be 0x03 (UI),
+ * although there might be other frame types as well.
+ * Scan forward until we see the last DLCI byte, with
+ * the low-order bit being 1, and then check the next
+ * byte to see if it's a control byte.
+ *
+ * XXX - in version 4 and 5 captures, wouldn't this just
+ * have a capture subtype of NET_FRAME_RELAY? Or is this
+ * here only to handle other versions of the capture
+ * file, where we might just not yet have found where
+ * the subtype is specified in the capture?
+ *
+ * Bay^H^H^HNortel Networks has a mechanism in the Optivity
+ * software for some of their routers to save captures
+ * in Sniffer format; they use a version number of 4.9, but
+ * don't put out any header records before the first FRAME2
+ * record. That means we have to use heuristics to guess
+ * what type of packet we have.
+ */
+ for (i = 0; i < len && (pd[i] & 0x01) == 0; i++)
+ ;
+ i++; /* advance to the byte after the last DLCI byte */
+ if (i == len) {
+ /*
+ * No control byte.
+ */
+ return WTAP_ENCAP_LAPB;
+ }
+ if (pd[i] == 0x03)
+ return WTAP_ENCAP_FRELAY_WITH_PHDR;
+ }
+
+ /*
+ * Assume LAPB, for now. If we support other HDLC encapsulations,
+ * we can check whether the low-order bit of the first byte is
+ * set (as it should be for LAPB) if no other checks pass.
+ *
+ * Or, if it's truly impossible to distinguish ISDN from non-ISDN
+ * captures, we could assume it's ISDN if it's not anything
+ * else.
+ */
+ return WTAP_ENCAP_LAPB;
+}
+
+static int fix_pseudo_header(int encap, const guint8 *pd, int len,
union wtap_pseudo_header *pseudo_header)
{
- switch (wth->file_encap) {
+ switch (encap) {
- case WTAP_ENCAP_LAPD:
- if (pseudo_header->x25.flags == 0x00)
- pseudo_header->p2p.sent = TRUE;
- else
- pseudo_header->p2p.sent = FALSE;
+ case WTAP_ENCAP_PER_PACKET:
+ /*
+ * Infer the packet type from the first two bytes.
+ */
+ encap = infer_pkt_encap(pd, len);
+
+ /*
+ * Fix up the pseudo-header to match the new
+ * encapsulation type.
+ */
+ switch (encap) {
+
+ case WTAP_ENCAP_WFLEET_HDLC:
+ case WTAP_ENCAP_CHDLC_WITH_PHDR:
+ case WTAP_ENCAP_PPP_WITH_PHDR:
+ if (pseudo_header->x25.flags == 0)
+ pseudo_header->p2p.sent = TRUE;
+ else
+ pseudo_header->p2p.sent = FALSE;
+ break;
+
+ case WTAP_ENCAP_ISDN:
+ if (pseudo_header->x25.flags == 0x00)
+ pseudo_header->isdn.uton = FALSE;
+ else
+ pseudo_header->isdn.uton = TRUE;
+
+ /*
+ * XXX - this is currently a per-packet
+ * encapsulation type, and we can't determine
+ * whether a capture is an ISDN capture before
+ * seeing any packets, and B-channel PPP packets
+ * look like PPP packets and are given
+ * WTAP_ENCAP_PPP_WITH_PHDR, not WTAP_ENCAP_ISDN,
+ * so we assume this is a D-channel packet and
+ * thus give it a channel number of 0.
+ */
+ pseudo_header->isdn.channel = 0;
+ break;
+ }
+ break;
+
+ case WTAP_ENCAP_ATM_PDUS:
+ /*
+ * If the Windows Sniffer writes out one of its ATM
+ * capture files in DOS Sniffer format, it doesn't
+ * distinguish between LE Control and LANE encapsulated
+ * LAN frames, it just marks them as LAN frames,
+ * so we fix that up here.
+ *
+ * I've also seen DOS Sniffer captures claiming that
+ * LANE packets that *don't* start with FF 00 are
+ * marked as LE Control frames, so we fix that up
+ * as well.
+ */
+ if (pseudo_header->atm.type == TRAF_LANE && len >= 2) {
+ if (pd[0] == 0xff && pd[1] == 0x00) {
+ /*
+ * This must be LE Control.
+ */
+ pseudo_header->atm.subtype =
+ TRAF_ST_LANE_LE_CTRL;
+ } else {
+ /*
+ * This can't be LE Control.
+ */
+ if (pseudo_header->atm.subtype ==
+ TRAF_ST_LANE_LE_CTRL) {
+ /*
+ * XXX - Ethernet or Token Ring?
+ */
+ pseudo_header->atm.subtype =
+ TRAF_ST_LANE_802_3;
+ }
+ }
+ }
break;
}
+ return encap;
}
/* Throw away the buffers used by the sequential I/O stream, but not
g_free(data);
}
+/* Close stuff used by the random I/O stream, if any, and free up any
+ private data structures. (If there's a "sequential_close" routine
+ for a capture file type, it'll be called before the "close" routine
+ is called, so we don't have to free the sequential buffer here.) */
static void ngsniffer_close(wtap *wth)
{
- if (wth->capture.ngsniffer->seq.buf != NULL)
- g_free(wth->capture.ngsniffer->seq.buf);
if (wth->capture.ngsniffer->rand.buf != NULL)
g_free(wth->capture.ngsniffer->rand.buf);
if (wth->capture.ngsniffer->first_blob != NULL) {
-1, /* WTAP_ENCAP_ATM_RFC1483 */
-1, /* WTAP_ENCAP_LINUX_ATM_CLIP */
7, /* WTAP_ENCAP_LAPB -> Internetwork analyzer (synchronous) */
- -1, /* WTAP_ENCAP_ATM_SNIFFER */
- -1 /* WTAP_ENCAP_NULL -> unsupported */
+ -1, /* WTAP_ENCAP_ATM_PDUS */
+ -1, /* WTAP_ENCAP_NULL -> unsupported */
+ -1, /* WTAP_ENCAP_ASCEND -> unsupported */
+ -1, /* WTAP_ENCAP_ISDN -> unsupported */
+ -1, /* WTAP_ENCAP_IP_OVER_FC -> unsupported */
+ 7, /* WTAP_ENCAP_PPP_WITH_PHDR -> Internetwork analyzer (synchronous) FIXME ! */
};
#define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
/* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
failure */
-gboolean ngsniffer_dump_open(wtap_dumper *wdh, int *err)
+gboolean ngsniffer_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err)
{
size_t nwritten;
char buf[6] = {REC_VERS, 0x00, 0x12, 0x00, 0x00, 0x00}; /* version record */
/* Write a record for a packet to a dump file.
Returns TRUE on success, FALSE on failure. */
static gboolean ngsniffer_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
- const union wtap_pseudo_header *pseudo_header, const u_char *pd, int *err)
+ const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err)
{
ngsniffer_dump_t *priv = wdh->dump.ngsniffer;
struct frame2_rec rec_hdr;
rec_hdr.time_med = htoles(t_med);
rec_hdr.time_high = htoles(t_high);
rec_hdr.size = htoles(phdr->caplen);
- if (wdh->encap == WTAP_ENCAP_LAPB || wdh->encap == WTAP_ENCAP_PPP)
- rec_hdr.fs = (pseudo_header->x25.flags & 0x80) ? 0x00 : 0x80;
+ if (wdh->encap == WTAP_ENCAP_LAPB || wdh->encap == WTAP_ENCAP_PPP_WITH_PHDR)
+ rec_hdr.fs = (pseudo_header->x25.flags & FROM_DCE) ? 0x00 : 0x80;
else
rec_hdr.fs = 0;
rec_hdr.flags = 0;
nwritten = fwrite(buf, 1, 6, wdh->fh);
if (nwritten != 6) {
- if (nwritten == 0 && ferror(wdh->fh))
- *err = errno;
- else
- *err = WTAP_ERR_SHORT_WRITE;
+ if (err != NULL) {
+ if (nwritten == 0 && ferror(wdh->fh))
+ *err = errno;
+ else
+ *err = WTAP_ERR_SHORT_WRITE;
+ }
return FALSE;
}
return TRUE;
Return value is the number of bytes in outbuf on return.
*/
static int
-SnifferDecompress( unsigned char * inbuf, size_t inlen,
+SnifferDecompress( unsigned char * inbuf, size_t inlen,
unsigned char * outbuf, size_t outlen, int *err )
{
unsigned char * pin = inbuf;
Run length is the low nybble of the first code byte.
Byte to repeat immediately follows.
Total code size: 2 bytes.
- */
+ */
length = code_low + 3;
/* If length would put us past end of output, avoid overflow */
if ( pout + length > pout_end )
break;
case 1 : /* RLE long runs */
/*
- Low 4 bits of run length is the low nybble of the
- first code byte, upper 8 bits of run length is in
+ Low 4 bits of run length is the low nybble of the
+ first code byte, upper 8 bits of run length is in
the next byte.
Byte to repeat immediately follows.
Total code size: 3 bytes.
- */
+ */
length = code_low + ((unsigned int)(*pin++) << 4) + 19;
/* If we are already at end of input, there is no byte
to repeat */
break;
case 2 : /* LZ77 long strings */
/*
- Low 4 bits of offset to string is the low nybble of the
- first code byte, upper 8 bits of offset is in
+ Low 4 bits of offset to string is the low nybble of the
+ first code byte, upper 8 bits of offset is in
the next byte.
Length of string immediately follows.
Total code size: 3 bytes.
- */
+ */
offset = code_low + ((unsigned int)(*pin++) << 4) + 3;
/* If we are already at end of input, there is no byte
to repeat */
break;
default : /* (3 to 15): LZ77 short strings */
/*
- Low 4 bits of offset to string is the low nybble of the
- first code byte, upper 8 bits of offset is in
+ Low 4 bits of offset to string is the low nybble of the
+ first code byte, upper 8 bits of offset is in
the next byte.
Length of string to repeat is overloaded into code_type.
Total code size: 2 bytes.
- */
+ */
offset = code_low + ((unsigned int)(*pin++) << 4) + 3;
/* Check if offset would put us back past begin of buffer */
if ( pout - offset < outbuf )
return -1;
bytes_left = comp_stream->nbytes - comp_stream->nextout;
}
-
+
bytes_to_copy = copybytes;
if (bytes_to_copy > bytes_left)
bytes_to_copy = bytes_left;
static long
ng_file_seek_seq(wtap *wth, long offset, int whence, int *err)
{
- long ret;
long delta;
char buf[65536];
long amount_to_read;
- if (wth->file_type == WTAP_FILE_NGSNIFFER_UNCOMPRESSED) {
- ret = file_seek(wth->fh, offset, whence);
- if (ret == -1)
- *err = file_error(wth->fh);
- return ret;
- }
+ if (wth->file_type == WTAP_FILE_NGSNIFFER_UNCOMPRESSED)
+ return file_seek(wth->fh, offset, whence, err);
switch (whence) {
static long
ng_file_seek_rand(wtap *wth, long offset, int whence, int *err)
{
- long ret;
ngsniffer_t *ngsniffer;
long delta;
GList *new, *next;
blob_info_t *next_blob, *new_blob;
- if (wth->file_type == WTAP_FILE_NGSNIFFER_UNCOMPRESSED) {
- ret = file_seek(wth->random_fh, offset, whence);
- if (ret == -1)
- *err = file_error(wth->random_fh);
- return ret;
- }
+ if (wth->file_type == WTAP_FILE_NGSNIFFER_UNCOMPRESSED)
+ return file_seek(wth->random_fh, offset, whence, err);
ngsniffer = wth->capture.ngsniffer;
if (delta > 0) {
/* We're going forwards.
Is the place to which we're seeking within the current buffer? */
- if ((unsigned)ngsniffer->rand.nextout + delta >= ngsniffer->rand.nbytes) {
+ if ((size_t)(ngsniffer->rand.nextout + delta) >= ngsniffer->rand.nbytes) {
/* No. Search for a blob that contains the target offset in
the uncompressed byte stream, starting with the blob
following the current blob. */
/* Seek in the compressed file to the offset in the compressed file
of the beginning of that blob. */
- if (file_seek(wth->random_fh, new_blob->blob_comp_offset, SEEK_SET) == -1) {
- *err = file_error(wth->random_fh);
+ if (file_seek(wth->random_fh, new_blob->blob_comp_offset, SEEK_SET, err) == -1)
return -1;
- }
/* Make the blob we found the current one. */
ngsniffer->current_blob = new;