aboutsummaryrefslogtreecommitdiffstats
path: root/wiretap/netmon.c
diff options
context:
space:
mode:
Diffstat (limited to 'wiretap/netmon.c')
-rw-r--r--wiretap/netmon.c166
1 files changed, 125 insertions, 41 deletions
diff --git a/wiretap/netmon.c b/wiretap/netmon.c
index d6e68a885c..2178bc0699 100644
--- a/wiretap/netmon.c
+++ b/wiretap/netmon.c
@@ -37,7 +37,9 @@
* ftp://ftp.microsoft.com/developr/drg/cifs/cifs/Bhfile.zip
*
* contains "STRUCT.H", which declares the typedef CAPTUREFILE_HEADER
- * for the header of a Microsoft Network Monitor capture file.
+ * for the header of a Microsoft Network Monitor 1.x capture file.
+ *
+ * The help files for Network Monitor 3.x document the 2.x file format.
*/
/* Capture file header, *including* magic number, is padded to 128 bytes. */
@@ -86,11 +88,12 @@ struct netmonrec_1_x_hdr {
guint16 incl_len; /* number of octets captured in file */
};
-/* Network Monitor 2.x record header; not defined in STRUCT.H, but deduced by
- * looking at capture files. */
+/*
+ * Network Monitor 2.x record header, as documented in NetMon 3.x's
+ * help files.
+ */
struct netmonrec_2_x_hdr {
- guint32 ts_delta_lo; /* time stamp - usecs since start of capture */
- guint32 ts_delta_hi; /* time stamp - usecs since start of capture */
+ guint64 ts_delta; /* time stamp - tenths of usecs since start of capture */
guint32 orig_len; /* actual length of packet */
guint32 incl_len; /* number of octets captured in file */
};
@@ -131,7 +134,7 @@ struct netmon_atm_hdr {
typedef struct {
time_t start_secs;
- guint32 start_usecs;
+ guint32 start_nsecs;
guint8 version_major;
guint8 version_minor;
guint32 *frame_table;
@@ -298,7 +301,7 @@ int netmon_open(wtap *wth, int *err, gchar **err_info)
* intervals since 1601-01-01 00:00:00 "UTC", there, instead
* of stuffing a SYSTEMTIME, which is time-zone-dependent, there?).
*/
- netmon->start_usecs = pletohs(&hdr.ts_msec)*1000;
+ netmon->start_nsecs = pletohs(&hdr.ts_msec)*1000000;
netmon->version_major = hdr.ver_major;
netmon->version_minor = hdr.ver_minor;
@@ -363,8 +366,26 @@ int netmon_open(wtap *wth, int *err, gchar **err_info)
/* Set up to start reading at the first frame. */
netmon->current_frame = 0;
- wth->tsprecision = WTAP_FILE_TSPREC_USEC;
+ switch (netmon->version_major) {
+ case 1:
+ /*
+ * Version 1.x of the file format supports
+ * millisecond precision.
+ */
+ wth->tsprecision = WTAP_FILE_TSPREC_MSEC;
+ break;
+
+ case 2:
+ /*
+ * Version 1.x of the file format supports
+ * 100-nanosecond precision; we don't
+ * currently support that, so say
+ * "nanosecond precision" for now.
+ */
+ wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
+ break;
+ }
return 1;
}
@@ -445,9 +466,9 @@ static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
int rec_offset;
guint8 *data_ptr;
gint64 delta = 0; /* signed - frame times can be before the nominal start */
+ gint64 t;
time_t secs;
- guint32 usecs;
- double t;
+ guint32 nsecs;
again:
/* Have we reached the end of the packet data? */
@@ -569,7 +590,6 @@ again:
return FALSE; /* Read error */
wth->data_offset += packet_size;
- t = (double)netmon->start_usecs;
switch (netmon->version_major) {
case 1:
@@ -577,25 +597,68 @@ again:
* According to Paul Long, this offset is unsigned.
* It's 32 bits, so the maximum value will fit in
* a gint64 such as delta, even after multiplying
- * it by 1000.
+ * it by 1000000.
*
* pletohl() returns a guint32; we cast it to gint64
* before multiplying, so that the product doesn't
* overflow a guint32.
*/
- delta = ((gint64)pletohl(&hdr.hdr_1_x.ts_delta))*1000;
+ delta = ((gint64)pletohl(&hdr.hdr_1_x.ts_delta))*1000000;
break;
case 2:
- delta = pletohl(&hdr.hdr_2_x.ts_delta_lo)
- | (((guint64)pletohl(&hdr.hdr_2_x.ts_delta_hi)) << 32);
+ /*
+ * OK, this is weird. Microsoft's documentation
+ * says this is in microseconds and is a 64-bit
+ * unsigned number, but it can be negative; they
+ * say what appears to amount to "treat it as an
+ * unsigned number, multiply it by 10, and then
+ * interpret the resulting 64-bit quantity as a
+ * signed number". That operation can turn a
+ * value with the uppermost bit 0 to a value with
+ * the uppermost bit 1, hence turning a large
+ * positive number-of-microseconds into a small
+ * negative number-of-100-nanosecond-increments.
+ */
+ delta = pletohll(&hdr.hdr_2_x.ts_delta)*10;
+
+ /*
+ * OK, it's now a signed value in 100-nanosecond
+ * units. Now convert it to nanosecond units.
+ */
+ delta *= 100;
break;
}
- t += (double)delta;
- secs = (time_t)(t/1000000);
- usecs = (guint32)(t - (double)secs*1000000);
+ secs = 0;
+ t = netmon->start_nsecs + delta;
+ while (t < 0) {
+ /*
+ * Propagate a borrow into the seconds.
+ * The seconds is a time_t, and can be < 0
+ * (unlikely, as Windows didn't exist before
+ * January 1, 1970, 00:00:00 UTC), while the
+ * nanoseconds should be positive, as in
+ * "nanoseconds since the instant of time
+ * represented by the seconds".
+ *
+ * We do not want t to be negative, as, according
+ * to the C90 standard, "if either operand [of /
+ * or %] is negative, whether the result of the
+ * / operator is the largest integer less than or
+ * equal to the algebraic quotient or the smallest
+ * greater than or equal to the algebraic quotient
+ * is implementation-defined, as is the sign of
+ * the result of the % operator", and we want
+ * the result of the division and remainder
+ * operations to be the same on all platforms.
+ */
+ t += 1000000000;
+ secs--;
+ }
+ secs += (time_t)(t/1000000000);
+ nsecs = (guint32)(t%1000000000);
wth->phdr.ts.secs = netmon->start_secs + secs;
- wth->phdr.ts.nsecs = usecs * 1000;
+ wth->phdr.ts.nsecs = nsecs;
wth->phdr.caplen = packet_size;
wth->phdr.len = orig_size;
@@ -914,17 +977,24 @@ static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
struct netmonrec_2_x_hdr rec_2_x_hdr;
char *hdrp;
size_t hdr_size;
- double t;
- guint32 time_low, time_high;
struct netmon_atm_hdr atm_hdr;
int atm_hdrsize;
+ gint64 secs;
+ gint32 nsecs;
- /* NetMon files have a capture start time in the file header,
- and have times relative to that in the packet headers;
- pick the time of the first packet as the capture start
- time. */
+ /*
+ * NetMon files have a capture start time in the file header,
+ * and have times relative to that in the packet headers;
+ * pick the time of the first packet as the capture start
+ * time.
+ *
+ * That time has millisecond resolution, so chop any
+ * sub-millisecond part of the time stamp off.
+ */
if (!netmon->got_first_record_time) {
- netmon->first_record_time = phdr->ts;
+ netmon->first_record_time.secs = phdr->ts.secs;
+ netmon->first_record_time.nsecs =
+ (phdr->ts.nsecs/1000000)*1000000;
netmon->got_first_record_time = TRUE;
}
@@ -932,12 +1002,37 @@ static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
atm_hdrsize = sizeof (struct netmon_atm_hdr);
else
atm_hdrsize = 0;
+ secs = (gint64)(phdr->ts.secs - netmon->first_record_time.secs);
+ nsecs = phdr->ts.nsecs - netmon->first_record_time.nsecs;
+ while (nsecs < 0) {
+ /*
+ * Propagate a borrow into the seconds.
+ * The seconds is a time_t, and can be < 0
+ * (unlikely, as neither UN*X nor DOS
+ * nor the original Mac System existed
+ * before January 1, 1970, 00:00:00 UTC),
+ * while the nanoseconds should be positive,
+ * as in "nanoseconds since the instant of time
+ * represented by the seconds".
+ *
+ * We do not want t to be negative, as, according
+ * to the C90 standard, "if either operand [of /
+ * or %] is negative, whether the result of the
+ * / operator is the largest integer less than or
+ * equal to the algebraic quotient or the smallest
+ * greater than or equal to the algebraic quotient
+ * is implementation-defined, as is the sign of
+ * the result of the % operator", and we want
+ * the result of the division and remainder
+ * operations to be the same on all platforms.
+ */
+ nsecs += 1000000000;
+ secs--;
+ }
switch (wdh->file_type) {
case WTAP_FILE_NETMON_1_x:
- rec_1_x_hdr.ts_delta = htolel(
- (phdr->ts.secs - netmon->first_record_time.secs)*1000
- + (phdr->ts.nsecs - netmon->first_record_time.nsecs + 500000)/1000000);
+ rec_1_x_hdr.ts_delta = htolel(secs*1000 + (nsecs + 500000)/1000000);
rec_1_x_hdr.orig_len = htoles(phdr->len + atm_hdrsize);
rec_1_x_hdr.incl_len = htoles(phdr->caplen + atm_hdrsize);
hdrp = (char *)&rec_1_x_hdr;
@@ -945,18 +1040,7 @@ static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
break;
case WTAP_FILE_NETMON_2_x:
- /*
- * Unfortunately, not all the platforms on which we run
- * support 64-bit integral types, even though most do
- * (even on 32-bit processors), so we do it in floating
- * point.
- */
- t = (phdr->ts.secs - netmon->first_record_time.secs)*1000000.0
- + (phdr->ts.nsecs - netmon->first_record_time.nsecs) / 1000;
- time_high = (guint32) (t/4294967296.0);
- time_low = (guint32) (t - (time_high*4294967296.0));
- rec_2_x_hdr.ts_delta_lo = htolel(time_low);
- rec_2_x_hdr.ts_delta_hi = htolel(time_high);
+ rec_2_x_hdr.ts_delta = htolell(secs*1000000 + (nsecs + 500)/1000);
rec_2_x_hdr.orig_len = htolel(phdr->len + atm_hdrsize);
rec_2_x_hdr.incl_len = htolel(phdr->caplen + atm_hdrsize);
hdrp = (char *)&rec_2_x_hdr;