aboutsummaryrefslogtreecommitdiffstats
path: root/wiretap/netmon.c
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2011-11-16 17:54:44 +0000
committerGuy Harris <guy@alum.mit.edu>2011-11-16 17:54:44 +0000
commit8281a7d28ef400e807ed272e64f889623cbbf9c3 (patch)
tree71ad72f63dcafe0697e56ed3e37ee7d551a1a733 /wiretap/netmon.c
parent234d0b96149301f662680b4143eb3e63de0dcdcb (diff)
Support nanosecond-resolution time for NetMon 2.x format (it's only
100-nanosecond resolution, but that's still better than microsecond resolution). For NetMon 1.x format, only claim to support millisecond resolution, as that's all you get. Fix handling of negative time deltas in NetMon 2.x format. When writing a NetMon file, trim the time of the first packet to millisecond precision to get the capture start time, so that the start time written to the file (which has millisecond precision) is the same as the start time used to calculate the deltas written to the packet headers. svn path=/trunk/; revision=39886
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;