Ethereal-users: Re: [ethereal-users] Problem reading a capture produced by MS Netmon 5.00.646

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Guy Harris <gharris@xxxxxxxxxxxx>
Date: Tue, 21 Mar 2000 22:57:52 -0800
> There are some Network Monitor 2 capture files that are in a very odd
> format; Tim Farley has some guesses what it might be, but we've yet to
> figure out the right way of detecting whether the file is in the
> standard format or in that format, or to figure out a way to make the
> code read both of those files correctly.
> 
> This may be one of those files.

It's not, fortunately.

I have a patch that, by using the table of offsets into the file of the
frames in a Network Monitor capture, appears to let me read your capture
file as well as to read many of the normal NetMon captures I've seen (I
haven't tried it on all the ones I have lying around, but it seems to
work on a reasonable sample of them).

It'll probably do worse than the current code on the weird files, but
that's life - the current code doesn't work right on them, either, past
a certain point in the file, and it's not clear whether those are actual
save files from NetMon or temporary files that somebody grabbed and that
might not even work right if handed to NetMon....

I've attached the patch; it should be applied to the Ethereal source, in
the "wiretap" directory.  It patches a fair number of files, as I had to
add support for per-capture-file-type close routines in order to free
the mallocated table of frame offsets, and figured that, as long as I'd
done that, I might as well make all the other capture types that had
private data use it as well.

Note that, sometimes, NetMon sticks an extra frame at the end, which
appears to be an LLC frame with the encapsulated-Ethernet OUI and an
Ethernet type of 0x1984, and a frame arrival time that I suspect is the
time the capture started, where the data contains some statistics on the
capture; NetMon appears to dissect it, based on the frame 715 dissection
in the text file you sent, but Ethereal doesn't, so there may be a
bogus-appearing frame at the end of your capture - that's the summary
statistics frame.

I'll check this patch into the CVS tree.
Index: netmon.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/wiretap/netmon.c,v
retrieving revision 1.25
diff -c -r1.25 netmon.c
*** netmon.c	2000/02/19 08:00:05	1.25
--- netmon.c	2000/03/22 06:45:27
***************
*** 95,100 ****
--- 95,101 ----
  };
  
  static int netmon_read(wtap *wth, int *err);
+ static void netmon_close(wtap *wth);
  static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
      const u_char *pd, int *err);
  static gboolean netmon_dump_close(wtap_dumper *wdh, int *err);
***************
*** 121,128 ****
  	};
  	#define NUM_NETMON_ENCAPS (sizeof netmon_encap / sizeof netmon_encap[0])
  	struct tm tm;
  	guint32 frame_table_length;
- 	guint32 first_frame_table_entry;
  
  	/* Read in the string that should be at the start of a Network
  	 * Monitor file */
--- 122,129 ----
  	};
  	#define NUM_NETMON_ENCAPS (sizeof netmon_encap / sizeof netmon_encap[0])
  	struct tm tm;
+ 	int frame_table_offset;
  	guint32 frame_table_length;
  
  	/* Read in the string that should be at the start of a Network
  	 * Monitor file */
***************
*** 180,185 ****
--- 181,187 ----
  	wth->file_type = file_type;
  	wth->capture.netmon = g_malloc(sizeof(netmon_t));
  	wth->subtype_read = netmon_read;
+ 	wth->subtype_close = netmon_close;
  	wth->file_encap = netmon_encap[hdr.network];
  	wth->snapshot_length = 16384;	/* XXX - not available in header */
  	/*
***************
*** 213,260 ****
  	wth->capture.netmon->version_major = hdr.ver_major;
  
  	/*
! 	 * The "frame index table" appears to come after the last
! 	 * packet; remember its offset, so we know when we have no
! 	 * more packets to read.
  	 */
! 	wth->capture.netmon->end_offset = pletohl(&hdr.frametableoffset);
  
  	/*
  	 * It appears that some NetMon 2.x files don't have the
  	 * first packet starting exactly 128 bytes into the file.
- 	 * So we read the first entry from the frame table, and
- 	 * use that as the offset of the first packet.
  	 *
! 	 * First, make sure the frame table has at least one entry
! 	 * in it....
  	 */
  	frame_table_length = pletohl(&hdr.frametablelength);
! 	if (frame_table_length < sizeof first_frame_table_entry) {
  		g_message("netmon: frame table length is %u, which means it's less than one entry in size",
  		    frame_table_length);
  		*err = WTAP_ERR_UNSUPPORTED;
  		return -1;
  	}
! 
! 	/*
! 	 * Now read that entry.  (It appears that the N+1st frame immediately
! 	 * follows the Nth frame, so we don't need any entries after the
! 	 * first entry.)
! 	 */
  	errno = WTAP_ERR_CANT_READ;
! 	file_seek(wth->fh, wth->capture.netmon->end_offset, SEEK_SET);
! 	bytes_read = file_read(&first_frame_table_entry, 1,
! 	    sizeof first_frame_table_entry, wth->fh);
! 	if (bytes_read != sizeof first_frame_table_entry) {
  		*err = file_error(wth->fh);
  		if (*err != 0)
  			return -1;
  		return 0;
  	}
  
! 	/* Seek to the beginning of the data records. */
! 	wth->data_offset = pletohl(&first_frame_table_entry);
! 	file_seek(wth->fh, wth->data_offset, SEEK_SET);
  
  	return 1;
  }
--- 215,263 ----
  	wth->capture.netmon->version_major = hdr.ver_major;
  
  	/*
! 	 * Get the offset of the frame index table.
  	 */
! 	frame_table_offset = pletohl(&hdr.frametableoffset);
  
  	/*
  	 * It appears that some NetMon 2.x files don't have the
  	 * first packet starting exactly 128 bytes into the file.
  	 *
! 	 * Furthermore, it also appears that there are "holes" in
! 	 * the file, i.e. frame N+1 doesn't always follow immediately
! 	 * after frame N.
! 	 *
! 	 * Therefore, we must read the frame table, and use the offsets
! 	 * in it as the offsets of the frames.
  	 */
  	frame_table_length = pletohl(&hdr.frametablelength);
! 	wth->capture.netmon->frame_table_size = frame_table_length / sizeof (guint32);
! 	if ((wth->capture.netmon->frame_table_size * sizeof (guint32)) != frame_table_length) {
! 		g_message("netmon: frame table length is %u, which is not a multiple of the size of an entry",
! 		    frame_table_length);
! 		*err = WTAP_ERR_UNSUPPORTED;
! 		return -1;
! 	}
! 	if (wth->capture.netmon->frame_table_size == 0) {
  		g_message("netmon: frame table length is %u, which means it's less than one entry in size",
  		    frame_table_length);
  		*err = WTAP_ERR_UNSUPPORTED;
  		return -1;
  	}
! 	wth->capture.netmon->frame_table = g_malloc(frame_table_length);
  	errno = WTAP_ERR_CANT_READ;
! 	file_seek(wth->fh, frame_table_offset, SEEK_SET);
! 	bytes_read = file_read(wth->capture.netmon->frame_table, 1,
! 	    frame_table_length, wth->fh);
! 	if (bytes_read != frame_table_length) {
  		*err = file_error(wth->fh);
  		if (*err != 0)
  			return -1;
  		return 0;
  	}
  
! 	/* Set up to start reading at the first frame. */
! 	wth->capture.netmon->current_frame = 0;
  
  	return 1;
  }
***************
*** 262,267 ****
--- 265,271 ----
  /* Read the next packet */
  static int netmon_read(wtap *wth, int *err)
  {
+ 	netmon_t *netmon = wth->capture.netmon;
  	guint32	packet_size = 0;
  	int	bytes_read;
  	union {
***************
*** 275,286 ****
  	double	t;
  
  	/* Have we reached the end of the packet data? */
! 	if (wth->data_offset >= wth->capture.netmon->end_offset) {
  		/* Yes. */
  		return 0;
  	}
  	/* Read record header. */
! 	switch (wth->capture.netmon->version_major) {
  
  	case 1:
  		hdr_size = sizeof (struct netmonrec_1_x_hdr);
--- 279,302 ----
  	double	t;
  
  	/* Have we reached the end of the packet data? */
! 	if (netmon->current_frame >= netmon->frame_table_size) {
  		/* Yes. */
  		return 0;
  	}
+ 
+ 	/* Seek to the beginning of the current record, if we're
+ 	   not there already (seeking to the current position
+ 	   may still cause a seek and a read of the underlying file,
+ 	   so we don't want to do it unconditionally). */
+ 	data_offset = netmon->frame_table[netmon->current_frame];
+ 	if (wth->data_offset != data_offset) {
+ 		wth->data_offset = data_offset;
+ 		file_seek(wth->fh, wth->data_offset, SEEK_SET);
+ 	}
+ 	netmon->current_frame++;
+ 
  	/* Read record header. */
! 	switch (netmon->version_major) {
  
  	case 1:
  		hdr_size = sizeof (struct netmonrec_1_x_hdr);
***************
*** 291,296 ****
--- 307,313 ----
  		break;
  	}
  	errno = WTAP_ERR_CANT_READ;
+ 
  	bytes_read = file_read(&hdr, 1, hdr_size, wth->fh);
  	if (bytes_read != hdr_size) {
  		*err = file_error(wth->fh);
***************
*** 304,310 ****
  	}
  	wth->data_offset += hdr_size;
  
! 	switch (wth->capture.netmon->version_major) {
  
  	case 1:
  		packet_size = pletohs(&hdr.hdr_1_x.incl_len);
--- 321,327 ----
  	}
  	wth->data_offset += hdr_size;
  
! 	switch (netmon->version_major) {
  
  	case 1:
  		packet_size = pletohs(&hdr.hdr_1_x.incl_len);
***************
*** 338,345 ****
  	}
  	wth->data_offset += packet_size;
  
! 	t = (double)wth->capture.netmon->start_usecs;
! 	switch (wth->capture.netmon->version_major) {
  
  	case 1:
  		t += ((double)pletohl(&hdr.hdr_1_x.ts_delta))*1000;
--- 355,362 ----
  	}
  	wth->data_offset += packet_size;
  
! 	t = (double)netmon->start_usecs;
! 	switch (netmon->version_major) {
  
  	case 1:
  		t += ((double)pletohl(&hdr.hdr_1_x.ts_delta))*1000;
***************
*** 352,361 ****
  	}
  	secs = (time_t)(t/1000000);
  	usecs = (guint32)(t - secs*1000000);
! 	wth->phdr.ts.tv_sec = wth->capture.netmon->start_secs + secs;
  	wth->phdr.ts.tv_usec = usecs;
  	wth->phdr.caplen = packet_size;
! 	switch (wth->capture.netmon->version_major) {
  
  	case 1:
  		wth->phdr.len = pletohs(&hdr.hdr_1_x.orig_len);
--- 369,378 ----
  	}
  	secs = (time_t)(t/1000000);
  	usecs = (guint32)(t - secs*1000000);
! 	wth->phdr.ts.tv_sec = netmon->start_secs + secs;
  	wth->phdr.ts.tv_usec = usecs;
  	wth->phdr.caplen = packet_size;
! 	switch (netmon->version_major) {
  
  	case 1:
  		wth->phdr.len = pletohs(&hdr.hdr_1_x.orig_len);
***************
*** 368,373 ****
--- 385,397 ----
  	wth->phdr.pkt_encap = wth->file_encap;
  
  	return data_offset;
+ }
+ 
+ static void
+ netmon_close(wtap *wth)
+ {
+ 	g_free(wth->capture.netmon->frame_table);
+ 	g_free(wth->capture.netmon);
  }
  
  static const int wtap_encap[] = {
Index: netxray.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/wiretap/netxray.c,v
retrieving revision 1.24
diff -c -r1.24 netxray.c
*** netxray.c	2000/02/19 08:00:04	1.24
--- netxray.c	2000/03/22 06:45:29
***************
*** 91,96 ****
--- 91,97 ----
  };
  
  static int netxray_read(wtap *wth, int *err);
+ static void netxray_close(wtap *wth);
  static gboolean netxray_dump_1_1(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
  	const u_char *pd, int *err);
  static gboolean netxray_dump_close_1_1(wtap_dumper *wdh, int *err);
***************
*** 186,191 ****
--- 187,193 ----
  	wth->file_type = file_type;
  	wth->capture.netxray = g_malloc(sizeof(netxray_t));
  	wth->subtype_read = netxray_read;
+ 	wth->subtype_close = netxray_close;
  	wth->file_encap = netxray_encap[hdr.network];
  	wth->snapshot_length = 16384;	/* XXX - not available in header */
  	wth->capture.netxray->start_time = pletohl(&hdr.start_time);
***************
*** 293,298 ****
--- 295,306 ----
  	wth->phdr.pkt_encap = wth->file_encap;
  
  	return data_offset;
+ }
+ 
+ static void
+ netxray_close(wtap *wth)
+ {
+ 	g_free(wth->capture.netxray);
  }
  
  static const int wtap_encap[] = {
Index: wtap.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/wiretap/wtap.c,v
retrieving revision 1.37
diff -c -r1.37 wtap.c
*** wtap.c	2000/01/22 06:22:44	1.37
--- wtap.c	2000/03/22 06:45:29
***************
*** 151,157 ****
  	"File contains record data we don't support",
  	NULL,
  	"Files can't be saved in that format",
! 	"Files from that network type can't be saved in that format",
  	"That format doesn't support per-packet encapsulations",
  	NULL,
  	NULL,
--- 151,157 ----
  	"File contains record data we don't support",
  	NULL,
  	"Files can't be saved in that format",
! 	"Files in that format can't be read or saved with that network type",
  	"That format doesn't support per-packet encapsulations",
  	NULL,
  	NULL,
***************
*** 189,238 ****
  
  void wtap_close(wtap *wth)
  {
! 	/* free up memory. If any capture structure ever allocates
! 	 * its own memory, it would be better to make a *close() function
! 	 * for each filetype, like pcap_close(0, lanalyzer_close(), etc.
! 	 * But for now this will work. */
! 	switch(wth->file_type) {
! 		case WTAP_FILE_PCAP:
! 		case WTAP_FILE_PCAP_MODIFIED:
! 			g_free(wth->capture.pcap);
! 			break;
! 
! 		case WTAP_FILE_LANALYZER:
! 			g_free(wth->capture.lanalyzer);
! 			break;
! 
! 		case WTAP_FILE_NGSNIFFER:
! 			g_free(wth->capture.ngsniffer);
! 			break;
! 
! 		case WTAP_FILE_RADCOM:
! 			g_free(wth->capture.radcom);
! 			break;
! 
! 		case WTAP_FILE_NETMON_1_x:
! 		case WTAP_FILE_NETMON_2_x:
! 			g_free(wth->capture.netmon);
! 			break;
! 
! 		case WTAP_FILE_NETXRAY_1_0:
! 		case WTAP_FILE_NETXRAY_1_1:
! 		case WTAP_FILE_NETXRAY_2_001:
! 			g_free(wth->capture.netxray);
! 			break;
! 
! 		case WTAP_FILE_ASCEND:
! 			g_free(wth->capture.ascend);
! 			break;
! 
! 		case WTAP_FILE_NETTL:
! 			g_free(wth->capture.nettl);
! 			break;
! 
! 		/* default:
! 			 nothing */
! 	}
  
  	file_close(wth->fh);
  
--- 189,196 ----
  
  void wtap_close(wtap *wth)
  {
! 	if (wth->subtype_close != NULL)
! 		(*wth->subtype_close)(wth);
  
  	file_close(wth->fh);
  
Index: nettl.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/wiretap/nettl.c,v
retrieving revision 1.8
diff -c -r1.8 nettl.c
*** nettl.c	2000/03/01 10:25:14	1.8
--- nettl.c	2000/03/22 06:45:29
***************
*** 67,72 ****
--- 67,73 ----
  /* header is followed by data and once again the total length (2 bytes) ! */
  
  static int nettl_read(wtap *wth, int *err);
+ static void nettl_close(wtap *wth);
  
  int nettl_open(wtap *wth, int *err)
  {
***************
*** 110,115 ****
--- 111,117 ----
      wth->file_type = WTAP_FILE_NETTL;
      wth->capture.nettl = g_malloc(sizeof(nettl_t));
      wth->subtype_read = nettl_read;
+     wth->subtype_close = nettl_close;
      wth->snapshot_length = 16384;	/* not available in header, only in frame */
  
      wth->capture.nettl->start = 0;
***************
*** 267,270 ****
--- 269,277 ----
  	return -1;
      }
      return data_offset;
+ }
+ 
+ static void nettl_close(wtap *wth)
+ {
+     g_free(wth->capture.nettl);
  }
Index: ascend.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/wiretap/ascend.c,v
retrieving revision 1.12
diff -c -r1.12 ascend.c
*** ascend.c	2000/01/22 06:22:35	1.12
--- ascend.c	2000/03/22 06:45:30
***************
*** 82,87 ****
--- 82,88 ----
  #define ASCEND_W2_SIZE (sizeof ascend_w2magic / sizeof ascend_w2magic[0])
  
  static int ascend_read(wtap *wth, int *err);
+ static void ascend_close(wtap *wth);
  
  /* Seeks to the beginning of the next packet, and returns the
     byte offset.  Returns -1 on failure.  A valid offset is 0; since
***************
*** 149,154 ****
--- 150,156 ----
    wth->file_type = WTAP_FILE_ASCEND;
    wth->snapshot_length = ASCEND_MAX_PKT_LEN;
    wth->subtype_read = ascend_read;
+   wth->subtype_close = ascend_close;
    wth->capture.ascend = g_malloc(sizeof(ascend_t));
  
    /* MAXen and Pipelines report the time since reboot.  In order to keep 
***************
*** 211,214 ****
--- 213,221 ----
  {
    file_seek(fh, seek_off - 1, SEEK_SET);
    return parse_ascend(fh, pd, NULL, NULL, len);
+ }
+ 
+ static void ascend_close(wtap *wth)
+ {
+   g_free(wth->capture.ascend);
  }
Index: radcom.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/wiretap/radcom.c,v
retrieving revision 1.18
diff -c -r1.18 radcom.c
*** radcom.c	2000/02/19 08:00:04	1.18
--- radcom.c	2000/03/22 06:45:31
***************
*** 68,73 ****
--- 68,74 ----
  };
  
  static int radcom_read(wtap *wth, int *err);
+ static void radcom_close(wtap *wth);
  
  int radcom_open(wtap *wth, int *err)
  {
***************
*** 135,140 ****
--- 136,142 ----
  	wth->file_type = WTAP_FILE_RADCOM;
  	wth->capture.radcom = g_malloc(sizeof(radcom_t));
  	wth->subtype_read = radcom_read;
+ 	wth->subtype_close = radcom_close;
  	wth->snapshot_length = 16384;	/* not available in header, only in frame */
  
  	tm.tm_year = pletohs(&start_date.year)-1900;
***************
*** 300,303 ****
--- 302,311 ----
  	}
  
  	return data_offset;
+ }
+ 
+ static void
+ radcom_close(wtap *wth)
+ {
+ 	g_free(wth->capture.radcom);
  }
Index: ngsniffer.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/wiretap/ngsniffer.c,v
retrieving revision 1.36
diff -c -r1.36 ngsniffer.c
*** ngsniffer.c	2000/02/19 08:00:07	1.36
--- ngsniffer.c	2000/03/22 06:45:32
***************
*** 247,252 ****
--- 247,253 ----
  static double Usec[] = { 15.0, 0.838096, 15.0, 0.5, 2.0, 1.0, 0.1 };
  
  static int ngsniffer_read(wtap *wth, int *err);
+ static void ngsniffer_close(wtap *wth);
  static gboolean ngsniffer_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
  	const u_char *pd, int *err);
  static gboolean ngsniffer_dump_close(wtap_dumper *wdh, int *err);
***************
*** 370,375 ****
--- 371,377 ----
  	wth->file_type = WTAP_FILE_NGSNIFFER;
  	wth->capture.ngsniffer = g_malloc(sizeof(ngsniffer_t));
  	wth->subtype_read = ngsniffer_read;
+ 	wth->subtype_close = ngsniffer_close;
  	wth->snapshot_length = 16384;	/* not available in header, only in frame */
  	wth->capture.ngsniffer->timeunit = Usec[version.timeunit];
  	wth->file_encap = sniffer_encap[version.network];
***************
*** 636,641 ****
--- 638,649 ----
  			*1.0e6);
  	wth->phdr.pkt_encap = wth->file_encap;
  	return data_offset;
+ }
+ 
+ static void
+ ngsniffer_close(wtap *wth)
+ {
+ 	g_free(wth->capture.ngsniffer);
  }
  
  static const int wtap_encap[] = {
Index: lanalyzer.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/wiretap/lanalyzer.c,v
retrieving revision 1.20
diff -c -r1.20 lanalyzer.c
*** lanalyzer.c	2000/01/22 06:22:38	1.20
--- lanalyzer.c	2000/03/22 06:45:33
***************
*** 49,54 ****
--- 49,55 ----
  #define BOARD_325TR		227	/* LANalyzer 325TR (Token-ring) */
  
  static int lanalyzer_read(wtap *wth, int *err);
+ static void lanalyzer_close(wtap *wth);
  
  int lanalyzer_open(wtap *wth, int *err)
  {
***************
*** 86,91 ****
--- 87,93 ----
  	wth->file_type = WTAP_FILE_LANALYZER;
  	wth->capture.lanalyzer = g_malloc(sizeof(lanalyzer_t));
  	wth->subtype_read = lanalyzer_read;
+ 	wth->subtype_close = lanalyzer_close;
  	wth->snapshot_length = 0;
  
  	/* Read records until we find the start of packets */
***************
*** 293,296 ****
--- 295,304 ----
  	wth->phdr.pkt_encap = wth->file_encap;
  
  	return data_offset;
+ }
+ 
+ static void
+ lanalyzer_close(wtap *wth)
+ {
+ 	g_free(wth->capture.lanalyzer);
  }
Index: libpcap.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/wiretap/libpcap.c,v
retrieving revision 1.32
diff -c -r1.32 libpcap.c
*** libpcap.c	2000/02/19 08:00:06	1.32
--- libpcap.c	2000/03/22 06:45:35
***************
*** 88,93 ****
--- 88,94 ----
  
  static int libpcap_read(wtap *wth, int *err);
  static void adjust_header(wtap *wth, struct pcaprec_hdr *hdr);
+ static void libpcap_close(wtap *wth);
  static gboolean libpcap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
      const u_char *pd, int *err);
  
***************
*** 259,264 ****
--- 260,266 ----
  	wth->capture.pcap->version_major = hdr.version_major;
  	wth->capture.pcap->version_minor = hdr.version_minor;
  	wth->subtype_read = libpcap_read;
+ 	wth->subtype_close = libpcap_close;
  	wth->file_encap = pcap_encap[hdr.network];
  	wth->snapshot_length = hdr.snaplen;
  
***************
*** 452,457 ****
--- 454,465 ----
  		hdr->orig_len = hdr->incl_len;
  		hdr->incl_len = temp;
  	}
+ }
+ 
+ static void
+ libpcap_close(wtap *wth)
+ {
+ 	g_free(wth->capture.pcap);
  }
  
  int wtap_pcap_encap_to_wtap_encap(int encap)
Index: file.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/wiretap/file.c,v
retrieving revision 1.48
diff -c -r1.48 file.c
*** file.c	2000/02/03 06:29:07	1.48
--- file.c	2000/03/22 06:45:35
***************
*** 151,156 ****
--- 151,157 ----
  	/* initialization */
  	wth->file_encap = WTAP_ENCAP_UNKNOWN;
  	wth->data_offset = 0;
+ 	wth->subtype_close = NULL;
  
  	/* Try all file types */
  	for (i = 0; i < N_FILE_TYPES; i++) {
Index: wtap.h
===================================================================
RCS file: /usr/local/cvsroot/ethereal/wiretap/wtap.h,v
retrieving revision 1.64
diff -c -r1.64 wtap.h
*** wtap.h	2000/02/19 08:00:08	1.64
--- wtap.h	2000/03/22 06:45:36
***************
*** 185,192 ****
  	guint32	start_usecs;
  	guint8	version_major;
  	guint32 *frame_table;
  	int	current_frame;
- 	int	end_offset;
  } netmon_t;
  
  typedef struct {
--- 185,192 ----
  	guint32	start_usecs;
  	guint8	version_major;
  	guint32 *frame_table;
+ 	int	frame_table_size;
  	int	current_frame;
  } netmon_t;
  
  typedef struct {
***************
*** 342,347 ****
--- 342,348 ----
  	} capture;
  
  	subtype_read_func	subtype_read;
+ 	void			(*subtype_close)(struct wtap*);
  	int			file_encap;	/* per-file, for those
  						   file formats that have
  						   per-file encapsulation