Add {0, NULL} to the isup_Pass_on_not_possible_indicator_vals and
[obnox/wireshark/wip.git] / capture.c
index d31543d2007fa895906f904b98e2903bd19fea81..21b41e9205811a3f4fc7b5b18bea9ca3fecf90bf 100644 (file)
--- a/capture.c
+++ b/capture.c
@@ -1,22 +1,22 @@
 /* capture.c
  * Routines for packet capture windows
  *
- * $Id: capture.c,v 1.174 2002/05/04 09:11:28 guy Exp $
+ * $Id: capture.c,v 1.217 2003/11/17 19:40:09 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
  * Copyright 1998 Gerald Combs
- * 
+ *
  * 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.
 
 #ifdef HAVE_LIBPCAP
 
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
 #ifdef HAVE_SYS_STAT_H
 # include <sys/stat.h>
 #endif
 #include <process.h>    /* For spawning child process */
 #endif
 
-/*
- * XXX - the various BSDs appear to define BSD in <sys/param.h>; we don't
- * want to include it if it's not present on this platform, however.
- */
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
-#ifndef BSD
-#define BSD
-#endif /* BSD */
-#endif /* defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) */
-
 /*
  * We don't want to do a "select()" on the pcap_t's file descriptor on
  * BSD (because "select()" doesn't work correctly on BPF devices on at
  * least some releases of some flavors of BSD), and we don't want to do
  * it on Windows (because "select()" is something for sockets, not for
- * arbitrary handles).
+ * arbitrary handles).  (Note that "Windows" here includes Cygwin;
+ * even in its pretend-it's-UNIX environment, we're using WinPcap, not
+ * a UNIX libpcap.)
  *
  * We *do* want to do it on other platforms, as, on other platforms (with
  * the possible exception of Ultrix and Digital UNIX), the read timeout
  * doesn't expire if no packets have arrived, so a "pcap_dispatch()" call
  * will block until packets arrive, causing the UI to hang.
+ *
+ * XXX - the various BSDs appear to define BSD in <sys/param.h>; we don't
+ * want to include it if it's not present on this platform, however.
  */
-#if !defined(BSD) && !defined(_WIN32)
+#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && \
+    !defined(__bsdi__) && !defined(__APPLE__) && !defined(_WIN32) && \
+    !defined(__CYGWIN__)
 # define MUST_DO_SELECT
 #endif
 
-#include "gtk/main.h"
-#include "gtk/gtkglobals.h"
 #include <epan/packet.h>
+#include <epan/dfilter/dfilter.h>
 #include "file.h"
 #include "capture.h"
 #include "util.h"
 
 #include "wiretap/libpcap.h"
 #include "wiretap/wtap.h"
+#include "wiretap/wtap-capture.h"
 
 #include "packet-atalk.h"
+#include "packet-atm.h"
 #include "packet-clip.h"
 #include "packet-eth.h"
 #include "packet-fddi.h"
 #include "packet-ieee80211.h"
 #include "packet-chdlc.h"
 #include "packet-prism.h"
+#include "packet-ipfc.h"
+#include "packet-arcnet.h"
 
-#ifdef WIN32
+#ifdef _WIN32
 #include "capture-wpcap.h"
 #endif
 
@@ -199,13 +195,11 @@ static void wait_for_child(gboolean);
 #ifndef _WIN32
 static char *signame(int);
 #endif
-static void capture_delete_cb(GtkWidget *, GdkEvent *, gpointer);
-static void capture_stop_cb(GtkWidget *, gpointer);
-static void capture_pcap_cb(u_char *, const struct pcap_pkthdr *,
-  const u_char *);
+static void capture_pcap_cb(guchar *, const struct pcap_pkthdr *,
+  const guchar *);
 static void get_capture_file_io_error(char *, int, const char *, int, gboolean);
+static void popup_errmsg(const char *);
 static void send_errmsg_to_parent(const char *);
-static float pct(gint, gint);
 static void stop_capture(int signo);
 
 typedef struct _loop_data {
@@ -216,16 +210,26 @@ typedef struct _loop_data {
   gint           sync_packets;
   gboolean       pcap_err;     /* TRUE if error from pcap */
   gboolean       from_pipe;    /* TRUE if we are capturing data from a pipe */
-  gboolean       modified;     /* TRUE if data in the pipe uses modified pcap headers */
-  gboolean       byte_swapped; /* TRUE if data in the pipe is byte swapped */
   packet_counts  counts;
   wtap_dumper   *pdh;
+#ifndef _WIN32
+  gboolean       modified;     /* TRUE if data in the pipe uses modified pcap headers */
+  gboolean       byte_swapped; /* TRUE if data in the pipe is byte swapped */
+  unsigned int   bytes_to_read, bytes_read; /* Used by pipe_dispatch */
+  enum {
+         STATE_EXPECT_REC_HDR, STATE_READ_REC_HDR,
+         STATE_EXPECT_DATA,     STATE_READ_DATA
+       } pipe_state;
+
+  enum { PIPOK, PIPEOF, PIPERR, PIPNEXIST } pipe_err;
+#endif
 } loop_data;
 
 #ifndef _WIN32
 static void adjust_header(loop_data *, struct pcap_hdr *, struct pcaprec_hdr *);
-static int pipe_open_live(char *, struct pcap_hdr *, loop_data *);
-static int pipe_dispatch(int, loop_data *, struct pcap_hdr *);
+static int pipe_open_live(char *, struct pcap_hdr *, loop_data *, char *, int);
+static int pipe_dispatch(int, loop_data *, struct pcap_hdr *, \
+               struct pcaprec_modified_hdr *, guchar *, char *, int);
 #endif
 
 /* Win32 needs the O_BINARY flag for open() */
@@ -278,13 +282,14 @@ quote_encapsulate(const char *string)
 #endif
 
 /* Open a specified file, or create a temporary file, and start a capture
-   to the file in question. */
-void
-do_capture(char *capfile_name)
+   to the file in question.  Returns TRUE if the capture starts
+   successfully, FALSE otherwise. */
+gboolean
+do_capture(const char *save_file)
 {
   char tmpname[128+1];
   gboolean is_tempfile;
-  u_char c;
+  guchar c;
   int i;
   guint byte_count;
   char *msg;
@@ -292,8 +297,14 @@ do_capture(char *capfile_name)
   int capture_succeeded;
   gboolean stats_known;
   struct pcap_stat stats;
-
-  if (capfile_name != NULL) {
+  gchar *capfile_name;
+
+  if (save_file != NULL) {
+    /* If the Sync option is set, we return to the caller while the capture
+     * is in progress.  Therefore we need to take a copy of save_file in
+     * case the caller destroys it after we return.
+     */
+    capfile_name = g_strdup(save_file);
     if (capture_opts.ringbuffer_on) {
       /* ringbuffer is enabled */
       cfile.save_file_fd = ringbuf_init(capfile_name,
@@ -320,13 +331,16 @@ do_capture(char *capfile_name)
         ringbuf_error_cleanup();
       }
       simple_dialog(ESD_TYPE_CRIT, NULL,
-       file_open_error_message(errno, TRUE), capfile_name);
+       file_open_error_message(errno, TRUE, WTAP_FILE_PCAP), capfile_name);
     }
-    return;
+    g_free(capfile_name);
+    return FALSE;
   }
-  close_cap_file(&cfile);
+  cf_close(&cfile);
   g_assert(cfile.save_file == NULL);
   cfile.save_file = capfile_name;
+  /* cfile.save_file is "g_free"ed below, which is equivalent to
+     "g_free(capfile_name)". */
 
   if (capture_opts.sync_mode) {        /* do the capture in a child process */
     char ssnap[24];
@@ -375,6 +389,12 @@ do_capture(char *capfile_name)
       argv = add_arg(argv, &argc, ssnap);
     }
 
+    if (capture_opts.linktype != -1) {
+      argv = add_arg(argv, &argc, "-y");
+      sprintf(ssnap,"%d",capture_opts.linktype);
+      argv = add_arg(argv, &argc, ssnap);
+    }
+
     if (capture_opts.has_autostop_filesize) {
       argv = add_arg(argv, &argc, "-a");
       sprintf(sautostop_filesize,"filesize:%d",capture_opts.autostop_filesize);
@@ -401,7 +421,7 @@ do_capture(char *capfile_name)
       cfile.save_file = NULL;
       simple_dialog(ESD_TYPE_CRIT, NULL, "Couldn't create sync pipe: %s",
                         strerror(error));
-      return;
+      return FALSE;
     }
 
     /* Convert font name to a quote-encapsulated string and pass to child */
@@ -415,6 +435,7 @@ do_capture(char *capfile_name)
     argv = add_arg(argv, &argc, sync_pipe_fd);
 
     /* Convert filter string to a quote delimited string and pass to child */
+    filterstring = NULL;
     if (cfile.cfilter != NULL && strlen(cfile.cfilter) != 0) {
       argv = add_arg(argv, &argc, "-f");
       filterstring = quote_encapsulate(cfile.cfilter);
@@ -424,11 +445,12 @@ do_capture(char *capfile_name)
     /* Spawn process */
     fork_child = spawnvp(_P_NOWAIT, ethereal_path, argv);
     g_free(fontstring);
-    g_free(filterstring);
+    if (filterstring) {
+      g_free(filterstring);
+    }
     /* Keep a copy for later evaluation by _cwait() */
     child_process = fork_child;
 #else
-    signal(SIGCHLD, SIG_IGN);
     if (pipe(sync_pipe) < 0) {
       /* Couldn't create the pipe between parent and child. */
       error = errno;
@@ -437,7 +459,7 @@ do_capture(char *capfile_name)
       cfile.save_file = NULL;
       simple_dialog(ESD_TYPE_CRIT, NULL, "Couldn't create sync pipe: %s",
                        strerror(error));
-      return;
+      return FALSE;
     }
 
     argv = add_arg(argv, &argc, "-m");
@@ -501,7 +523,7 @@ do_capture(char *capfile_name)
       cfile.save_file = NULL;
       simple_dialog(ESD_TYPE_CRIT, NULL, "Couldn't create child process: %s",
                        strerror(error));
-      return;
+      return FALSE;
     }
 
     /* Read a byte count from "sync_pipe[READ]", terminated with a
@@ -521,7 +543,7 @@ do_capture(char *capfile_name)
        g_free(cfile.save_file);
        cfile.save_file = NULL;
        wait_for_child(TRUE);
-       return;
+       return FALSE;
       }
       if (c == SP_CAPSTART || c == SP_ERROR_MSG)
        break;
@@ -535,48 +557,11 @@ do_capture(char *capfile_name)
        cfile.save_file = NULL;
        simple_dialog(ESD_TYPE_WARN, NULL,
                        "Capture child process sent us a bad message");
-       return;
+       return FALSE;
       }
       byte_count = byte_count*10 + c - '0';
     }
-    if (c == SP_CAPSTART) {
-      /* Success.  Open the capture file, and set up to read it. */
-      err = start_tail_cap_file(cfile.save_file, is_tempfile, &cfile);
-      if (err == 0) {
-       /* We were able to open and set up to read the capture file;
-          arrange that our callback be called whenever it's possible
-          to read from the sync pipe, so that it's called when
-          the child process wants to tell us something. */
-#ifdef _WIN32
-       /* Tricky to use pipes in win9x, as no concept of wait.  NT can
-          do this but that doesn't cover all win32 platforms.  GTK can do
-          this but doesn't seem to work over processes.  Attempt to do
-          something similar here, start a timer and check for data on every
-          timeout. */
-       cap_timer_id = gtk_timeout_add(1000, cap_timer_cb, NULL);
-#else
-       cap_input_id = gtk_input_add_full(sync_pipe[READ],
-                                      GDK_INPUT_READ|GDK_INPUT_EXCEPTION,
-                                      cap_file_input_cb,
-                                      NULL,
-                                      (gpointer) &cfile,
-                                      NULL);
-#endif
-      } else {
-       /* We weren't able to open the capture file; complain, and
-          close the sync pipe. */
-       simple_dialog(ESD_TYPE_CRIT, NULL,
-                       file_open_error_message(err, FALSE), cfile.save_file);
-
-       /* Close the sync pipe. */
-       close(sync_pipe[READ]);
-
-       /* Don't unlink the save file - leave it around, for debugging
-          purposes. */
-       g_free(cfile.save_file);
-       cfile.save_file = NULL;
-      }
-    } else {
+    if (c != SP_CAPSTART) {
       /* Failure - the child process sent us a message indicating
         what the problem was. */
       if (byte_count == 0) {
@@ -600,7 +585,7 @@ do_capture(char *capfile_name)
                  "Capture child process failed: EOF reading its error message.");
            wait_for_child(FALSE);
          } else
-           simple_dialog(ESD_TYPE_WARN, NULL, msg);
+           simple_dialog(ESD_TYPE_CRIT, NULL, msg);
          g_free(msg);
        }
 
@@ -612,7 +597,43 @@ do_capture(char *capfile_name)
        g_free(cfile.save_file);
        cfile.save_file = NULL;
       }
+      return FALSE;
+    }
+
+    /* The child process started a capture.
+       Attempt to open the capture file and set up to read it. */
+    err = cf_start_tail(cfile.save_file, is_tempfile, &cfile);
+    if (err != 0) {
+      /* We weren't able to open the capture file; user has been
+        alerted. Close the sync pipe. */
+
+      close(sync_pipe[READ]);
+
+      /* Don't unlink the save file - leave it around, for debugging
+        purposes. */
+      g_free(cfile.save_file);
+      cfile.save_file = NULL;
+      return FALSE;
     }
+    /* We were able to open and set up to read the capture file;
+       arrange that our callback be called whenever it's possible
+       to read from the sync pipe, so that it's called when
+       the child process wants to tell us something. */
+#ifdef _WIN32
+    /* Tricky to use pipes in win9x, as no concept of wait.  NT can
+       do this but that doesn't cover all win32 platforms.  GTK can do
+       this but doesn't seem to work over processes.  Attempt to do
+       something similar here, start a timer and check for data on every
+       timeout. */
+    cap_timer_id = gtk_timeout_add(1000, cap_timer_cb, NULL);
+#else
+    cap_input_id = gtk_input_add_full(sync_pipe[READ],
+                                     GDK_INPUT_READ|GDK_INPUT_EXCEPTION,
+                                     cap_file_input_cb,
+                                     NULL,
+                                     (gpointer) &cfile,
+                                     NULL);
+#endif
   } else {
     /* Not sync mode. */
     capture_succeeded = capture(&stats_known, &stats);
@@ -620,61 +641,81 @@ do_capture(char *capfile_name)
       /* DON'T unlink the save file.  Presumably someone wants it. */
       gtk_exit(0);
     }
-    if (capture_succeeded) {
-      /* Capture succeeded; read in the capture file. */
-      if ((err = open_cap_file(cfile.save_file, is_tempfile, &cfile)) == 0) {
-        /* Set the read filter to NULL. */
-        cfile.rfcode = NULL;
-
-        /* Get the packet-drop statistics.
-
-           XXX - there are currently no packet-drop statistics stored
-           in libpcap captures, and that's what we're reading.
-
-           At some point, we will add support in Wiretap to return
-          packet-drop statistics for capture file formats that store it,
-          and will make "read_cap_file()" get those statistics from
-          Wiretap.  We clear the statistics (marking them as "not known")
-          in "open_cap_file()", and "read_cap_file()" will only fetch
-          them and mark them as known if Wiretap supplies them, so if
-          we get the statistics now, after calling "open_cap_file()" but
-          before calling "read_cap_file()", the values we store will
-          be used by "read_cap_file()".
-
-           If a future libpcap capture file format stores the statistics,
-           we'll put them into the capture file that we write, and will
-          thus not have to set them here - "read_cap_file()" will get
-          them from the file and use them. */
-        if (stats_known) {
-          cfile.drops_known = TRUE;
-
-          /* XXX - on some systems, libpcap doesn't bother filling in
-             "ps_ifdrop" - it doesn't even set it to zero - so we don't
-             bother looking at it.
-
-             Ideally, libpcap would have an interface that gave us
-             several statistics - perhaps including various interface
-             error statistics - and would tell us which of them it
-             supplies, allowing us to display only the ones it does. */
-          cfile.drops = stats.ps_drop;
-        }
-        switch (read_cap_file(&cfile, &err)) {
-
-        case READ_SUCCESS:
-        case READ_ERROR:
-          /* Just because we got an error, that doesn't mean we were unable
-             to read any of the file; we handle what we could get from the
-             file. */
-          break;
-
-        case READ_ABORTED:
-          /* Exit by leaving the main loop, so that any quit functions
-             we registered get called. */
-          gtk_main_quit();
-          return;
-        }
+    if (!capture_succeeded) {
+      /* We didn't succeed in doing the capture, so we don't have a save
+        file. */
+      if (capture_opts.ringbuffer_on) {
+       ringbuf_free();
+      } else {
+       g_free(cfile.save_file);
       }
+      cfile.save_file = NULL;
+      return FALSE;
+    }
+    /* Capture succeeded; attempt to read in the capture file. */
+    if ((err = cf_open(cfile.save_file, is_tempfile, &cfile)) != 0) {
+      /* We're not doing a capture any more, so we don't have a save
+        file. */
+      if (capture_opts.ringbuffer_on) {
+       ringbuf_free();
+      } else {
+       g_free(cfile.save_file);
+      }
+      cfile.save_file = NULL;
+      return FALSE;
+    }
+
+    /* Set the read filter to NULL. */
+    cfile.rfcode = NULL;
+
+    /* Get the packet-drop statistics.
+
+       XXX - there are currently no packet-drop statistics stored
+       in libpcap captures, and that's what we're reading.
+
+       At some point, we will add support in Wiretap to return
+       packet-drop statistics for capture file formats that store it,
+       and will make "cf_read()" get those statistics from Wiretap.
+       We clear the statistics (marking them as "not known") in
+       "cf_open()", and "cf_read()" will only fetch them and mark
+       them as known if Wiretap supplies them, so if we get the
+       statistics now, after calling "cf_open()" but before calling
+       "cf_read()", the values we store will be used by "cf_read()".
+
+       If a future libpcap capture file format stores the statistics,
+       we'll put them into the capture file that we write, and will
+       thus not have to set them here - "cf_read()" will get them from
+       the file and use them. */
+    if (stats_known) {
+      cfile.drops_known = TRUE;
+
+      /* XXX - on some systems, libpcap doesn't bother filling in
+         "ps_ifdrop" - it doesn't even set it to zero - so we don't
+         bother looking at it.
+
+         Ideally, libpcap would have an interface that gave us
+         several statistics - perhaps including various interface
+         error statistics - and would tell us which of them it
+         supplies, allowing us to display only the ones it does. */
+      cfile.drops = stats.ps_drop;
+    }
+    switch (cf_read(&cfile, &err)) {
+
+    case READ_SUCCESS:
+    case READ_ERROR:
+      /* Just because we got an error, that doesn't mean we were unable
+         to read any of the file; we handle what we could get from the
+         file. */
+      break;
+
+    case READ_ABORTED:
+      /* Exit by leaving the main loop, so that any quit functions
+         we registered get called. */
+      if (gtk_main_level() > 0)
+        gtk_main_quit();
+      return FALSE;
     }
+
     /* We're not doing a capture any more, so we don't have a save
        file. */
     if (capture_opts.ringbuffer_on) {
@@ -684,6 +725,7 @@ do_capture(char *capfile_name)
     }
     cfile.save_file = NULL;
   }
+  return TRUE;
 }
 
 #ifdef _WIN32
@@ -729,7 +771,7 @@ cap_timer_cb(gpointer data)
 /* There's stuff to read from the sync pipe, meaning the child has sent
    us a message, or the sync pipe has closed, meaning the child has
    closed it (perhaps because it exited). */
-static void 
+static void
 cap_file_input_cb(gpointer data, gint source _U_,
   GdkInputCondition condition _U_)
 {
@@ -750,10 +792,10 @@ cap_file_input_cb(gpointer data, gint source _U_,
        capturing any more packets.  Pick up its exit status, and
        complain if it did anything other than exit with status 0. */
     wait_for_child(FALSE);
-      
+
     /* Read what remains of the capture file, and finish the capture.
        XXX - do something if this fails? */
-    switch (finish_tail_cap_file(cf, &err)) {
+    switch (cf_finish_tail(cf, &err)) {
 
     case READ_SUCCESS:
     case READ_ERROR:
@@ -822,20 +864,20 @@ cap_file_input_cb(gpointer data, gint source _U_,
         msglen -= chars_to_copy;
       }
       *r = '\0';
-      simple_dialog(ESD_TYPE_WARN, NULL, msg);
+      simple_dialog(ESD_TYPE_CRIT, NULL, msg);
       g_free(msg);
       break;
     default :
       q++;
       nread--;
       break;
-    } 
+    }
   }
 
   /* Read from the capture file the number of records the child told us
      it added.
      XXX - do something if this fails? */
-  switch (continue_tail_cap_file(cf, to_read, &err)) {
+  switch (cf_continue_tail(cf, to_read, &err)) {
 
   case READ_SUCCESS:
   case READ_ERROR:
@@ -964,7 +1006,7 @@ signame(int sig)
     sigmsg = "Segmentation violation";
     break;
 
-  /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO 
+  /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
      Linux is POSIX compliant.  These are not POSIX-defined signals ---
      ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
 
@@ -1011,24 +1053,11 @@ signame(int sig)
 
 /*
  * Timeout, in milliseconds, for reads from the stream of captured packets.
- *
- * XXX - Michael Tuexen says MacOS X's BPF appears to be broken, in that
- * if you use a timeout of 250 in "pcap_open_live()", you don't see
- * packets until a large number of packets arrive; the timeout doesn't
- * cause a smaller number of packets to be delivered.  Perhaps a timeout
- * that's less than 1 second acts like no timeout at all, so that you
- * don't see packets until the BPF buffer fills up?
- *
- * The workaround is to use a timeout of 1000 seconds on MacOS X.
  */
-#ifdef __APPLE__
-#define        CAP_READ_TIMEOUT        1000
-#else
 #define        CAP_READ_TIMEOUT        250
-#endif
 
 #ifndef _WIN32
-/* Take carre of byte order in the libpcap headers read from pipes.
+/* Take care of byte order in the libpcap headers read from pipes.
  * (function taken from wiretap/libpcap.c) */
 static void
 adjust_header(loop_data *ld, struct pcap_hdr *hdr, struct pcaprec_hdr *rechdr)
@@ -1059,29 +1088,91 @@ adjust_header(loop_data *ld, struct pcap_hdr *hdr, struct pcaprec_hdr *rechdr)
   }
 }
 
-/* Mimic pcap_open_live() for pipe captures 
+/* Mimic pcap_open_live() for pipe captures
  * We check if "pipename" is "-" (stdin) or a FIFO, open it, and read the
  * header.
  * N.B. : we can't read the libpcap formats used in RedHat 6.1 or SuSE 6.3
  * because we can't seek on pipes (see wiretap/libpcap.c for details) */
 static int
-pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld)
+pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
+                 char *errmsg, int errmsgl)
 {
   struct stat pipe_stat;
   int         fd;
   guint32     magic;
-  int         bytes_read, b;
+  int         b, sel_ret;
+  unsigned int bytes_read;
+  fd_set      rfds;
+  struct timeval timeout;
 
-  if (strcmp(pipename, "-") == 0) fd = 0; /* read from stdin */
-  else if (stat(pipename, &pipe_stat) == 0 && S_ISFIFO(pipe_stat.st_mode)) {
-    if ((fd = open(pipename, O_RDONLY)) == -1) return -1;
-  } else return -1;
+  /*
+   * XXX Ethereal blocks until we return
+   */
+  if (strcmp(pipename, "-") == 0)
+    fd = 0; /* read from stdin */
+  else {
+    if (stat(pipename, &pipe_stat) < 0) {
+      if (errno == ENOENT || errno == ENOTDIR)
+        ld->pipe_err = PIPNEXIST;
+      else {
+        snprintf(errmsg, errmsgl,
+          "The capture session could not be initiated "
+          "due to error on pipe: %s", strerror(errno));
+        ld->pipe_err = PIPERR;
+      }
+      return -1;
+    }
+    if (! S_ISFIFO(pipe_stat.st_mode)) {
+      if (S_ISCHR(pipe_stat.st_mode)) {
+        /*
+         * Assume the user specified an interface on a system where
+         * interfaces are in /dev.  Pretend we haven't seen it.
+         */
+         ld->pipe_err = PIPNEXIST;
+      } else {
+        snprintf(errmsg, errmsgl,
+            "The capture session could not be initiated because\n"
+            "\"%s\" is neither an interface nor a pipe", pipename);
+        ld->pipe_err = PIPERR;
+      }
+      return -1;
+    }
+    fd = open(pipename, O_RDONLY | O_NONBLOCK);
+    if (fd == -1) {
+      snprintf(errmsg, errmsgl,
+          "The capture session could not be initiated "
+          "due to error on pipe open: %s", strerror(errno));
+      ld->pipe_err = PIPERR;
+      return -1;
+    }
+  }
 
   ld->from_pipe = TRUE;
+
   /* read the pcap header */
-  if (read(fd, &magic, sizeof magic) != sizeof magic) {
-    close(fd);
-    return -1;
+  FD_ZERO(&rfds);
+  bytes_read = 0;
+  while (bytes_read < sizeof magic) {
+    FD_SET(fd, &rfds);
+    timeout.tv_sec = 0;
+    timeout.tv_usec = CAP_READ_TIMEOUT*1000;
+    sel_ret = select(fd+1, &rfds, NULL, NULL, &timeout);
+    if (sel_ret < 0) {
+      snprintf(errmsg, errmsgl,
+        "Unexpected error from select: %s", strerror(errno));
+      goto error;
+    } else if (sel_ret > 0) {
+      b = read(fd, ((char *)&magic)+bytes_read, sizeof magic-bytes_read);
+      if (b <= 0) {
+        if (b == 0)
+          snprintf(errmsg, errmsgl, "End of file on pipe during open");
+        else
+          snprintf(errmsg, errmsgl, "Error on pipe during open: %s",
+            strerror(errno));
+        goto error;
+      }
+      bytes_read += b;
+    }
   }
 
   switch (magic) {
@@ -1113,25 +1204,36 @@ pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld)
     break;
   default:
     /* Not a "libpcap" type we know about. */
-    close(fd);
-    return -1;
+    snprintf(errmsg, errmsgl, "Unrecognized libpcap format");
+    goto error;
   }
 
   /* Read the rest of the header */
-  bytes_read = read(fd, hdr, sizeof(struct pcap_hdr));
-  if (bytes_read <= 0) {
-    close(fd);
-    return -1;
-  }
-  while ((unsigned) bytes_read < sizeof(struct pcap_hdr))
-  {
-    b = read(fd, ((char *)&hdr)+bytes_read, sizeof(struct pcap_hdr) - bytes_read);
-    if (b <= 0) {
-      close(fd);
-      return -1;
+  bytes_read = 0;
+  while (bytes_read < sizeof(struct pcap_hdr)) {
+    FD_SET(fd, &rfds);
+    timeout.tv_sec = 0;
+    timeout.tv_usec = CAP_READ_TIMEOUT*1000;
+    sel_ret = select(fd+1, &rfds, NULL, NULL, &timeout);
+    if (sel_ret < 0) {
+      snprintf(errmsg, errmsgl,
+        "Unexpected error from select: %s", strerror(errno));
+      goto error;
+    } else if (sel_ret > 0) {
+      b = read(fd, ((char *)hdr)+bytes_read,
+            sizeof(struct pcap_hdr) - bytes_read);
+      if (b <= 0) {
+        if (b == 0)
+          snprintf(errmsg, errmsgl, "End of file on pipe during open");
+        else
+          snprintf(errmsg, errmsgl, "Error on pipe during open: %s",
+            strerror(errno));
+        goto error;
+      }
+      bytes_read += b;
     }
-    bytes_read += b;
   }
+
   if (ld->byte_swapped) {
     /* Byte-swap the header fields about which we care. */
     hdr->version_major = BSWAP16(hdr->version_major);
@@ -1139,118 +1241,128 @@ pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld)
     hdr->snaplen = BSWAP32(hdr->snaplen);
     hdr->network = BSWAP32(hdr->network);
   }
+
   if (hdr->version_major < 2) {
-    close(fd);
-    return -1;
+    snprintf(errmsg, errmsgl, "Unable to read old libpcap format");
+    goto error;
   }
 
+  ld->pipe_state = STATE_EXPECT_REC_HDR;
+  ld->pipe_err = PIPOK;
   return fd;
+
+error:
+  ld->pipe_err = PIPERR;
+  close(fd);
+  return -1;
+
 }
 
 /* We read one record from the pipe, take care of byte order in the record
  * header, write the record in the capture file, and update capture statistics. */
+
 static int
-pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr)
+pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr,
+               struct pcaprec_modified_hdr *rechdr, guchar *data,
+               char *errmsg, int errmsgl)
 {
-  struct wtap_pkthdr whdr;
-  struct pcaprec_modified_hdr rechdr;
-  int bytes_to_read, bytes_read, b;
-  u_char pd[WTAP_MAX_PACKET_SIZE];
-  int err;
-
-  /* read the record header */
-  bytes_to_read = ld->modified ? sizeof rechdr : sizeof rechdr.hdr;
-  bytes_read = read(fd, &rechdr, bytes_to_read);
-  if (bytes_read <= 0) {
-    close(fd);
-    ld->go = FALSE;
-    return 0;
-  }
-  while (bytes_read < bytes_to_read)
-  {
-    b = read(fd, ((char *)&rechdr)+bytes_read, bytes_to_read - bytes_read);
+  struct pcap_pkthdr phdr;
+  int b;
+  enum { PD_REC_HDR_READ, PD_DATA_READ, PD_PIPE_EOF, PD_PIPE_ERR,
+          PD_ERR } result;
+
+  switch (ld->pipe_state) {
+
+  case STATE_EXPECT_REC_HDR:
+    ld->bytes_to_read = ld->modified ?
+      sizeof(struct pcaprec_modified_hdr) : sizeof(struct pcaprec_hdr);
+    ld->bytes_read = 0;
+    ld->pipe_state = STATE_READ_REC_HDR;
+    /* Fall through */
+
+  case STATE_READ_REC_HDR:
+    b = read(fd, ((char *)rechdr)+ld->bytes_read,
+      ld->bytes_to_read - ld->bytes_read);
     if (b <= 0) {
-      close(fd);
-      ld->go = FALSE;
-      return 0;
+      if (b == 0)
+        result = PD_PIPE_EOF;
+      else
+        result = PD_PIPE_ERR;
+      break;
     }
-    bytes_read += b;
-  }
-  /* take care of byte order */
-  adjust_header(ld, hdr, &rechdr.hdr);
-  if (rechdr.hdr.incl_len > WTAP_MAX_PACKET_SIZE) {
-    close(fd);
-    ld->go = FALSE;
-    return 0;
-  }
-  /* read the packet data */
-  bytes_read = read(fd, pd, rechdr.hdr.incl_len);
-  if (bytes_read <= 0) {
-    close(fd);
-    ld->go = FALSE;
-    return 0;
-  }
-  while ((unsigned) bytes_read < rechdr.hdr.incl_len)
-  {
-    b = read(fd, pd+bytes_read, rechdr.hdr.incl_len - bytes_read);
+    if ((ld->bytes_read += b) < ld->bytes_to_read)
+        return 0;
+    result = PD_REC_HDR_READ;
+    break;
+
+  case STATE_EXPECT_DATA:
+    ld->bytes_read = 0;
+    ld->pipe_state = STATE_READ_DATA;
+    /* Fall through */
+
+  case STATE_READ_DATA:
+    b = read(fd, data+ld->bytes_read, rechdr->hdr.incl_len - ld->bytes_read);
     if (b <= 0) {
-      close(fd);
-      ld->go = FALSE;
-      return 0;
-    }
-    bytes_read += b;
-  }
-  /* dump the packet data to the capture file */
-  whdr.ts.tv_sec = rechdr.hdr.ts_sec;
-  whdr.ts.tv_usec = rechdr.hdr.ts_usec;
-  whdr.caplen = rechdr.hdr.incl_len;
-  whdr.len = rechdr.hdr.orig_len;
-  whdr.pkt_encap = ld->linktype;
-  wtap_dump(ld->pdh, &whdr, NULL, pd, &err);
-
-  /* update capture statistics */
-  switch (ld->linktype) {
-    case WTAP_ENCAP_ETHERNET:
-      capture_eth(pd, 0, whdr.caplen, &ld->counts);
-      break;
-    case WTAP_ENCAP_FDDI:
-    case WTAP_ENCAP_FDDI_BITSWAPPED:
-      capture_fddi(pd, whdr.caplen, &ld->counts);
-      break;
-    case WTAP_ENCAP_PRISM_HEADER:
-      capture_prism(pd, 0, whdr.caplen, &ld->counts);
-      break;
-    case WTAP_ENCAP_TOKEN_RING:
-      capture_tr(pd, 0, whdr.caplen, &ld->counts);
-      break;
-    case WTAP_ENCAP_NULL:
-      capture_null(pd, whdr.caplen, &ld->counts);
-      break;
-    case WTAP_ENCAP_PPP:
-      capture_ppp_hdlc(pd, 0, whdr.caplen, &ld->counts);
-      break;
-    case WTAP_ENCAP_RAW_IP:
-      capture_raw(pd, whdr.caplen, &ld->counts);
-      break;
-    case WTAP_ENCAP_LINUX_ATM_CLIP:
-      capture_clip(pd, whdr.caplen, &ld->counts);
-      break;
-    case WTAP_ENCAP_IEEE_802_11:
-    case WTAP_ENCAP_IEEE_802_11_WITH_RADIO:
-      capture_ieee80211(pd, 0, whdr.caplen, &ld->counts);
-      break;
-    case WTAP_ENCAP_CHDLC:
-      capture_chdlc(pd, 0, whdr.caplen, &ld->counts);
+      if (b == 0)
+        result = PD_PIPE_EOF;
+      else
+        result = PD_PIPE_ERR;
       break;
-    case WTAP_ENCAP_LOCALTALK:
-      capture_llap(&ld->counts);
+    }
+    if ((ld->bytes_read += b) < rechdr->hdr.incl_len)
+      return 0;
+    result = PD_DATA_READ;
+    break;
+
+  default:
+    snprintf(errmsg, errmsgl, "pipe_dispatch: invalid state");
+    result = PD_ERR;
+
+  } /* switch (ld->pipe_state) */
+
+  /*
+   * We've now read as much data as we were expecting, so process it.
+   */
+  switch (result) {
+
+  case PD_REC_HDR_READ:
+    /* We've read the header. Take care of byte order. */
+    adjust_header(ld, hdr, &rechdr->hdr);
+    if (rechdr->hdr.incl_len > WTAP_MAX_PACKET_SIZE) {
+      snprintf(errmsg, errmsgl, "Frame %u too long (%d bytes)",
+        ld->counts.total+1, rechdr->hdr.incl_len);
       break;
-    /* XXX - FreeBSD may append 4-byte ATM pseudo-header to DLT_ATM_RFC1483,
-       with LLC header following; we should implement it at some
-       point. */
+    }
+    ld->pipe_state = STATE_EXPECT_DATA;
+    return 0;
+
+  case PD_DATA_READ:
+    /* Fill in a "struct pcap_pkthdr", and process the packet. */
+    phdr.ts.tv_sec = rechdr->hdr.ts_sec;
+    phdr.ts.tv_usec = rechdr->hdr.ts_usec;
+    phdr.caplen = rechdr->hdr.incl_len;
+    phdr.len = rechdr->hdr.orig_len;
+
+    capture_pcap_cb((guchar *)ld, &phdr, data);
+
+    ld->pipe_state = STATE_EXPECT_REC_HDR;
+    return 1;
+
+  case PD_PIPE_EOF:
+    ld->pipe_err = PIPEOF;
+    return -1;
+
+  case PD_PIPE_ERR:
+    snprintf(errmsg, errmsgl, "Error reading from pipe: %s",
+      strerror(errno));
+    /* Fall through */
+  case PD_ERR:
+    break;
   }
 
-  return 1;
+  ld->pipe_err = PIPERR;
+  /* Return here rather than inside the switch to prevent GCC warning */
+  return -1;
 }
 #endif
 
@@ -1265,72 +1377,93 @@ static loop_data   ld;
 int
 capture(gboolean *stats_known, struct pcap_stat *stats)
 {
-  GtkWidget  *cap_w, *main_vb, *stop_bt, *counts_tb;
   pcap_t     *pch;
   int         pcap_encap;
   int         file_snaplen;
   gchar       open_err_str[PCAP_ERRBUF_SIZE];
   gchar       lookup_net_err_str[PCAP_ERRBUF_SIZE];
-  gchar       label_str[64];
   bpf_u_int32 netnum, netmask;
   struct bpf_program fcode;
+  const char *set_linktype_err_str;
   time_t      upd_time, cur_time;
+  time_t      start_time;
   int         err, inpkts;
   condition  *cnd_stop_capturesize = NULL;
   condition  *cnd_stop_timeout = NULL;
-  unsigned int i;
+  condition  *cnd_ring_timeout = NULL;
   static const char capstart_msg = SP_CAPSTART;
   char        errmsg[4096+1];
-  gboolean    dump_ok;
-#ifndef _WIN32
+  gboolean    write_ok;
+  gboolean    close_ok;
+  fd_set      set1;
+  struct timeval timeout;
+  capture_info   capture_ui;
+
+#ifdef _WIN32
+  WORD        wVersionRequested;
+  WSADATA     wsaData;
+#else
   static const char ppamsg[] = "can't find PPA for ";
   char       *libpcap_warn;
+  int         sel_ret;
+  int         pipe_fd = -1;
+  struct pcap_hdr hdr;
+  struct pcaprec_modified_hdr rechdr;
+  guchar pcap_data[WTAP_MAX_PACKET_SIZE];
 #endif
-  fd_set      set1;
-  struct timeval timeout;
 #ifdef MUST_DO_SELECT
   int         pcap_fd = 0;
 #endif
-#ifdef _WIN32 
-  WORD wVersionRequested; 
-  WSADATA wsaData; 
-#endif
-#ifndef _WIN32
-  int         pipe_fd = -1;
-  struct pcap_hdr hdr;
-#endif
-  struct {
-      const gchar *title;
-      gint *value_ptr;
-      GtkWidget *label, *value, *percent;
-  } counts[] = {
-      { "Total", &ld.counts.total, NULL, NULL, NULL },
-      { "SCTP", &ld.counts.sctp, NULL, NULL, NULL },
-      { "TCP", &ld.counts.tcp, NULL, NULL, NULL },
-      { "UDP", &ld.counts.udp, NULL, NULL, NULL },
-      { "ICMP", &ld.counts.icmp, NULL, NULL, NULL },
-      { "OSPF", &ld.counts.ospf, NULL, NULL, NULL },
-      { "GRE", &ld.counts.gre, NULL, NULL, NULL },
-      { "NetBIOS", &ld.counts.netbios, NULL, NULL, NULL },
-      { "IPX", &ld.counts.ipx, NULL, NULL, NULL },
-      { "VINES", &ld.counts.vines, NULL, NULL, NULL },
-      { "Other", &ld.counts.other, NULL, NULL, NULL }
-  };
-
-#define N_COUNTS (sizeof counts / sizeof counts[0])
-
-  /* Initialize Windows Socket if we are in a WIN32 OS 
+
+/* Size of buffer to hold decimal representation of
+   signed/unsigned 64-bit int */
+#define DECISIZE 20
+
+  /* Initialize Windows Socket if we are in a WIN32 OS
      This needs to be done before querying the interface for network/netmask */
-#ifdef _WIN32 
-  wVersionRequested = MAKEWORD( 1, 1 ); 
-  err = WSAStartup( wVersionRequested, &wsaData ); 
-  if (err!=0) { 
-    snprintf(errmsg, sizeof errmsg, 
-      "Couldn't initialize Windows Sockets."); 
-       pch=NULL; 
-    goto error; 
-  } 
-#endif 
+#ifdef _WIN32
+  /* XXX - do we really require 1.1 or earlier?
+     Are there any versions that support only 2.0 or higher? */
+  wVersionRequested = MAKEWORD(1, 1);
+  err = WSAStartup(wVersionRequested, &wsaData);
+  if (err != 0) {
+    switch (err) {
+
+    case WSASYSNOTREADY:
+      snprintf(errmsg, sizeof errmsg,
+        "Couldn't initialize Windows Sockets: Network system not ready for network communication");
+      break;
+
+    case WSAVERNOTSUPPORTED:
+      snprintf(errmsg, sizeof errmsg,
+        "Couldn't initialize Windows Sockets: Windows Sockets version %u.%u not supported",
+        LOBYTE(wVersionRequested), HIBYTE(wVersionRequested));
+      break;
+
+    case WSAEINPROGRESS:
+      snprintf(errmsg, sizeof errmsg,
+        "Couldn't initialize Windows Sockets: Blocking operation is in progress");
+      break;
+
+    case WSAEPROCLIM:
+      snprintf(errmsg, sizeof errmsg,
+        "Couldn't initialize Windows Sockets: Limit on the number of tasks supported by this WinSock implementation has been reached");
+      break;
+
+    case WSAEFAULT:
+      snprintf(errmsg, sizeof errmsg,
+        "Couldn't initialize Windows Sockets: Bad pointer passed to WSAStartup");
+      break;
+
+    default:
+      snprintf(errmsg, sizeof errmsg,
+        "Couldn't initialize Windows Sockets: error %d", err);
+      break;
+    }
+    pch = NULL;
+    goto error;
+  }
+#endif
 
   ld.go             = TRUE;
   ld.counts.total   = 0;
@@ -1353,6 +1486,7 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
   ld.counts.netbios = 0;
   ld.counts.vines   = 0;
   ld.counts.other   = 0;
+  ld.counts.arp     = 0;
   ld.pdh            = NULL;
 
   /* We haven't yet gotten the capture statistics. */
@@ -1369,9 +1503,21 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
                       capture_opts.promisc_mode, CAP_READ_TIMEOUT,
                       open_err_str);
 
-  if (pch == NULL) {
+  if (pch != NULL) {
+    /* setting the data link type only works on real interfaces */
+    if (capture_opts.linktype != -1) {
+      set_linktype_err_str = set_pcap_linktype(pch, cfile.iface,
+       capture_opts.linktype);
+      if (set_linktype_err_str != NULL) {
+       snprintf(errmsg, sizeof errmsg, "Unable to set data link type (%s).",
+         set_linktype_err_str);
+       goto error;
+      }
+    }
+  } else {
+    /* We couldn't open "cfile.iface" as a network device. */
 #ifdef _WIN32
-    /* Well, we couldn't start the capture.
+    /* On Windows, we don't support capturing on pipes, so we give up.
        If this is a child process that does the capturing in sync
        mode or fork mode, it shouldn't do any UI stuff until we pop up the
        capture-progress window, and, since we couldn't start the
@@ -1388,56 +1534,62 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
        "The capture session could not be initiated (%s).\n"
        "Please check that you have the proper interface specified.\n"
        "\n"
-       "Note that the driver Ethereal uses for packet capture on Windows\n"
-       "doesn't support capturing on PPP/WAN interfaces in Windows NT/2000.\n",
+       "Note that the driver Ethereal uses for packet capture on Windows doesn't\n"
+       "support capturing on PPP/WAN interfaces in Windows NT/2000/XP/.NET Server.\n",
        open_err_str);
     goto error;
 #else
     /* try to open cfile.iface as a pipe */
-    pipe_fd = pipe_open_live(cfile.iface, &hdr, &ld);
+    pipe_fd = pipe_open_live(cfile.iface, &hdr, &ld, errmsg, sizeof errmsg);
 
     if (pipe_fd == -1) {
-      /* Well, we couldn't start the capture assuming the interface was
-         a device, and we couldn't open the pipe, either.
-
-        We choose to report the error for the device, rather than the
-        file, under the assumption that you're typically capturing on
-        a device.
 
-        If this is a child process that does the capturing in sync
-        mode or fork mode, it shouldn't do any UI stuff until we pop up the
-        capture-progress window, and, since we couldn't start the
-        capture, we haven't popped it up. */
+      /* If this is a child process that does the capturing in sync
+       * mode or fork mode, it shouldn't do any UI stuff until we pop up the
+       * capture-progress window, and, since we couldn't start the
+       * capture, we haven't popped it up.
+       */
       if (!capture_child) {
        while (gtk_events_pending()) gtk_main_iteration();
       }
 
-      /* If we got a "can't find PPA for XXX" message, warn the user (who
-         is running Ethereal on HP-UX) that they don't have a version
-        of libpcap that properly handles HP-UX (libpcap 0.6.x and later
-        versions, which properly handle HP-UX, say "can't find /dev/dlpi
-        PPA for XXX" rather than "can't find PPA for XXX"). */
-      if (strncmp(open_err_str, ppamsg, sizeof ppamsg - 1) == 0)
-       libpcap_warn =
-         "\n\n"
-         "You are running Ethereal with a version of the libpcap library\n"
-         "that doesn't handle HP-UX network devices well; this means that\n"
-         "Ethereal may not be able to capture packets.\n"
-         "\n"
-         "To fix this, you should install libpcap 0.6.2, or a later version\n"
-         "of libpcap, rather than libpcap 0.4 or 0.5.x.  It is available in\n"
-         "packaged binary form from the Software Porting And Archive Centre\n"
-         "for HP-UX; the Centre is at http://hpux.connect.org.uk/ - the page\n"
-         "at the URL lists a number of mirror sites.";
-      else
-       libpcap_warn = "";
-      snprintf(errmsg, sizeof errmsg,
+      if (ld.pipe_err == PIPNEXIST) {
+       /* Pipe doesn't exist, so output message for interface */
+
+       /* If we got a "can't find PPA for XXX" message, warn the user (who
+          is running Ethereal on HP-UX) that they don't have a version
+          of libpcap that properly handles HP-UX (libpcap 0.6.x and later
+          versions, which properly handle HP-UX, say "can't find /dev/dlpi
+          PPA for XXX" rather than "can't find PPA for XXX"). */
+       if (strncmp(open_err_str, ppamsg, sizeof ppamsg - 1) == 0)
+         libpcap_warn =
+           "\n\n"
+           "You are running Ethereal with a version of the libpcap library\n"
+           "that doesn't handle HP-UX network devices well; this means that\n"
+           "Ethereal may not be able to capture packets.\n"
+           "\n"
+           "To fix this, you should install libpcap 0.6.2, or a later version\n"
+           "of libpcap, rather than libpcap 0.4 or 0.5.x.  It is available in\n"
+           "packaged binary form from the Software Porting And Archive Centre\n"
+           "for HP-UX; the Centre is at http://hpux.connect.org.uk/ - the page\n"
+           "at the URL lists a number of mirror sites.";
+       else
+         libpcap_warn = "";
+       snprintf(errmsg, sizeof errmsg,
          "The capture session could not be initiated (%s).\n"
          "Please check to make sure you have sufficient permissions, and that\n"
          "you have the proper interface or pipe specified.%s", open_err_str,
          libpcap_warn);
+      }
+      /*
+       * Else pipe (or file) does exist and pipe_open_live() has
+       * filled in errmsg
+       */
       goto error;
-    }
+    } else
+      /* pipe_open_live() succeeded; don't want
+         error message from pcap_open_live() */
+      open_err_str[0] = '\0';
 #endif
   }
 
@@ -1457,8 +1609,19 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
       netmask = 0;
     }
     if (pcap_compile(pch, &fcode, cfile.cfilter, 1, netmask) < 0) {
-      snprintf(errmsg, sizeof errmsg, "Unable to parse filter string (%s).",
-       pcap_geterr(pch));
+      dfilter_t   *rfcode = NULL;
+      if (dfilter_compile(cfile.cfilter, &rfcode)) {
+        snprintf(errmsg, sizeof errmsg,
+          "Unable to parse capture filter string (%s).\n"
+          "  Interestingly enough, this looks like a valid display filter\n"
+          "  Are you sure you didn't mix them up?",
+          pcap_geterr(pch));
+       dfilter_free(rfcode);
+      } else {
+        snprintf(errmsg, sizeof errmsg,
+          "Unable to parse capture filter string (%s).",
+          pcap_geterr(pch));
+      }
       goto error;
     }
     if (pcap_setfilter(pch, &fcode) < 0) {
@@ -1487,7 +1650,7 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
     goto error;
   }
   if (capture_opts.ringbuffer_on) {
-    ld.pdh = ringbuf_init_wtap_dump_fdopen(WTAP_FILE_PCAP, ld.linktype, 
+    ld.pdh = ringbuf_init_wtap_dump_fdopen(WTAP_FILE_PCAP, ld.linktype,
       file_snaplen, &err);
   } else {
     ld.pdh = wtap_dump_fdopen(cfile.save_file_fd, WTAP_FILE_PCAP,
@@ -1549,62 +1712,12 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
     write(1, &capstart_msg, 1);
   }
 
-  cap_w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-  gtk_window_set_title(GTK_WINDOW(cap_w), "Ethereal: Capture");
-  gtk_window_set_modal(GTK_WINDOW(cap_w), TRUE);
-
-  /* Container for capture display widgets */
-  main_vb = gtk_vbox_new(FALSE, 1);
-  gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
-  gtk_container_add(GTK_CONTAINER(cap_w), main_vb);
-  gtk_widget_show(main_vb);
-
-  /* Individual statistic elements */
-  counts_tb = gtk_table_new(N_COUNTS, 3, TRUE);
-  gtk_box_pack_start(GTK_BOX(main_vb), counts_tb, TRUE, TRUE, 3);
-  gtk_widget_show(counts_tb);
-
-  for (i = 0; i < N_COUNTS; i++) {
-      counts[i].label = gtk_label_new(counts[i].title);
-      gtk_misc_set_alignment(GTK_MISC(counts[i].label), 0.0f, 0.0f);
-
-      counts[i].value = gtk_label_new("0");
-      gtk_misc_set_alignment(GTK_MISC(counts[i].value), 0.0f, 0.0f);
-
-      counts[i].percent = gtk_label_new("0.0%");
-      gtk_misc_set_alignment(GTK_MISC(counts[i].percent), 0.0f, 0.0f);
-
-      gtk_table_attach_defaults(GTK_TABLE(counts_tb),
-                                counts[i].label, 0, 1, i, i + 1);
-
-      gtk_table_attach(GTK_TABLE(counts_tb),
-                       counts[i].value,
-                       1, 2, i, i + 1, 0, 0, 5, 0);
-
-      gtk_table_attach_defaults(GTK_TABLE(counts_tb),
-                                counts[i].percent, 2, 3, i, i + 1);
-
-      gtk_widget_show(counts[i].label);
-      gtk_widget_show(counts[i].value);
-      gtk_widget_show(counts[i].percent);
-  }
-
-  /* allow user to either click a stop button, or the close button on
-       the window to stop a capture in progress. */
-  stop_bt = gtk_button_new_with_label ("Stop");
-  gtk_signal_connect(GTK_OBJECT(stop_bt), "clicked",
-    GTK_SIGNAL_FUNC(capture_stop_cb), (gpointer) &ld);
-  gtk_signal_connect(GTK_OBJECT(cap_w), "delete_event",
-       GTK_SIGNAL_FUNC(capture_delete_cb), (gpointer) &ld);
-  gtk_box_pack_end(GTK_BOX(main_vb), stop_bt, FALSE, FALSE, 3);
-  GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT);
-  gtk_widget_grab_default(stop_bt);
-  GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT);
-  gtk_widget_grab_default(stop_bt);
-  gtk_widget_show(stop_bt);
-
-  gtk_widget_show(cap_w);
+  /* start capture info dialog */
+  capture_ui.callback_data  = &ld;
+  capture_ui.counts         = &ld.counts;
+  capture_info_create(&capture_ui);
 
+  start_time = time(NULL);
   upd_time = time(NULL);
 #ifdef MUST_DO_SELECT
   if (!ld.from_pipe) pcap_fd = pcap_fileno(pch);
@@ -1615,18 +1728,26 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
    * Catch SIGUSR1, so that we exit cleanly if the parent process
    * kills us with it due to the user selecting "Capture->Stop".
    */
-  signal(SIGUSR1, stop_capture);
+  if (capture_child)
+    signal(SIGUSR1, stop_capture);
 #endif
-  /* initialize capture stop conditions */ 
+  /* initialize capture stop conditions */
   init_capture_stop_conditions();
   /* create stop conditions */
   if (capture_opts.has_autostop_filesize)
     cnd_stop_capturesize =
-        cnd_new(CND_CLASS_CAPTURESIZE,(long)capture_opts.autostop_filesize * 1000); 
+        cnd_new(CND_CLASS_CAPTURESIZE,(long)capture_opts.autostop_filesize * 1000);
   if (capture_opts.has_autostop_duration)
     cnd_stop_timeout =
         cnd_new(CND_CLASS_TIMEOUT,(gint32)capture_opts.autostop_duration);
 
+  if (capture_opts.ringbuffer_on && capture_opts.has_ring_duration)
+    cnd_ring_timeout =
+       cnd_new(CND_CLASS_TIMEOUT, capture_opts.ringbuffer_duration);
+
+
+  /* WOW, everything is prepared! */
+  /* please fasten your seat belts, we will enter now the actual capture loop */
   while (ld.go) {
     while (gtk_events_pending()) gtk_main_iteration();
 
@@ -1636,16 +1757,25 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
       FD_SET(pipe_fd, &set1);
       timeout.tv_sec = 0;
       timeout.tv_usec = CAP_READ_TIMEOUT*1000;
-      if (select(pipe_fd+1, &set1, NULL, NULL, &timeout) != 0) {
+      sel_ret = select(pipe_fd+1, &set1, NULL, NULL, &timeout);
+      if (sel_ret <= 0) {
+       inpkts = 0;
+        if (sel_ret < 0 && errno != EINTR) {
+          snprintf(errmsg, sizeof(errmsg),
+            "Unexpected error from select: %s", strerror(errno));
+          popup_errmsg(errmsg);
+          ld.go = FALSE;
+        }
+      } else {
        /*
-        * "select()" says we can read from the pipe without blocking; go for
-        * it. We are not sure we can read a whole record, but at least the
-        * begninning of one. pipe_dispatch() will block reading the whole
-        * record.
+        * "select()" says we can read from the pipe without blocking
         */
-       inpkts = pipe_dispatch(pipe_fd, &ld, &hdr);
-      } else
-       inpkts = 0;
+       inpkts = pipe_dispatch(pipe_fd, &ld, &hdr, &rechdr, pcap_data,
+          errmsg, sizeof errmsg);
+       if (inpkts < 0) {
+         ld.go = FALSE;
+        }
+      }
     }
     else
 #endif
@@ -1682,144 +1812,164 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
       FD_SET(pcap_fd, &set1);
       timeout.tv_sec = 0;
       timeout.tv_usec = CAP_READ_TIMEOUT*1000;
-      if (select(pcap_fd+1, &set1, NULL, NULL, &timeout) != 0) {
+      sel_ret = select(pcap_fd+1, &set1, NULL, NULL, &timeout);
+      if (sel_ret > 0) {
        /*
         * "select()" says we can read from it without blocking; go for
         * it.
         */
-       inpkts = pcap_dispatch(pch, 1, capture_pcap_cb, (u_char *) &ld);
+       inpkts = pcap_dispatch(pch, 1, capture_pcap_cb, (guchar *) &ld);
        if (inpkts < 0) {
          ld.pcap_err = TRUE;
          ld.go = FALSE;
        }
-      } else
-       inpkts = 0;
+      } else {
+        inpkts = 0;
+        if (sel_ret < 0 && errno != EINTR) {
+          snprintf(errmsg, sizeof(errmsg),
+            "Unexpected error from select: %s", strerror(errno));
+          popup_errmsg(errmsg);
+          ld.go = FALSE;
+        }
+      }
 #else
-      inpkts = pcap_dispatch(pch, 1, capture_pcap_cb, (u_char *) &ld);
+      inpkts = pcap_dispatch(pch, 1, capture_pcap_cb, (guchar *) &ld);
       if (inpkts < 0) {
         ld.pcap_err = TRUE;
         ld.go = FALSE;
       }
 #endif
     }
-    if (inpkts > 0)
+
+    if (inpkts > 0) {
       ld.sync_packets += inpkts;
-    /* check capture stop conditons */
-    if (cnd_stop_timeout != NULL && cnd_eval(cnd_stop_timeout)) {
-      /* The specified capture time has elapsed; stop the capture. */
-      ld.go = FALSE;
-    } else if (cnd_stop_capturesize != NULL && cnd_eval(cnd_stop_capturesize, 
-                  (guint32)wtap_get_bytes_dumped(ld.pdh))){
-      /* Capture file reached its maximum size. */
-      if (capture_opts.ringbuffer_on) {
-        /* Switch to the next ringbuffer file */
-        if (ringbuf_switch_file(&cfile, &ld.pdh, &ld.err)) {
-          /* File switch succeeded: reset the condition */
-          cnd_reset(cnd_stop_capturesize);
+      /* check capture stop conditons */
+      if (cnd_stop_capturesize != NULL && cnd_eval(cnd_stop_capturesize,
+                    (guint32)wtap_get_bytes_dumped(ld.pdh))){
+        /* Capture file reached its maximum size. */
+        if (capture_opts.ringbuffer_on) {
+          /* Switch to the next ringbuffer file */
+          if (ringbuf_switch_file(&cfile, &ld.pdh, &ld.err)) {
+            /* File switch succeeded: reset the condition */
+            cnd_reset(cnd_stop_capturesize);
+           if (cnd_ring_timeout) {
+             cnd_reset(cnd_ring_timeout);
+           }
+          } else {
+            /* File switch failed: stop here */
+            ld.go = FALSE;
+            continue;
+          }
         } else {
-          /* File switch failed: stop here */
+          /* no ringbuffer - just stop */
           ld.go = FALSE;
-          continue;
         }
-      } else {
-        /* no ringbuffer - just stop */
-        ld.go = FALSE;
       }
     }
+
     /* Only update once a second so as not to overload slow displays */
     cur_time = time(NULL);
     if (cur_time > upd_time) {
       upd_time = cur_time;
 
-      for (i = 0; i < N_COUNTS; i++) {
-          snprintf(label_str, sizeof(label_str), "%d",
-                   *counts[i].value_ptr);
+      /*if (pcap_stats(pch, stats) >= 0) {
+        *stats_known = TRUE;
+      }*/
 
-          gtk_label_set(GTK_LABEL(counts[i].value), label_str);
+       /* Let the parent process know. */
+      /* calculate and display running time */
+      cur_time -= start_time;
+      capture_ui.running_time   = cur_time;
+      capture_ui.new_packets    = ld.sync_packets;
+      capture_info_update(&capture_ui);
+
+      if (ld.sync_packets) {
+        /* do sync here */
+        fflush(wtap_dump_file(ld.pdh));
+
+        if (capture_child) {
+         /* This is the child process for a sync mode capture, so send
+            our parent a message saying we've written out "ld.sync_packets"
+            packets to the capture file. */
+         char tmp[DECISIZE+1+1];
+         sprintf(tmp, "%d%c", ld.sync_packets, SP_PACKET_COUNT);
+         write(1, tmp, strlen(tmp));
+        }
 
-          snprintf(label_str, sizeof(label_str), "(%.1f%%)",
-                   pct(*counts[i].value_ptr, ld.counts.total));
+       ld.sync_packets = 0;
 
-          gtk_label_set(GTK_LABEL(counts[i].percent), label_str);
       }
 
-      /* do sync here, too */
-      fflush(wtap_dump_file(ld.pdh));
-      if (capture_child && ld.sync_packets) {
-       /* This is the child process for a sync mode capture, so send
-          our parent a message saying we've written out "ld.sync_packets"
-          packets to the capture file. */
-       char tmp[20];
-       sprintf(tmp, "%d%c", ld.sync_packets, SP_PACKET_COUNT);
-       write(1, tmp, strlen(tmp));
-       ld.sync_packets = 0;
+      if (cnd_stop_timeout != NULL && cnd_eval(cnd_stop_timeout)) {
+        /* The specified capture time has elapsed; stop the capture. */
+        ld.go = FALSE;
+      } else if (cnd_ring_timeout != NULL && cnd_eval(cnd_ring_timeout)) {
+       /* time elasped for this ring file, swith to the next */
+       if (ringbuf_switch_file(&cfile, &ld.pdh, &ld.err)) {
+         /* File switch succeeded: reset the condition */
+         cnd_reset(cnd_ring_timeout);
+       } else {
+         /* File switch failed: stop here */
+         ld.go = FALSE;
+       }
       }
     }
-  }
-    
+
+  } /* while (ld.go) */
+
   /* delete stop conditions */
   if (cnd_stop_capturesize != NULL)
     cnd_delete(cnd_stop_capturesize);
   if (cnd_stop_timeout != NULL)
     cnd_delete(cnd_stop_timeout);
+  if (cnd_ring_timeout != NULL)
+    cnd_delete(cnd_ring_timeout);
 
   if (ld.pcap_err) {
     snprintf(errmsg, sizeof(errmsg), "Error while capturing packets: %s",
       pcap_geterr(pch));
-    if (capture_child) {
-      /* Tell the parent, so that they can pop up the message;
-         we're going to exit, so if we try to pop it up, either
-         it won't pop up or it'll disappear as soon as we exit. */
-      send_errmsg_to_parent(errmsg);
-    } else {
-     /* Just pop up the message ourselves. */
-     simple_dialog(ESD_TYPE_WARN, NULL, "%s", errmsg);
-    }
+    popup_errmsg(errmsg);
+#ifdef _WIN32
   }
+#else
+  } else if (ld.from_pipe && ld.pipe_err == PIPERR)
+      popup_errmsg(errmsg);
+#endif
 
-  if (ld.err != 0) {
+  if (ld.err == 0)
+    write_ok = TRUE;
+  else {
     get_capture_file_io_error(errmsg, sizeof(errmsg), cfile.save_file, ld.err,
                              FALSE);
-    if (capture_child) {
-      /* Tell the parent, so that they can pop up the message;
-         we're going to exit, so if we try to pop it up, either
-         it won't pop up or it'll disappear as soon as we exit. */
-      send_errmsg_to_parent(errmsg);
-    } else {
-     /* Just pop up the message ourselves. */
-     simple_dialog(ESD_TYPE_WARN, NULL, "%s", errmsg);
-    }
+    popup_errmsg(errmsg);
+    write_ok = FALSE;
+  }
 
-    /* A write failed, so we've already told the user there's a problem;
-       if the close fails, there's no point in telling them about that
-       as well. */
-    if (capture_opts.ringbuffer_on) {
-      ringbuf_wtap_dump_close(&cfile, &err);
-    } else {
-      wtap_dump_close(ld.pdh, &err);
-    }
-   } else {
-    if (capture_opts.ringbuffer_on) {
-      dump_ok = ringbuf_wtap_dump_close(&cfile, &err);
-    } else {
-      dump_ok = wtap_dump_close(ld.pdh, &err);
-    }
-    if (!dump_ok) {
-      get_capture_file_io_error(errmsg, sizeof(errmsg), cfile.save_file, err,
-                               TRUE);
-      if (capture_child) {
-        /* Tell the parent, so that they can pop up the message;
-           we're going to exit, so if we try to pop it up, either
-           it won't pop up or it'll disappear as soon as we exit. */
-        send_errmsg_to_parent(errmsg);
-      } else {
-       /* Just pop up the message ourselves. */
-       simple_dialog(ESD_TYPE_WARN, NULL, "%s", errmsg);
-      }
-    }
+  if (capture_opts.ringbuffer_on) {
+    close_ok = ringbuf_wtap_dump_close(&cfile, &err);
+  } else {
+    close_ok = wtap_dump_close(ld.pdh, &err);
   }
+  /* If we've displayed a message about a write error, there's no point
+     in displaying another message about an error on close. */
+  if (!close_ok && write_ok) {
+    get_capture_file_io_error(errmsg, sizeof(errmsg), cfile.save_file, err,
+               TRUE);
+    popup_errmsg(errmsg);
+  }
+  /* Set write_ok to mean the write and the close were successful. */
+  write_ok = (write_ok && close_ok);
+
 #ifndef _WIN32
-  if (ld.from_pipe)
+  /*
+   * XXX We exhibit different behaviour between normal mode and sync mode
+   * when the pipe is stdin and not already at EOF.  If we're a child, the
+   * parent's stdin isn't closed, so if the user starts another capture,
+   * pipe_open_live() will very likely not see the expected magic bytes and
+   * will say "Unrecognized libpcap format".  On the other hand, in normal
+   * mode, pipe_open_live() will say "End of file on pipe during open".
+   */
+  if (ld.from_pipe && pipe_fd >= 0)
     close(pipe_fd);
   else
 #endif
@@ -1830,7 +1980,7 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
       *stats_known = TRUE;
       if (capture_child) {
        /* Let the parent process know. */
-       char tmp[20];
+       char tmp[DECISIZE+1+1];
        sprintf(tmp, "%d%c", stats->ps_drop, SP_DROPS);
        write(1, tmp, strlen(tmp));
       }
@@ -1838,28 +1988,19 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
       snprintf(errmsg, sizeof(errmsg),
                "Can't get packet-drop statistics: %s",
                pcap_geterr(pch));
-      if (capture_child) {
-        /* Tell the parent, so that they can pop up the message;
-           we're going to exit, so if we try to pop it up, either
-           it won't pop up or it'll disappear as soon as we exit. */
-        send_errmsg_to_parent(errmsg);
-      } else {
-       /* Just pop up the message ourselves. */
-       simple_dialog(ESD_TYPE_WARN, NULL, "%s", errmsg);
-      }
+      popup_errmsg(errmsg);
     }
     pcap_close(pch);
   }
 
-#ifdef WIN32
+#ifdef _WIN32
   /* Shut down windows sockets */
   WSACleanup();
 #endif
 
-  gtk_grab_remove(GTK_WIDGET(cap_w));
-  gtk_widget_destroy(GTK_WIDGET(cap_w));
+  capture_info_destroy(&capture_ui);
 
-  return TRUE;
+  return write_ok;
 
 error:
   if (capture_opts.ringbuffer_on) {
@@ -1876,17 +2017,18 @@ error:
     g_free(cfile.save_file);
   }
   cfile.save_file = NULL;
-  if (capture_child) {
-    /* This is the child process for a sync mode capture.
-       Send the error message to our parent, so they can display a
-       dialog box containing it. */
-    send_errmsg_to_parent(errmsg);
-  } else {
-    /* Display the dialog box ourselves; there's no parent. */
-    simple_dialog(ESD_TYPE_CRIT, NULL, "%s", errmsg);
+  popup_errmsg(errmsg);
+
+#ifndef _WIN32
+  if (ld.from_pipe) {
+    if (pipe_fd >= 0)
+      close(pipe_fd);
+  } else
+#endif
+  {
+    if (pch != NULL)
+      pcap_close(pch);
   }
-  if (pch != NULL && !ld.from_pipe)
-    pcap_close(pch);
 
   return FALSE;
 }
@@ -1949,44 +2091,46 @@ get_capture_file_io_error(char *errmsg, int errmsglen, const char *fname,
   }
 }
 
+static void
+popup_errmsg(const char *errmsg)
+{
+  if (capture_child) {
+    /* This is the child process for a sync mode capture.
+       Send the error message to our parent, so they can display a
+       dialog box containing it. */
+    send_errmsg_to_parent(errmsg);
+  } else {
+    /* Display the dialog box ourselves; there's no parent. */
+    simple_dialog(ESD_TYPE_CRIT, NULL, "%s", errmsg);
+  }
+}
+
 static void
 send_errmsg_to_parent(const char *errmsg)
 {
     int msglen = strlen(errmsg);
-    char lenbuf[10+1+1];
+    char lenbuf[DECISIZE+1+1];
 
     sprintf(lenbuf, "%u%c", msglen, SP_ERROR_MSG);
     write(1, lenbuf, strlen(lenbuf));
     write(1, errmsg, msglen);
 }
 
-static float
-pct(gint num, gint denom) {
-  if (denom) {
-    return (float) num * 100.0 / (float) denom;
-  } else {
-    return 0.0;
-  }
-}
-
 static void
 stop_capture(int signo _U_)
 {
   ld.go = FALSE;
 }
 
-static void
-capture_delete_cb(GtkWidget *w _U_, GdkEvent *event _U_, gpointer data) {
-  capture_stop_cb(NULL, data);
-}
+void capture_ui_stop_callback(
+gpointer               callback_data)
+{
+  loop_data *ld = (loop_data *) callback_data;
 
-static void
-capture_stop_cb(GtkWidget *w _U_, gpointer data) {
-  loop_data *ld = (loop_data *) data;
-  
   ld->go = FALSE;
 }
 
+
 void
 capture_stop(void)
 {
@@ -2012,70 +2156,94 @@ kill_capture_child(void)
 }
 
 static void
-capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
-  const u_char *pd) {
+capture_pcap_cb(guchar *user, const struct pcap_pkthdr *phdr,
+  const guchar *pd)
+{
   struct wtap_pkthdr whdr;
+  union wtap_pseudo_header pseudo_header;
   loop_data *ld = (loop_data *) user;
   int err;
 
-  if ((++ld->counts.total >= ld->max) && (ld->max > 0)) 
+  if ((++ld->counts.total >= ld->max) && (ld->max > 0))
   {
      ld->go = FALSE;
   }
+
+  /* Convert from libpcap to Wiretap format.
+     If that fails, set "ld->go" to FALSE, to stop the capture, and set
+     "ld->err" to the error. */
+  pd = wtap_process_pcap_packet(ld->linktype, phdr, pd, &pseudo_header,
+                               &whdr, &err);
+  if (pd == NULL) {
+    ld->go = FALSE;
+    ld->err = err;
+    return;
+  }
+
   if (ld->pdh) {
-     /* "phdr->ts" may not necessarily be a "struct timeval" - it may
-        be a "struct bpf_timeval", with member sizes wired to 32
-       bits - and we may go that way ourselves in the future, so
-       copy the members individually. */
-     whdr.ts.tv_sec = phdr->ts.tv_sec;
-     whdr.ts.tv_usec = phdr->ts.tv_usec;
-     whdr.caplen = phdr->caplen;
-     whdr.len = phdr->len;
-     whdr.pkt_encap = ld->linktype;
-
-     /* If this fails, set "ld->go" to FALSE, to stop the capture, and set
-        "ld->err" to the error. */
-     if (!wtap_dump(ld->pdh, &whdr, NULL, pd, &err)) {
-       ld->go = FALSE;
-       ld->err = err;
-     }
+    /* We're supposed to write the packet to a file; do so.
+       If this fails, set "ld->go" to FALSE, to stop the capture, and set
+       "ld->err" to the error. */
+    if (!wtap_dump(ld->pdh, &whdr, &pseudo_header, pd, &err)) {
+      ld->go = FALSE;
+      ld->err = err;
+    }
   }
 
   switch (ld->linktype) {
     case WTAP_ENCAP_ETHERNET:
-      capture_eth(pd, 0, phdr->len, &ld->counts);
+      capture_eth(pd, 0, whdr.caplen, &ld->counts);
       break;
     case WTAP_ENCAP_FDDI:
     case WTAP_ENCAP_FDDI_BITSWAPPED:
-      capture_fddi(pd, phdr->len, &ld->counts);
+      capture_fddi(pd, whdr.caplen, &ld->counts);
       break;
     case WTAP_ENCAP_PRISM_HEADER:
-      capture_prism(pd, 0, phdr->len, &ld->counts);
+      capture_prism(pd, 0, whdr.caplen, &ld->counts);
       break;
     case WTAP_ENCAP_TOKEN_RING:
-      capture_tr(pd, 0, phdr->len, &ld->counts);
+      capture_tr(pd, 0, whdr.caplen, &ld->counts);
       break;
     case WTAP_ENCAP_NULL:
-      capture_null(pd, phdr->len, &ld->counts);
+      capture_null(pd, whdr.caplen, &ld->counts);
       break;
     case WTAP_ENCAP_PPP:
-      capture_ppp_hdlc(pd, 0, phdr->len, &ld->counts);
+      capture_ppp_hdlc(pd, 0, whdr.caplen, &ld->counts);
       break;
     case WTAP_ENCAP_RAW_IP:
-      capture_raw(pd, phdr->len, &ld->counts);
+      capture_raw(pd, whdr.caplen, &ld->counts);
       break;
     case WTAP_ENCAP_SLL:
-      capture_sll(pd, phdr->len, &ld->counts);
+      capture_sll(pd, whdr.caplen, &ld->counts);
       break;
     case WTAP_ENCAP_LINUX_ATM_CLIP:
-      capture_clip(pd, phdr->len, &ld->counts);
+      capture_clip(pd, whdr.caplen, &ld->counts);
+      break;
+    case WTAP_ENCAP_IEEE_802_11:
+    case WTAP_ENCAP_IEEE_802_11_WITH_RADIO:
+      capture_ieee80211(pd, 0, whdr.caplen, &ld->counts);
+      break;
+    case WTAP_ENCAP_CHDLC:
+      capture_chdlc(pd, 0, whdr.caplen, &ld->counts);
       break;
     case WTAP_ENCAP_LOCALTALK:
       capture_llap(&ld->counts);
       break;
-    /* XXX - FreeBSD may append 4-byte ATM pseudo-header to DLT_ATM_RFC1483,
-       with LLC header following; we should implement it at some
-       point. */
+    case WTAP_ENCAP_ATM_PDUS:
+      capture_atm(&pseudo_header, pd, whdr.caplen, &ld->counts);
+      break;
+    case WTAP_ENCAP_IP_OVER_FC:
+      capture_ipfc(pd, whdr.caplen, &ld->counts);
+      break;
+    case WTAP_ENCAP_ARCNET:
+      capture_arcnet(pd, whdr.caplen, &ld->counts, FALSE, TRUE);
+      break;
+    case WTAP_ENCAP_ARCNET_LINUX:
+      capture_arcnet(pd, whdr.caplen, &ld->counts, TRUE, FALSE);
+      break;
+    /* XXX - some ATM drivers on FreeBSD might prepend a 4-byte ATM
+       pseudo-header to DLT_ATM_RFC1483, with LLC header following;
+       we might have to implement that at some point. */
   }
 }