Update some links.
[obnox/wireshark/wip.git] / dumpcap.c
index 2f00b6d1e68bc66c1b7a873f6f59988450ed5535..30454d308aec631981f3745928156271fcca41df 100644 (file)
--- a/dumpcap.c
+++ b/dumpcap.c
@@ -25,6 +25,7 @@
 # include "config.h"
 #endif
 
+#include <stdio.h>
 #include <stdlib.h> /* for exit() */
 #include <glib.h>
 
 #include <unistd.h>
 #endif
 
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#if defined(__APPLE__) && defined(__LP64__)
+#include <sys/utsname.h>
+#endif
+
 #include <signal.h>
 #include <errno.h>
 
-#ifdef NEED_GETOPT_H
-#include "getopt.h"
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+#include "wsutil/wsgetopt.h"
 #endif
 
 #ifdef HAVE_NETDB_H
 #ifdef HAVE_LIBCAP
 # include <sys/prctl.h>
 # include <sys/capability.h>
-# include <stdio.h>
 #endif
 
 #include "ringbuffer.h"
 #include "clopts_common.h"
+#include "console_io.h"
 #include "cmdarg_err.h"
 #include "version_info.h"
 
-#include <pcap.h>
-#include "pcapio.h"
-
 #include "capture-pcap-util.h"
 
+#include "pcapio.h"
+
 #ifdef _WIN32
 #include "capture-wpcap.h"
+#include <wsutil/unicode-utils.h>
 #endif
 
-#ifdef _WIN32
-#include "epan/unicode-utils.h"
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif
+
+#ifdef NEED_INET_V6DEFS_H
+# include "wsutil/inet_v6defs.h"
 #endif
 
-#include "epan/privileges.h"
+#include <wsutil/privileges.h>
 
 #include "sync_pipe.h"
 
 #include "capture_opts.h"
+#include "capture_ifinfo.h"
 #include "capture_sync.h"
 
 #include "conditions.h"
 
 #include "tempfile.h"
 #include "log.h"
-#include "file_util.h"
+#include "wsutil/file_util.h"
 
 /*
  * Get information about libpcap format from "wiretap/libpcap.h".
@@ -111,12 +128,27 @@ FILE *debug_log;   /* for logging debug messages to  */
                    /*  is defined                    */
 #endif
 
+#ifdef _WIN32
+#define USE_THREADS
+#endif
+
 static gboolean capture_child = FALSE; /* FALSE: standalone call, TRUE: this is an Wireshark capture child */
 #ifdef _WIN32
 static gchar *sig_pipe_name = NULL;
 static HANDLE sig_pipe_handle = NULL;
+static gboolean signal_pipe_check_running(void);
+#endif
+
+#ifdef USE_THREADS
+static GAsyncQueue *cap_pipe_pending_q, *cap_pipe_done_q;
+static GMutex *cap_pipe_read_mtx;
 #endif
 
+#ifdef SIGINFO
+static gboolean infodelay;     /* if TRUE, don't print capture info in SIGINFO handler */
+static gboolean infoprint;     /* if TRUE, print capture info after clearing infodelay */
+#endif /* SIGINFO */
+
 /** Stop a low-level capture (stops the capture child). */
 static void capture_loop_stop(void);
 
@@ -129,7 +161,7 @@ static void capture_loop_stop(void);
  * is interrupted by a signal on UN*X, just go back and try again to
  * read again.
  *
- * On UN*X, we catch SIGUSR1 as a "stop capturing" signal, and, in
+ * On UN*X, we catch SIGINT as a "stop capturing" signal, and, in
  * the signal handler, set a flag to stop capturing; however, without
  * a guarantee of that sort, we can't guarantee that we'll stop capturing
  * if the read will be retried and won't time out if no packets arrive.
@@ -152,7 +184,7 @@ static void capture_loop_stop(void);
  * exit pcap_dispatch() with an indication that no packets have arrived,
  * and will break out of the capture loop at that point.
  *
- * On Windows, we can't send a SIGUSR1 to stop capturing, so none of this
+ * On Windows, we can't send a SIGINT to stop capturing, so none of this
  * applies in any case.
  *
  * XXX - the various BSDs appear to define BSD in <sys/param.h>; we don't
@@ -185,6 +217,10 @@ typedef struct _loop_data {
   int            err;                   /* if non-zero, error seen while capturing */
   gint           packet_count;          /* Number of packets we have already captured */
   gint           packet_max;            /* Number of packets we're supposed to capture - 0 means infinite */
+  gint           inpkts_to_sync_pipe;   /* Packets not already send out to the sync_pipe */
+#ifdef SIGINFO
+  gboolean       report_packet_count;   /* Set by SIGINFO handler; print packet count */
+#endif
 
   /* pcap "input file" */
   pcap_t        *pcap_h;                /* pcap handle */
@@ -197,11 +233,18 @@ typedef struct _loop_data {
   gboolean       from_cap_pipe;         /* TRUE if we are capturing data from a capture pipe */
   struct pcap_hdr cap_pipe_hdr;         /* Pcap header when capturing from a pipe */
   struct pcaprec_modified_hdr cap_pipe_rechdr;  /* Pcap record header when capturing from a pipe */
+#ifdef _WIN32
+  HANDLE         cap_pipe_h;            /* The handle of the capture pipe */
+#else
   int            cap_pipe_fd;           /* the file descriptor of the capture pipe */
+#endif
   gboolean       cap_pipe_modified;     /* TRUE if data in the pipe uses modified pcap headers */
   gboolean       cap_pipe_byte_swapped; /* TRUE if data in the pipe is byte swapped */
-  unsigned int   cap_pipe_bytes_to_read;/* Used by cap_pipe_dispatch */
-  unsigned int   cap_pipe_bytes_read;   /* Used by cap_pipe_dispatch */
+#ifdef USE_THREADS
+  char *         cap_pipe_buf;          /* Pointer to the data buffer we read into */
+#endif /* USE_THREADS */
+  int   cap_pipe_bytes_to_read;/* Used by cap_pipe_dispatch */
+  int   cap_pipe_bytes_read;   /* Used by cap_pipe_dispatch */
   enum {
          STATE_EXPECT_REC_HDR,
          STATE_READ_REC_HDR,
@@ -210,12 +253,14 @@ typedef struct _loop_data {
        } cap_pipe_state;
   enum { PIPOK, PIPEOF, PIPERR, PIPNEXIST } cap_pipe_err;
 
-  /* output file */
+  /* output file(s) */
   FILE          *pdh;
+  int            save_file_fd;
   int            linktype;
+  int            file_snaplen;
   gint           wtap_linktype;
   long           bytes_written;
-
+  guint32        autostop_files;
 } loop_data;
 
 /*
@@ -226,17 +271,32 @@ static const char please_report[] =
     "(This is not a crash; please do not report it as such.)";
 
 /*
- * This needs to be static, so that the SIGUSR1 handler can clear the "go"
+ * This needs to be static, so that the SIGINT handler can clear the "go"
  * flag.
  */
-static loop_data   ld;
+static loop_data   global_ld;
 
 
 /*
  * Timeout, in milliseconds, for reads from the stream of captured packets.
+ *
+ * A bug in Mac OS X 10.6 and 10.6.1 causes calls to pcap_open_live(), in
+ * 64-bit applications, with sub-second timeouts not to work.  The bug is
+ * fixed in 10.6.2.
  */
+#if defined(__APPLE__) && defined(__LP64__)
+static gboolean need_timeout_workaround;
+
+#define        CAP_READ_TIMEOUT        (need_timeout_workaround ? 1000 : 250)
+#else
 #define        CAP_READ_TIMEOUT        250
-static char *cap_pipe_err_str;
+#endif
+
+/*
+ * Timeout, in microseconds, for threaded reads from a pipe.
+ */
+#define THREAD_READ_TIMEOUT   100
+static const char *cap_pipe_err_str;
 
 static void
 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
@@ -244,29 +304,22 @@ console_log_handler(const char *log_domain, GLogLevelFlags log_level,
 
 /* capture related options */
 static capture_options global_capture_opts;
-static capture_options *capture_opts = &global_capture_opts;
+static gboolean quiet;
 
 static void capture_loop_packet_cb(u_char *user, const struct pcap_pkthdr *phdr,
   const u_char *pd);
 static void capture_loop_get_errmsg(char *errmsg, int errmsglen, const char *fname,
                          int err, gboolean is_close);
 
-
-#if __GNUC__ >= 2
-static void exit_main(int err) __attribute__ ((noreturn));
-#else
-static void exit_main(int err);
-#endif
+static void exit_main(int err) G_GNUC_NORETURN;
 
 static void report_new_capture_file(const char *filename);
 static void report_packet_count(int packet_count);
-static void report_packet_drops(int drops);
+static void report_packet_drops(guint32 drops);
 static void report_capture_error(const char *error_msg, const char *secondary_error_msg);
 static void report_cfilter_error(const char *cfilter, const char *errmsg);
 
-#ifdef _WIN32
-static gboolean signal_pipe_check_running(void);
-#endif
+#define MSG_MAX_LENGTH 4096
 
 static void
 print_usage(gboolean print_ver) {
@@ -291,14 +344,20 @@ print_usage(gboolean print_ver) {
   fprintf(output, "  -f <capture filter>      packet filter in libpcap filter syntax\n");
   fprintf(output, "  -s <snaplen>             packet snapshot length (def: 65535)\n");
   fprintf(output, "  -p                       don't capture in promiscuous mode\n");
-#ifdef _WIN32
+#ifdef HAVE_PCAP_CREATE
+  fprintf(output, "  -I                       capture in monitor mode, if available\n");
+#endif
+#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
   fprintf(output, "  -B <buffer size>         size of kernel buffer (def: 1MB)\n");
 #endif
   fprintf(output, "  -y <link type>           link layer type (def: first appropriate)\n");
   fprintf(output, "  -D                       print list of interfaces and exit\n");
   fprintf(output, "  -L                       print list of link-layer types of iface and exit\n");
+#ifdef HAVE_BPF_IMAGE
+  fprintf(output, "  -d                       print generated BPF code for capture filter\n");
+#endif
   fprintf(output, "  -S                       print statistics for each interface once every second\n");
-  fprintf(output, "  -M                       for -D, -L, and -S produce machine-readable output\n");
+  fprintf(output, "  -M                       for -D, -L, and -S, produce machine-readable output\n");
   fprintf(output, "\n");
 #ifdef HAVE_PCAP_REMOTE
   fprintf(output, "\nRPCAP options:\n");
@@ -322,8 +381,10 @@ print_usage(gboolean print_ver) {
   fprintf(output, "  -b <ringbuffer opt.> ... duration:NUM - switch to next file after NUM secs\n");
   fprintf(output, "                           filesize:NUM - switch to next file after NUM KB\n");
   fprintf(output, "                              files:NUM - ringbuffer: replace after NUM files\n");
+  fprintf(output, "  -n                       use pcapng format instead of pcap\n");
   /*fprintf(output, "\n");*/
   fprintf(output, "Miscellaneous:\n");
+  fprintf(output, "  -q                       don't report packet capture counts\n");
   fprintf(output, "  -v                       print version information and exit\n");
   fprintf(output, "  -h                       display this help and exit\n");
   fprintf(output, "\n");
@@ -347,6 +408,26 @@ show_version(GString *comp_info_str, GString *runtime_info_str)
         wireshark_svnversion, get_copyright_info() ,comp_info_str->str, runtime_info_str->str);
 }
 
+/*
+ * Print to the standard error.  This is a command-line tool, so there's
+ * no need to pop up a console.
+ */
+void
+vfprintf_stderr(const char *fmt, va_list ap)
+{
+  vfprintf(stderr, fmt, ap);
+}
+
+void
+fprintf_stderr(const char *fmt, ...)
+{
+  va_list ap;
+
+  va_start(ap, fmt);
+  vfprintf_stderr(fmt, ap);
+  va_end(ap);
+}
+
 /*
  * Report an error in command-line arguments.
  */
@@ -395,10 +476,823 @@ cmdarg_err_cont(const char *fmt, ...)
   }
 }
 
+#ifdef HAVE_LIBCAP
+static void
+#if 0 /* Set to enable capability debugging */
+/* see 'man cap_to_text()' for explanation of output                         */
+/* '='   means 'all= '  ie: no capabilities                                  */
+/* '=ip' means 'all=ip' ie: all capabilities are permissible and inheritable */
+/* ....                                                                      */
+print_caps(const char *pfx) {
+    cap_t caps = cap_get_proc();
+    g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+          "%s: EUID: %d  Capabilities: %s", pfx,
+          geteuid(), cap_to_text(caps, NULL));
+    cap_free(caps);
+#else
+print_caps(const char *pfx _U_) {
+#endif
+}
+
+static void
+relinquish_all_capabilities(void)
+{
+    /* Drop any and all capabilities this process may have.            */
+    /* Allowed whether or not process has any privileges.              */
+    cap_t caps = cap_init();    /* all capabilities initialized to off */
+    print_caps("Pre-clear");
+    if (cap_set_proc(caps)) {
+        cmdarg_err("cap_set_proc() fail return: %s", strerror(errno));
+    }
+    print_caps("Post-clear");
+    cap_free(caps);
+}
+#endif
+
+static pcap_t *
+open_capture_device(capture_options *capture_opts,
+                    char (*open_err_str)[PCAP_ERRBUF_SIZE])
+{
+  pcap_t *pcap_h;
+#ifdef HAVE_PCAP_CREATE
+  int         err;
+#endif
+#ifdef HAVE_PCAP_REMOTE
+  struct pcap_rmtauth auth;
+#endif
+
+  /* Open the network interface to capture from it.
+     Some versions of libpcap may put warnings into the error buffer
+     if they succeed; to tell if that's happened, we have to clear
+     the error buffer, and check if it's still a null string.  */
+  (*open_err_str)[0] = '\0';
+#ifdef HAVE_PCAP_OPEN
+  /*
+   * If we're opening a remote device, use pcap_open(); that's currently
+   * the only open routine that supports remote devices.
+   */
+  if (strncmp (capture_opts->iface, "rpcap://", 8) == 0) {
+    auth.type = capture_opts->auth_type == CAPTURE_AUTH_PWD ?
+      RPCAP_RMTAUTH_PWD : RPCAP_RMTAUTH_NULL;
+    auth.username = capture_opts->auth_username;
+    auth.password = capture_opts->auth_password;
+
+    pcap_h = pcap_open(capture_opts->iface,
+                       capture_opts->has_snaplen ? capture_opts->snaplen :
+                                                   WTAP_MAX_PACKET_SIZE,
+                       /* flags */
+                       (capture_opts->promisc_mode ? PCAP_OPENFLAG_PROMISCUOUS : 0) |
+                       (capture_opts->datatx_udp ? PCAP_OPENFLAG_DATATX_UDP : 0) |
+                       (capture_opts->nocap_rpcap ? PCAP_OPENFLAG_NOCAPTURE_RPCAP : 0),
+                       CAP_READ_TIMEOUT, &auth, *open_err_str);
+  } else
+#endif /* HAVE_PCAP_OPEN */
+  {
+    /*
+     * If we're not opening a remote device, use pcap_create() and
+     * pcap_activate() if we have them, so that we can set the buffer
+     * size, otherwise use pcap_open_live().
+     */
+#ifdef HAVE_PCAP_CREATE
+    pcap_h = pcap_create(capture_opts->iface, *open_err_str);
+    if (pcap_h != NULL) {
+      pcap_set_snaplen(pcap_h, capture_opts->has_snaplen ? capture_opts->snaplen : WTAP_MAX_PACKET_SIZE);
+      pcap_set_promisc(pcap_h, capture_opts->promisc_mode);
+      pcap_set_timeout(pcap_h, CAP_READ_TIMEOUT);
+
+      if (capture_opts->buffer_size > 1) {
+        pcap_set_buffer_size(pcap_h, capture_opts->buffer_size * 1024 * 1024);
+      }
+      if (capture_opts->monitor_mode)
+        pcap_set_rfmon(pcap_h, 1);
+      err = pcap_activate(pcap_h);
+      if (err < 0) {
+        /* Failed to activate, set to NULL */
+        if (err == PCAP_ERROR)
+          g_strlcpy(*open_err_str, pcap_geterr(pcap_h), sizeof *open_err_str);
+        else
+          g_strlcpy(*open_err_str, pcap_statustostr(err), sizeof *open_err_str);
+        pcap_close(pcap_h);
+        pcap_h = NULL;
+      }
+    }
+#else
+    pcap_h = pcap_open_live(capture_opts->iface,
+                            capture_opts->has_snaplen ? capture_opts->snaplen :
+                                                        WTAP_MAX_PACKET_SIZE,
+                            capture_opts->promisc_mode, CAP_READ_TIMEOUT,
+                            *open_err_str);
+#endif
+  }
+
+  /* If not using libcap: we now can now set euid/egid to ruid/rgid         */
+  /*  to remove any suid privileges.                                        */
+  /* If using libcap: we can now remove NET_RAW and NET_ADMIN capabilities  */
+  /*  (euid/egid have already previously been set to ruid/rgid.             */
+  /* (See comment in main() for details)                                    */
+#ifndef HAVE_LIBCAP
+  relinquish_special_privs_perm();
+#else
+  relinquish_all_capabilities();
+#endif
+
+  return pcap_h;
+}
+
+static void
+get_capture_device_open_failure_messages(const char *open_err_str,
+                                         const char *iface
+#ifndef _WIN32
+                                                           _U_
+#endif
+                                         ,
+                                         char *errmsg, size_t errmsg_len,
+                                         char *secondary_errmsg,
+                                         size_t secondary_errmsg_len)
+{
+  const char *libpcap_warn;
+  static const char ppamsg[] = "can't find PPA for ";
+
+  /* If we got a "can't find PPA for X" message, warn the user (who
+     is running dumcap 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 X" rather than "can't find PPA for X"). */
+  if (strncmp(open_err_str, ppamsg, sizeof ppamsg - 1) == 0)
+    libpcap_warn =
+      "\n\n"
+      "You are running (T)Wireshark with a version of the libpcap library\n"
+      "that doesn't handle HP-UX network devices well; this means that\n"
+      "(T)Wireshark 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 = "";
+  g_snprintf(errmsg, (gulong) errmsg_len,
+             "The capture session could not be initiated (%s).", open_err_str);
+#ifndef _WIN32
+  g_snprintf(secondary_errmsg, (gulong) secondary_errmsg_len,
+"Please check to make sure you have sufficient permissions, and that you have "
+"the proper interface or pipe specified.%s", libpcap_warn);
+#else
+  g_snprintf(secondary_errmsg, (gulong) secondary_errmsg_len,
+"\n"
+"Please check that \"%s\" is the proper interface.\n"
+"\n"
+"\n"
+"Help can be found at:\n"
+"\n"
+"       http://wiki.wireshark.org/WinPcap\n"
+"       http://wiki.wireshark.org/CaptureSetup\n",
+             iface);
+#endif /* _WIN32 */
+}
+
+/* Set the data link type on a pcap. */
+static gboolean
+set_pcap_linktype(pcap_t *pcap_h, capture_options *capture_opts,
+                  char *errmsg, size_t errmsg_len,
+                  char *secondary_errmsg, size_t secondary_errmsg_len)
+{
+  char *set_linktype_err_str;
+
+  if (capture_opts->linktype == -1)
+    return TRUE; /* just use the default */
+#ifdef HAVE_PCAP_SET_DATALINK
+  if (pcap_set_datalink(pcap_h, capture_opts->linktype) == 0)
+    return TRUE; /* no error */
+  set_linktype_err_str = pcap_geterr(pcap_h);
+#else
+  /* Let them set it to the type it is; reject any other request. */
+  if (get_pcap_linktype(pcap_h, capture_opts->iface) == capture_opts->linktype)
+    return TRUE; /* no error */
+  set_linktype_err_str =
+    "That DLT isn't one of the DLTs supported by this device";
+#endif
+  g_snprintf(errmsg, (gulong) errmsg_len, "Unable to set data link type (%s).",
+             set_linktype_err_str);
+  /*
+   * If the error isn't "XXX is not one of the DLTs supported by this device",
+   * tell the user to tell the Wireshark developers about it.
+   */
+  if (strstr(set_linktype_err_str, "is not one of the DLTs supported by this device") == NULL)
+    g_snprintf(secondary_errmsg, (gulong) secondary_errmsg_len, please_report);
+  else
+    secondary_errmsg[0] = '\0';
+  return FALSE;
+}
+
+static gboolean
+compile_capture_filter(const char *iface, pcap_t *pcap_h,
+                       struct bpf_program *fcode, char *cfilter)
+{
+  bpf_u_int32 netnum, netmask;
+  gchar       lookup_net_err_str[PCAP_ERRBUF_SIZE];
+
+  if (pcap_lookupnet(iface, &netnum, &netmask, lookup_net_err_str) < 0) {
+    /*
+     * Well, we can't get the netmask for this interface; it's used
+     * only for filters that check for broadcast IP addresses, so
+     * we just punt and use 0.  It might be nice to warn the user,
+     * but that's a pain in a GUI application, as it'd involve popping
+     * up a message box, and it's not clear how often this would make
+     * a difference (only filters that check for IP broadcast addresses
+     * use the netmask).
+     */
+    /*cmdarg_err(
+      "Warning:  Couldn't obtain netmask info (%s).", lookup_net_err_str);*/
+    netmask = 0;
+  }
+  if (pcap_compile(pcap_h, fcode, cfilter, 1, netmask) < 0)
+    return FALSE;
+  return TRUE;
+}
+
+#ifdef HAVE_BPF_IMAGE
+static gboolean
+show_filter_code(capture_options *capture_opts)
+{
+  pcap_t *pcap_h;
+  gchar open_err_str[PCAP_ERRBUF_SIZE];
+  char errmsg[MSG_MAX_LENGTH+1];
+  char secondary_errmsg[MSG_MAX_LENGTH+1];
+  struct bpf_program fcode;
+  struct bpf_insn *insn;
+  u_int i;
+
+  pcap_h = open_capture_device(capture_opts, &open_err_str);
+  if (pcap_h == NULL) {
+    /* Open failed; get messages */
+    get_capture_device_open_failure_messages(open_err_str,
+                                             capture_opts->iface,
+                                             errmsg, sizeof errmsg,
+                                             secondary_errmsg,
+                                             sizeof secondary_errmsg);
+    /* And report them */
+    report_capture_error(errmsg, secondary_errmsg);
+    return FALSE;
+  }
+
+  /* Set the link-layer type. */
+  if (!set_pcap_linktype(pcap_h, capture_opts, errmsg, sizeof errmsg,
+                         secondary_errmsg, sizeof secondary_errmsg)) {
+    pcap_close(pcap_h);
+    report_capture_error(errmsg, secondary_errmsg);
+    return FALSE;
+  }
+
+  /* OK, try to compile the capture filter. */
+  if (!compile_capture_filter(capture_opts->iface, pcap_h, &fcode,
+                              capture_opts->cfilter)) {
+    pcap_close(pcap_h);
+    report_cfilter_error(capture_opts->cfilter, errmsg);
+    return FALSE;
+  }
+  pcap_close(pcap_h);
+
+  if (capture_child) {
+    /* Let our parent know we succeeded. */
+    pipe_write_block(2, SP_SUCCESS, NULL);
+ }
+
+  /* Now print the filter code. */
+  insn = fcode.bf_insns;
+
+  for (i = 0; i < fcode.bf_len; insn++, i++)
+    printf("%s\n", bpf_image(insn, i));
+  return TRUE;
+}
+#endif
+
+/*
+ * capture_interface_list() is expected to do the right thing to get
+ * a list of interfaces.
+ *
+ * In most of the programs in the Wireshark suite, "the right thing"
+ * is to run dumpcap and ask it for the list, because dumpcap may
+ * be the only program in the suite with enough privileges to get
+ * the list.
+ *
+ * In dumpcap itself, however, we obviously can't run dumpcap to
+ * ask for the list.  Therefore, our capture_interface_list() should
+ * just call get_interface_list().
+ */
+GList *
+capture_interface_list(int *err, char **err_str)
+{
+  return get_interface_list(err, err_str);
+}
+
+/*
+ * Get the data-link type for a libpcap device.
+ * This works around AIX 5.x's non-standard and incompatible-with-the-
+ * rest-of-the-universe libpcap.
+ */
+static int
+get_pcap_linktype(pcap_t *pch, const char *devname
+#ifndef _AIX
+       _U_
+#endif
+)
+{
+  int linktype;
+#ifdef _AIX
+  const char *ifacename;
+#endif
+
+  linktype = pcap_datalink(pch);
+#ifdef _AIX
+
+  /*
+   * The libpcap that comes with AIX 5.x uses RFC 1573 ifType values
+   * rather than DLT_ values for link-layer types; the ifType values
+   * for LAN devices are:
+   *
+   *   Ethernet        6
+   *   802.3           7
+   *   Token Ring      9
+   *   FDDI            15
+   *
+   * and the ifType value for a loopback device is 24.
+   *
+   * The AIX names for LAN devices begin with:
+   *
+   *   Ethernet                en
+   *   802.3                   et
+   *   Token Ring              tr
+   *   FDDI                    fi
+   *
+   * and the AIX names for loopback devices begin with "lo".
+   *
+   * (The difference between "Ethernet" and "802.3" is presumably
+   * whether packets have an Ethernet header, with a packet type,
+   * or an 802.3 header, with a packet length, followed by an 802.2
+   * header and possibly a SNAP header.)
+   *
+   * If the device name matches "linktype" interpreted as an ifType
+   * value, rather than as a DLT_ value, we will assume this is AIX's
+   * non-standard, incompatible libpcap, rather than a standard libpcap,
+   * and will map the link-layer type to the standard DLT_ value for
+   * that link-layer type, as that's what the rest of Wireshark expects.
+   *
+   * (This means the capture files won't be readable by a tcpdump
+   * linked with AIX's non-standard libpcap, but so it goes.  They
+   * *will* be readable by standard versions of tcpdump, Wireshark,
+   * and so on.)
+   *
+   * XXX - if we conclude we're using AIX libpcap, should we also
+   * set a flag to cause us to assume the time stamps are in
+   * seconds-and-nanoseconds form, and to convert them to
+   * seconds-and-microseconds form before processing them and
+   * writing them out?
+   */
+
+  /*
+   * Find the last component of the device name, which is the
+   * interface name.
+   */
+  ifacename = strchr(devname, '/');
+  if (ifacename == NULL)
+    ifacename = devname;
+
+  /* See if it matches any of the LAN device names. */
+  if (strncmp(ifacename, "en", 2) == 0) {
+    if (linktype == 6) {
+      /*
+       * That's the RFC 1573 value for Ethernet; map it to DLT_EN10MB.
+       */
+      linktype = 1;
+    }
+  } else if (strncmp(ifacename, "et", 2) == 0) {
+    if (linktype == 7) {
+      /*
+       * That's the RFC 1573 value for 802.3; map it to DLT_EN10MB.
+       * (libpcap, tcpdump, Wireshark, etc. don't care if it's Ethernet
+       * or 802.3.)
+       */
+      linktype = 1;
+    }
+  } else if (strncmp(ifacename, "tr", 2) == 0) {
+    if (linktype == 9) {
+      /*
+       * That's the RFC 1573 value for 802.5 (Token Ring); map it to
+       * DLT_IEEE802, which is what's used for Token Ring.
+       */
+      linktype = 6;
+    }
+  } else if (strncmp(ifacename, "fi", 2) == 0) {
+    if (linktype == 15) {
+      /*
+       * That's the RFC 1573 value for FDDI; map it to DLT_FDDI.
+       */
+      linktype = 10;
+    }
+  } else if (strncmp(ifacename, "lo", 2) == 0) {
+    if (linktype == 24) {
+      /*
+       * That's the RFC 1573 value for "software loopback" devices; map it
+       * to DLT_NULL, which is what's used for loopback devices on BSD.
+       */
+      linktype = 0;
+    }
+  }
+#endif
+
+  return linktype;
+}
+
+static data_link_info_t *
+create_data_link_info(int dlt)
+{
+  data_link_info_t *data_link_info;
+  const char *text;
+
+  data_link_info = (data_link_info_t *)g_malloc(sizeof (data_link_info_t));
+  data_link_info->dlt = dlt;
+  text = pcap_datalink_val_to_name(dlt);
+  if (text != NULL)
+    data_link_info->name = g_strdup(text);
+  else
+    data_link_info->name = g_strdup_printf("DLT %d", dlt);
+  text = pcap_datalink_val_to_description(dlt);
+  if (text != NULL)
+    data_link_info->description = g_strdup(text);
+  else
+    data_link_info->description = NULL;
+  return data_link_info;
+}
+
+/*
+ * Get the capabilities of a network device.
+ */
+static if_capabilities_t *
+get_if_capabilities(const char *devname, gboolean monitor_mode
+#ifndef HAVE_PCAP_CREATE
+       _U_
+#endif
+, char **err_str)
+{
+    if_capabilities_t *caps;
+    char errbuf[PCAP_ERRBUF_SIZE];
+    pcap_t *pch;
+#ifdef HAVE_PCAP_CREATE
+    int status;
+#endif
+    int deflt;
+#ifdef HAVE_PCAP_LIST_DATALINKS
+    int *linktypes;
+    int i, nlt;
+#endif
+    data_link_info_t *data_link_info;
+
+    /*
+     * Allocate the interface capabilities structure.
+     */
+    caps = g_malloc(sizeof *caps);
+
+#ifdef HAVE_PCAP_OPEN
+    pch = pcap_open(devname, MIN_PACKET_SIZE, 0, 0, NULL, errbuf);
+    caps->can_set_rfmon = FALSE;
+    if (pch == NULL) {
+        if (err_str != NULL)
+            *err_str = g_strdup(errbuf);
+        g_free(caps);
+        return NULL;
+    }
+#elif defined(HAVE_PCAP_CREATE)
+    pch = pcap_create(devname, errbuf);
+    if (pch == NULL) {
+        if (err_str != NULL)
+            *err_str = g_strdup(errbuf);
+        g_free(caps);
+        return NULL;
+    }
+    status = pcap_can_set_rfmon(pch);
+    if (status < 0) {
+        /* Error. */
+        if (status == PCAP_ERROR)
+            *err_str = g_strdup_printf("pcap_can_set_rfmon() failed: %s",
+                                       pcap_geterr(pch));
+        else
+            *err_str = g_strdup(pcap_statustostr(status));
+        pcap_close(pch);
+        g_free(caps);
+        return NULL;
+    }
+    if (status == 0)
+        caps->can_set_rfmon = FALSE;
+    else if (status == 1) {
+        caps->can_set_rfmon = TRUE;
+        if (monitor_mode)
+            pcap_set_rfmon(pch, 1);
+    } else {
+        if (err_str != NULL) {
+            *err_str = g_strdup_printf("pcap_can_set_rfmon() returned %d",
+                                       status);
+        }
+        pcap_close(pch);
+        g_free(caps);
+        return NULL;
+    }
+
+    status = pcap_activate(pch);
+    if (status < 0) {
+        /* Error.  We ignore warnings (status > 0). */
+        if (err_str != NULL) {
+            if (status == PCAP_ERROR)
+                *err_str = g_strdup_printf("pcap_activate() failed: %s",
+                                           pcap_geterr(pch));
+            else
+                *err_str = g_strdup(pcap_statustostr(status));
+        }
+        pcap_close(pch);
+        g_free(caps);
+        return NULL;
+    }
+#else
+    pch = pcap_open_live(devname, MIN_PACKET_SIZE, 0, 0, errbuf);
+    caps->can_set_rfmon = FALSE;
+    if (pch == NULL) {
+        if (err_str != NULL)
+            *err_str = g_strdup(errbuf);
+        g_free(caps);
+        return NULL;
+    }
+#endif
+    deflt = get_pcap_linktype(pch, devname);
+#ifdef HAVE_PCAP_LIST_DATALINKS
+    nlt = pcap_list_datalinks(pch, &linktypes);
+    if (nlt == 0 || linktypes == NULL) {
+        pcap_close(pch);
+        if (err_str != NULL)
+            *err_str = NULL; /* an empty list doesn't mean an error */
+        return NULL;
+    }
+    caps->data_link_types = NULL;
+    for (i = 0; i < nlt; i++) {
+        data_link_info = create_data_link_info(linktypes[i]);
+
+        /*
+         * XXX - for 802.11, make the most detailed 802.11
+         * version the default, rather than the one the
+         * device has as the default?
+         */
+        if (linktypes[i] == deflt)
+            caps->data_link_types = g_list_prepend(caps->data_link_types,
+                                                   data_link_info);
+        else
+            caps->data_link_types = g_list_append(caps->data_link_types,
+                                                  data_link_info);
+    }
+#ifdef HAVE_PCAP_FREE_DATALINKS
+    pcap_free_datalinks(linktypes);
+#else
+    /*
+     * In Windows, there's no guarantee that if you have a library
+     * built with one version of the MSVC++ run-time library, and
+     * it returns a pointer to allocated data, you can free that
+     * data from a program linked with another version of the
+     * MSVC++ run-time library.
+     *
+     * This is not an issue on UN*X.
+     *
+     * See the mail threads starting at
+     *
+     *    http://www.winpcap.org/pipermail/winpcap-users/2006-September/001421.html
+     *
+     * and
+     *
+     *    http://www.winpcap.org/pipermail/winpcap-users/2008-May/002498.html
+     */
+#ifndef _WIN32
+#define xx_free free  /* hack so checkAPIs doesn't complain */
+    xx_free(linktypes);
+#endif /* _WIN32 */
+#endif /* HAVE_PCAP_FREE_DATALINKS */
+#else /* HAVE_PCAP_LIST_DATALINKS */
+
+    data_link_info = create_data_link_info(deflt);
+    caps->data_link_types = g_list_append(caps->data_link_types,
+                                          data_link_info);
+#endif /* HAVE_PCAP_LIST_DATALINKS */
+
+    pcap_close(pch);
+
+    if (err_str != NULL)
+        *err_str = NULL;
+    return caps;
+}
+
+#define ADDRSTRLEN 46 /* Covers IPv4 & IPv6 */
+static void
+print_machine_readable_interfaces(GList *if_list)
+{
+    int         i;
+    GList       *if_entry;
+    if_info_t   *if_info;
+    GSList      *addr;
+    if_addr_t   *if_addr;
+    char        addr_str[ADDRSTRLEN];
+
+    if (capture_child) {
+        /* Let our parent know we succeeded. */
+        pipe_write_block(2, SP_SUCCESS, NULL);
+    }
+
+    i = 1;  /* Interface id number */
+    for (if_entry = g_list_first(if_list); if_entry != NULL;
+         if_entry = g_list_next(if_entry)) {
+        if_info = (if_info_t *)if_entry->data;
+        printf("%d. %s", i++, if_info->name);
+
+        /*
+         * Print the contents of the if_entry struct in a parseable format.
+         * Each if_entry element is tab-separated.  Addresses are comma-
+         * separated.
+         */
+        /* XXX - Make sure our description doesn't contain a tab */
+        if (if_info->description != NULL)
+            printf("\t%s\t", if_info->description);
+        else
+            printf("\t\t");
+
+        for(addr = g_slist_nth(if_info->addrs, 0); addr != NULL;
+                    addr = g_slist_next(addr)) {
+            if (addr != g_slist_nth(if_info->addrs, 0))
+                printf(",");
+
+            if_addr = (if_addr_t *)addr->data;
+            switch(if_addr->ifat_type) {
+            case IF_AT_IPv4:
+                if (inet_ntop(AF_INET, &if_addr->addr.ip4_addr, addr_str,
+                              ADDRSTRLEN)) {
+                    printf("%s", addr_str);
+                } else {
+                    printf("<unknown IPv4>");
+                }
+                break;
+            case IF_AT_IPv6:
+                if (inet_ntop(AF_INET6, &if_addr->addr.ip6_addr,
+                              addr_str, ADDRSTRLEN)) {
+                    printf("%s", addr_str);
+                } else {
+                    printf("<unknown IPv6>");
+                }
+                break;
+            default:
+                printf("<type unknown %u>", if_addr->ifat_type);
+            }
+        }
+
+        if (if_info->loopback)
+            printf("\tloopback");
+        else
+            printf("\tnetwork");
+
+        printf("\n");
+    }
+}
+
+/*
+ * If you change the machine-readable output format of this function,
+ * you MUST update capture_ifinfo.c:capture_get_if_capabilities() accordingly!
+ */
+static void
+print_machine_readable_if_capabilities(if_capabilities_t *caps)
+{
+    GList *lt_entry;
+    data_link_info_t *data_link_info;
+    const gchar *desc_str;
+
+    if (capture_child) {
+        /* Let our parent know we succeeded. */
+        pipe_write_block(2, SP_SUCCESS, NULL);
+    }
+
+    if (caps->can_set_rfmon)
+        printf("1\n");
+    else
+        printf("0\n");
+    for (lt_entry = caps->data_link_types; lt_entry != NULL;
+         lt_entry = g_list_next(lt_entry)) {
+      data_link_info = (data_link_info_t *)lt_entry->data;
+      if (data_link_info->description != NULL)
+        desc_str = data_link_info->description;
+      else
+        desc_str = "(not supported)";
+      printf("%d\t%s\t%s\n", data_link_info->dlt, data_link_info->name,
+             desc_str);
+    }
+}
+
+typedef struct {
+    char *name;
+    pcap_t *pch;
+} if_stat_t;
+
+/* Print the number of packets captured for each interface until we're killed. */
+static int
+print_statistics_loop(gboolean machine_readable)
+{
+    GList       *if_list, *if_entry, *stat_list = NULL, *stat_entry;
+    if_info_t   *if_info;
+    if_stat_t   *if_stat;
+    int         err;
+    gchar       *err_str;
+    pcap_t      *pch;
+    char        errbuf[PCAP_ERRBUF_SIZE];
+    struct pcap_stat ps;
+
+    if_list = get_interface_list(&err, &err_str);
+    if (if_list == NULL) {
+        switch (err) {
+        case CANT_GET_INTERFACE_LIST:
+            cmdarg_err("%s", err_str);
+            g_free(err_str);
+            break;
+
+        case NO_INTERFACES_FOUND:
+            cmdarg_err("There are no interfaces on which a capture can be done");
+            break;
+        }
+        return err;
+    }
+
+    for (if_entry = g_list_first(if_list); if_entry != NULL; if_entry = g_list_next(if_entry)) {
+        if_info = (if_info_t *)if_entry->data;
+#ifdef HAVE_PCAP_OPEN
+        pch = pcap_open(if_info->name, MIN_PACKET_SIZE, 0, 0, NULL, errbuf);
+#else
+        pch = pcap_open_live(if_info->name, MIN_PACKET_SIZE, 0, 0, errbuf);
+#endif
+
+        if (pch) {
+            if_stat = (if_stat_t *)g_malloc(sizeof(if_stat_t));
+            if_stat->name = g_strdup(if_info->name);
+            if_stat->pch = pch;
+            stat_list = g_list_append(stat_list, if_stat);
+        }
+    }
+
+    if (!stat_list) {
+        cmdarg_err("There are no interfaces on which a capture can be done");
+        return 2;
+    }
+
+    if (capture_child) {
+        /* Let our parent know we succeeded. */
+        pipe_write_block(2, SP_SUCCESS, NULL);
+    }
+
+    if (!machine_readable) {
+        printf("%-15s  %10s  %10s\n", "Interface", "Received",
+            "Dropped");
+    }
+
+    global_ld.go = TRUE;
+    while (global_ld.go) {
+        for (stat_entry = g_list_first(stat_list); stat_entry != NULL; stat_entry = g_list_next(stat_entry)) {
+            if_stat = (if_stat_t *)stat_entry->data;
+            pcap_stats(if_stat->pch, &ps);
+
+            if (!machine_readable) {
+                printf("%-15s  %10u  %10u\n", if_stat->name,
+                    ps.ps_recv, ps.ps_drop);
+            } else {
+                printf("%s\t%u\t%u\n", if_stat->name,
+                    ps.ps_recv, ps.ps_drop);
+                fflush(stdout);
+            }
+        }
+#ifdef _WIN32
+        if (! global_ld.from_cap_pipe)
+            Sleep(1 * 1000);
+#else
+        sleep(1);
+#endif
+    }
+
+    /* XXX - Not reached.  Should we look for 'q' in stdin? */
+    for (stat_entry = g_list_first(stat_list); stat_entry != NULL; stat_entry = g_list_next(stat_entry)) {
+        if_stat = (if_stat_t *)stat_entry->data;
+        pcap_close(if_stat->pch);
+        g_free(if_stat->name);
+        g_free(if_stat);
+    }
+    g_list_free(stat_list);
+    free_interface_list(if_list);
+
+    return 0;
+}
+
 
 #ifdef _WIN32
 static BOOL WINAPI
-capture_cleanup(DWORD dwCtrlType)
+capture_cleanup_handler(DWORD dwCtrlType)
 {
     /* CTRL_C_EVENT is sort of like SIGINT, CTRL_BREAK_EVENT is unique to
        Windows, CTRL_CLOSE_EVENT is sort of like SIGHUP, CTRL_LOGOFF_EVENT
@@ -430,21 +1324,54 @@ capture_cleanup(DWORD dwCtrlType)
 }
 #else
 static void
-capture_cleanup(int signum)
+capture_cleanup_handler(int signum _U_)
 {
     /* On UN*X, we cleanly shut down the capture on SIGINT, SIGHUP, and
        SIGTERM.  We assume that if the user wanted it to keep running
        after they logged out, they'd have nohupped it. */
 
-    g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
-        "Console: Signal");
-    g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
-        "Console: Signal, signal value: %u", signum);
+    /* Note: don't call g_log() in the signal handler: if we happened to be in
+     * g_log() in process context when the signal came in, g_log will detect
+     * the "recursion" and abort.
+     */
 
     capture_loop_stop();
 }
 #endif
 
+
+#ifdef SIGINFO
+static void
+report_counts(void)
+{
+  /* Don't print this if we're a capture child. */
+  if (!capture_child) {
+    if (quiet) {
+      /* Report the count only if we aren't printing a packet count
+         as packets arrive. */
+      fprintf(stderr, "%u packet%s captured\n", global_ld.packet_count,
+              plurality(global_ld.packet_count, "", "s"));
+    }
+  }
+  infoprint = FALSE; /* we just reported it */
+}
+
+static void
+report_counts_siginfo(int signum _U_)
+{
+  int sav_errno = errno;
+
+  /* If we've been told to delay printing, just set a flag asking
+     that we print counts (if we're supposed to), otherwise print
+     the count of packets captured (if we're supposed to). */
+  if (infodelay)
+    infoprint = TRUE;
+  else
+    report_counts();
+  errno = sav_errno;
+}
+#endif /* SIGINFO */
+
 static void exit_main(int status)
 {
 #ifdef _WIN32
@@ -468,24 +1395,6 @@ static void exit_main(int status)
  * CAP_NET_ADMIN and CAP_NET_RAW, then relinquish our permissions.
  * (See comment in main() for details)
  */
-
-static void
-#if 0 /* Set to enable capability debugging */
-/* see 'man cap_to_text()' for explanation of output                         */
-/* '='   means 'all= '  ie: no capabilities                                  */
-/* '=ip' means 'all=ip' ie: all capabilities are permissible and inheritable */
-/* ....                                                                      */
-print_caps(char *pfx) {
-    cap_t caps = cap_get_proc();
-    g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
-          "%s: EUID: %d  Capabilities: %s", pfx,
-          geteuid(), cap_to_text(caps, NULL));
-    cap_free(caps);
-#else
-print_caps(char *pfx _U_) {
-#endif
-}
-
 static void
 relinquish_privs_except_capture(void)
 {
@@ -531,21 +1440,6 @@ relinquish_privs_except_capture(void)
     }
 }
 
-
-static void
-relinquish_all_capabilities()
-{
-    /* Drop any and all capabilities this process may have.            */
-    /* Allowed whether or not process has any privileges.              */
-    cap_t caps = cap_init();    /* all capabilities initialized to off */
-    print_caps("Pre-clear");
-    if (cap_set_proc(caps)) {
-        cmdarg_err("cap_set_proc() fail return: %s", strerror(errno));
-    }
-    print_caps("Post-clear");
-    cap_free(caps);
-}
-
 #endif /* HAVE_LIBCAP */
 
 /* Take care of byte order in the libpcap headers read from pipes.
@@ -579,18 +1473,100 @@ cap_pipe_adjust_header(gboolean byte_swapped, struct pcap_hdr *hdr, struct pcapr
   }
 }
 
-/* Provide select() functionality for a single file descriptor
- * on both UNIX/POSIX and Windows.
+#ifdef USE_THREADS
+/*
+ * Thread function that reads from a pipe and pushes the data
+ * to the main application thread.
+ */
+/*
+ * XXX Right now we use async queues for basic signaling. The main thread
+ * sets cap_pipe_buf and cap_bytes_to_read, then pushes an item onto
+ * cap_pipe_pending_q which triggers a read in the cap_pipe_read thread.
+ * Iff the read is successful cap_pipe_read pushes an item onto
+ * cap_pipe_done_q, otherwise an error is signaled. No data is passed in
+ * the queues themselves (yet).
  *
- * The Windows version calls WaitForSingleObject instead of
- * select().
+ * We might want to move some of the cap_pipe_dispatch logic here so that
+ * we can let cap_pipe_read run independently, queuing up multiple reads
+ * for the main thread (and possibly get rid of cap_pipe_read_mtx).
+ */
+static void *cap_pipe_read(void *ld_ptr) {
+    loop_data *ld = (loop_data *)ld_ptr;
+    int bytes_read;
+#ifdef _WIN32
+    BOOL res;
+    DWORD b, last_err;
+#else /* _WIN32 */
+    int b;
+#endif /* _WIN32 */
+
+    while (ld->cap_pipe_err == PIPOK) {
+        g_async_queue_pop(cap_pipe_pending_q); /* Wait for our cue (ahem) from the main thread */
+        g_mutex_lock(cap_pipe_read_mtx);
+        bytes_read = 0;
+        while (bytes_read < (int) ld->cap_pipe_bytes_to_read) {
+#ifdef _WIN32
+            /* If we try to use read() on a named pipe on Windows with partial
+             * data it appears to return EOF.
+             */
+            res = ReadFile(ld->cap_pipe_h, ld->cap_pipe_buf+bytes_read,
+                           ld->cap_pipe_bytes_to_read - bytes_read,
+                           &b, NULL);
+
+            bytes_read += b;
+            if (!res) {
+                last_err = GetLastError();
+                if (last_err == ERROR_MORE_DATA) {
+                    continue;
+                } else if (last_err == ERROR_HANDLE_EOF || last_err == ERROR_BROKEN_PIPE || last_err == ERROR_PIPE_NOT_CONNECTED) {
+                    ld->cap_pipe_err = PIPEOF;
+                    bytes_read = 0;
+                    break;
+                }
+                ld->cap_pipe_err = PIPERR;
+                bytes_read = -1;
+                break;
+            } else if (b == 0 && ld->cap_pipe_bytes_to_read > 0) {
+                ld->cap_pipe_err = PIPEOF;
+                bytes_read = 0;
+                break;
+            }
+#else /* _WIN32 */
+            b = read(ld->cap_pipe_fd, ld->cap_pipe_buf+bytes_read,
+                     ld->cap_pipe_bytes_to_read - bytes_read);
+            if (b <= 0) {
+                if (b == 0) {
+                    ld->cap_pipe_err = PIPEOF;
+                    bytes_read = 0;
+                    break;
+                } else {
+                    ld->cap_pipe_err = PIPERR;
+                    bytes_read = -1;
+                    break;
+                }
+            } else {
+                bytes_read += b;
+            }
+#endif /*_WIN32 */
+        }
+        ld->cap_pipe_bytes_read = bytes_read;
+        if (ld->cap_pipe_bytes_read >= ld->cap_pipe_bytes_to_read) {
+            g_async_queue_push(cap_pipe_done_q, ld->cap_pipe_buf); /* Any non-NULL value will do */
+        }
+        g_mutex_unlock(cap_pipe_read_mtx);
+    }
+    return NULL;
+}
+#endif /* USE_THREADS */
+
+/* Provide select() functionality for a single file descriptor
+ * on UNIX/POSIX. Windows uses cap_pipe_read via a thread.
  *
  * Returns the same values as select.  If an error is returned,
  * the string cap_pipe_err_str should be used instead of errno.
  */
 static int
 cap_pipe_select(int pipe_fd) {
-#ifndef _WIN32
   fd_set      rfds;
   struct timeval timeout, *pto;
   int sel_ret;
@@ -609,98 +1585,123 @@ cap_pipe_select(int pipe_fd) {
     cap_pipe_err_str = strerror(errno);
   return sel_ret;
 }
-#else
-  /* XXX - Should we just use file handles exclusively under Windows?
-   * Otherwise we have to convert between file handles and file descriptors
-   * here and when we open a named pipe.
-   */
-  HANDLE hPipe = (HANDLE) _get_osfhandle(pipe_fd);
-  wchar_t *err_str;
-  DWORD wait_ret;
-
-  if (hPipe == INVALID_HANDLE_VALUE) {
-    cap_pipe_err_str = "Could not open standard input";
-    return -1;
-  }
-
-  cap_pipe_err_str = "Unknown error";
-
-  wait_ret = WaitForSingleObject(hPipe, CAP_READ_TIMEOUT);
-  switch (wait_ret) {
-    /* XXX - This probably isn't correct */
-    case WAIT_ABANDONED:
-      errno = EINTR;
-      return -1;
-    case WAIT_OBJECT_0:
-      return 1;
-    case WAIT_TIMEOUT:
-      return 0;
-    case WAIT_FAILED:
-      FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
-        NULL, GetLastError(), 0, (LPTSTR) &err_str, 0, NULL);
-      cap_pipe_err_str = utf_16to8(err_str);
-      LocalFree(err_str);
-      return -1;
-    default:
-      g_assert_not_reached();
-      return -1;
-  }
-}
-#endif
 
 
 /* Mimic pcap_open_live() for pipe captures
- * We check if "pipename" is "-" (stdin) or a FIFO, open it, and read the
- * header.
+
+ * We check if "pipename" is "-" (stdin), a AF_UNIX socket, 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
+static void
 cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
-                 char *errmsg, int errmsgl)
+                   char *errmsg, int errmsgl)
 {
 #ifndef _WIN32
   struct stat pipe_stat;
-#else
+  struct sockaddr_un sa;
+  int          sel_ret;
+  int          b;
+  unsigned int bytes_read;
+  int          fd;
+#else /* _WIN32 */
 #if 1
   char *pncopy, *pos;
   wchar_t *err_str;
 #endif
-  HANDLE hPipe = NULL;
 #endif
-  int          sel_ret;
-  int          fd;
-  int          b;
-  guint32       magic;
-  unsigned int bytes_read;
+  guint32       magic = 0;
 
+#ifndef _WIN32
+  ld->cap_pipe_fd = -1;
+#else
+  ld->cap_pipe_h = INVALID_HANDLE_VALUE;
+#endif
   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "cap_pipe_open_live: %s", pipename);
 
   /*
-   * XXX (T)Wireshark blocks until we return
+   * XXX - this blocks until a pcap per-file header has been written to
+   * the pipe, so it could block indefinitely.
    */
   if (strcmp(pipename, "-") == 0) {
+#ifndef _WIN32
     fd = 0; /* read from stdin */
-#ifdef _WIN32
-    /*
-     * This is needed to set the stdin pipe into binary mode, otherwise
-     * CR/LF are mangled...
-     */
-    _setmode(0, _O_BINARY);
+#else /* _WIN32 */
+    ld->cap_pipe_h = GetStdHandle(STD_INPUT_HANDLE);
 #endif  /* _WIN32 */
   } else {
 #ifndef _WIN32
-    if (eth_stat(pipename, &pipe_stat) < 0) {
+    if (ws_stat(pipename, &pipe_stat) < 0) {
       if (errno == ENOENT || errno == ENOTDIR)
         ld->cap_pipe_err = PIPNEXIST;
       else {
         g_snprintf(errmsg, errmsgl,
           "The capture session could not be initiated "
-          "due to error on pipe: %s", strerror(errno));
+          "due to error getting information on pipe/socket: %s", strerror(errno));
         ld->cap_pipe_err = PIPERR;
       }
-      return -1;
+      return;
     }
-    if (! S_ISFIFO(pipe_stat.st_mode)) {
+    if (S_ISFIFO(pipe_stat.st_mode)) {
+      fd = ws_open(pipename, O_RDONLY | O_NONBLOCK, 0000 /* no creation so don't matter */);
+      if (fd == -1) {
+        g_snprintf(errmsg, errmsgl,
+            "The capture session could not be initiated "
+            "due to error on pipe open: %s", strerror(errno));
+        ld->cap_pipe_err = PIPERR;
+        return;
+      }
+    } else if (S_ISSOCK(pipe_stat.st_mode)) {
+      fd = socket(AF_UNIX, SOCK_STREAM, 0);
+      if (fd == -1) {
+        g_snprintf(errmsg, errmsgl,
+           "The capture session could not be initiated "
+           "due to error on socket create: %s", strerror(errno));
+        ld->cap_pipe_err = PIPERR;
+       return;
+      }
+      sa.sun_family = AF_UNIX;
+      /*
+       * The Single UNIX Specification says:
+       *
+       *   The size of sun_path has intentionally been left undefined.
+       *   This is because different implementations use different sizes.
+       *   For example, 4.3 BSD uses a size of 108, and 4.4 BSD uses a size
+       *   of 104. Since most implementations originate from BSD versions,
+       *   the size is typically in the range 92 to 108.
+       *
+       *   Applications should not assume a particular length for sun_path
+       *   or assume that it can hold {_POSIX_PATH_MAX} bytes (256).
+       *
+       * It also says
+       *
+       *   The <sys/un.h> header shall define the sockaddr_un structure,
+       *   which shall include at least the following members:
+       *
+       *   sa_family_t  sun_family  Address family.
+       *   char         sun_path[]  Socket pathname.
+       *
+       * so we assume that it's an array, with a specified size,
+       * and that the size reflects the maximum path length.
+       */
+      if (g_strlcpy(sa.sun_path, pipename, sizeof sa.sun_path) > sizeof sa.sun_path) {
+        /* Path name too long */
+        g_snprintf(errmsg, errmsgl,
+           "The capture session coud not be initiated "
+           "due to error on socket connect: Path name too long");
+        ld->cap_pipe_err = PIPERR;
+       return;
+      }
+      b = connect(fd, (struct sockaddr *)&sa, sizeof sa);
+      if (b == -1) {
+        g_snprintf(errmsg, errmsgl,
+           "The capture session coud not be initiated "
+           "due to error on socket connect: %s", strerror(errno));
+        ld->cap_pipe_err = PIPERR;
+       return;
+      }
+    } else {
       if (S_ISCHR(pipe_stat.st_mode)) {
         /*
          * Assume the user specified an interface on a system where
@@ -711,18 +1712,10 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
       {
         g_snprintf(errmsg, errmsgl,
             "The capture session could not be initiated because\n"
-            "\"%s\" is neither an interface nor a pipe", pipename);
+            "\"%s\" is neither an interface nor a socket nor a pipe", pipename);
         ld->cap_pipe_err = PIPERR;
       }
-      return -1;
-    }
-    fd = eth_open(pipename, O_RDONLY | O_NONBLOCK, 0000 /* no creation so don't matter */);
-    if (fd == -1) {
-      g_snprintf(errmsg, errmsgl,
-          "The capture session could not be initiated "
-          "due to error on pipe open: %s", strerror(errno));
-      ld->cap_pipe_err = PIPERR;
-      return -1;
+      return;
     }
 #else /* _WIN32 */
 #define PIPE_STR "\\pipe\\"
@@ -743,55 +1736,47 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
           "The capture session could not be initiated because\n"
           "\"%s\" is neither an interface nor a pipe", pipename);
       ld->cap_pipe_err = PIPNEXIST;
-      return -1;
+      return;
     }
 
     /* Wait for the pipe to appear */
     while (1) {
-      hPipe = CreateFile(utf_8to16(pipename), GENERIC_READ, 0, NULL,
+      ld->cap_pipe_h = CreateFile(utf_8to16(pipename), GENERIC_READ, 0, NULL,
           OPEN_EXISTING, 0, NULL);
 
-      if (hPipe != INVALID_HANDLE_VALUE)
+      if (ld->cap_pipe_h != INVALID_HANDLE_VALUE)
         break;
 
       if (GetLastError() != ERROR_PIPE_BUSY) {
         FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
           NULL, GetLastError(), 0, (LPTSTR) &err_str, 0, NULL);
         g_snprintf(errmsg, errmsgl,
-            "The capture session on \"%s\" could not be initiated "
-            "due to error on pipe open: pipe busy: %s (error %d)",
-           pipename, utf_16to8(err_str), GetLastError());
+            "The capture session on \"%s\" could not be started "
+            "due to error on pipe open: %s (error %d)",
+            pipename, utf_16to8(err_str), GetLastError());
         LocalFree(err_str);
         ld->cap_pipe_err = PIPERR;
-        return -1;
+        return;
       }
 
       if (!WaitNamedPipe(utf_8to16(pipename), 30 * 1000)) {
         FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
           NULL, GetLastError(), 0, (LPTSTR) &err_str, 0, NULL);
         g_snprintf(errmsg, errmsgl,
-            "The capture session could not be initiated "
-            "due to error on named pipe open: %s (error %d)",
-           utf_16to8(err_str), GetLastError());
+            "The capture session on \"%s\" timed out during "
+            "pipe open: %s (error %d)",
+            pipename, utf_16to8(err_str), GetLastError());
         LocalFree(err_str);
         ld->cap_pipe_err = PIPERR;
-        return -1;
+        return;
       }
     }
-
-    fd = _open_osfhandle((long) hPipe, _O_RDONLY);
-    if (fd == -1) {
-      g_snprintf(errmsg, errmsgl,
-          "The capture session could not be initiated "
-          "due to error on pipe open: %s", strerror(errno));
-      ld->cap_pipe_err = PIPERR;
-      return -1;
-    }
 #endif /* _WIN32 */
   }
 
   ld->from_cap_pipe = TRUE;
 
+#ifndef USE_THREADS
   /* read the pcap header */
   bytes_read = 0;
   while (bytes_read < sizeof magic) {
@@ -804,15 +1789,34 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
       b = read(fd, ((char *)&magic)+bytes_read, sizeof magic-bytes_read);
       if (b <= 0) {
         if (b == 0)
-          g_snprintf(errmsg, errmsgl, "End of file on pipe during open");
+          g_snprintf(errmsg, errmsgl, "End of file on pipe magic during open");
         else
-          g_snprintf(errmsg, errmsgl, "Error on pipe during open: %s",
+          g_snprintf(errmsg, errmsgl, "Error on pipe magic during open: %s",
             strerror(errno));
         goto error;
       }
       bytes_read += b;
     }
   }
+#else /* USE_THREADS */
+  g_thread_create(&cap_pipe_read, ld, FALSE, NULL);
+
+  ld->cap_pipe_buf = (char *) &magic;
+  ld->cap_pipe_bytes_read = 0;
+  ld->cap_pipe_bytes_to_read = sizeof(magic);
+  /* We don't have to worry about cap_pipe_read_mtx here */
+  g_async_queue_push(cap_pipe_pending_q, ld->cap_pipe_buf);
+  g_async_queue_pop(cap_pipe_done_q);
+  if (ld->cap_pipe_bytes_read <= 0) {
+    if (ld->cap_pipe_bytes_read == 0)
+      g_snprintf(errmsg, errmsgl, "End of file on pipe magic during open");
+    else
+      g_snprintf(errmsg, errmsgl, "Error on pipe magic during open: %s",
+                 strerror(errno));
+    goto error;
+  }
+
+#endif /* USE_THREADS */
 
   switch (magic) {
   case PCAP_MAGIC:
@@ -847,6 +1851,7 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
     goto error;
   }
 
+#ifndef USE_THREADS
   /* Read the rest of the header */
   bytes_read = 0;
   while (bytes_read < sizeof(struct pcap_hdr)) {
@@ -860,15 +1865,30 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
             sizeof(struct pcap_hdr) - bytes_read);
       if (b <= 0) {
         if (b == 0)
-          g_snprintf(errmsg, errmsgl, "End of file on pipe during open");
+          g_snprintf(errmsg, errmsgl, "End of file on pipe header during open");
         else
-          g_snprintf(errmsg, errmsgl, "Error on pipe during open: %s",
+          g_snprintf(errmsg, errmsgl, "Error on pipe header during open: %s",
             strerror(errno));
         goto error;
       }
       bytes_read += b;
     }
   }
+#else /* USE_THREADS */
+  ld->cap_pipe_buf = (char *) hdr;
+  ld->cap_pipe_bytes_read = 0;
+  ld->cap_pipe_bytes_to_read = sizeof(struct pcap_hdr);
+  g_async_queue_push(cap_pipe_pending_q, ld->cap_pipe_buf);
+  g_async_queue_pop(cap_pipe_done_q);
+  if (ld->cap_pipe_bytes_read <= 0) {
+    if (ld->cap_pipe_bytes_read == 0)
+      g_snprintf(errmsg, errmsgl, "End of file on pipe header during open");
+    else
+      g_snprintf(errmsg, errmsgl, "Error on pipe header header during open: %s",
+            strerror(errno));
+    goto error;
+  }
+#endif /* USE_THREADS */
 
   if (ld->cap_pipe_byte_swapped) {
     /* Byte-swap the header fields about which we care. */
@@ -886,13 +1906,19 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
 
   ld->cap_pipe_state = STATE_EXPECT_REC_HDR;
   ld->cap_pipe_err = PIPOK;
-  return fd;
+#ifndef _WIN32
+  ld->cap_pipe_fd = fd;
+#endif
+  return;
 
 error:
   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "cap_pipe_open_live: error %s", errmsg);
   ld->cap_pipe_err = PIPERR;
-  eth_close(fd);
-  return -1;
+#ifndef _WIN32
+  ws_close(fd);
+  ld->cap_pipe_fd = -1;
+#endif
+  return;
 
 }
 
@@ -903,10 +1929,17 @@ static int
 cap_pipe_dispatch(loop_data *ld, guchar *data, char *errmsg, int errmsgl)
 {
   struct pcap_pkthdr phdr;
-  int b;
   enum { PD_REC_HDR_READ, PD_DATA_READ, PD_PIPE_EOF, PD_PIPE_ERR,
-          PD_ERR } result;
-
+         PD_ERR } result;
+#ifdef USE_THREADS
+  GTimeVal wait_time;
+  gpointer q_status;
+#else
+  int b;
+#endif
+#ifdef _WIN32
+  wchar_t *err_str;
+#endif
 
 #ifdef LOG_CAPTURE_VERBOSE
   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "cap_pipe_dispatch");
@@ -915,13 +1948,25 @@ cap_pipe_dispatch(loop_data *ld, guchar *data, char *errmsg, int errmsgl)
   switch (ld->cap_pipe_state) {
 
   case STATE_EXPECT_REC_HDR:
+#ifdef USE_THREADS
+    if (g_mutex_trylock(cap_pipe_read_mtx)) {
+#endif
+
+    ld->cap_pipe_state = STATE_READ_REC_HDR;
     ld->cap_pipe_bytes_to_read = ld->cap_pipe_modified ?
       sizeof(struct pcaprec_modified_hdr) : sizeof(struct pcaprec_hdr);
     ld->cap_pipe_bytes_read = 0;
-    ld->cap_pipe_state = STATE_READ_REC_HDR;
+
+#ifdef USE_THREADS
+      ld->cap_pipe_buf = (char *) &ld->cap_pipe_rechdr;
+      g_async_queue_push(cap_pipe_pending_q, ld->cap_pipe_buf);
+      g_mutex_unlock(cap_pipe_read_mtx);
+    }
+#endif
     /* Fall through */
 
   case STATE_READ_REC_HDR:
+#ifndef USE_THREADS
     b = read(ld->cap_pipe_fd, ((char *)&ld->cap_pipe_rechdr)+ld->cap_pipe_bytes_read,
              ld->cap_pipe_bytes_to_read - ld->cap_pipe_bytes_read);
     if (b <= 0) {
@@ -931,19 +1976,48 @@ cap_pipe_dispatch(loop_data *ld, guchar *data, char *errmsg, int errmsgl)
         result = PD_PIPE_ERR;
       break;
     }
-    if ((ld->cap_pipe_bytes_read += b) < ld->cap_pipe_bytes_to_read)
+    ld->cap_pipe_bytes_read += b;
+#else /* USE_THREADS */
+    g_get_current_time(&wait_time);
+    g_time_val_add(&wait_time, THREAD_READ_TIMEOUT);
+    q_status = g_async_queue_timed_pop(cap_pipe_done_q, &wait_time);
+    if (ld->cap_pipe_err == PIPEOF) {
+      result = PD_PIPE_EOF;
+      break;
+    } else if (ld->cap_pipe_err == PIPERR) {
+      result = PD_PIPE_ERR;
+      break;
+    }
+    if (!q_status) {
+      return 0;
+    }
+#endif /* USE_THREADS */
+    if ((ld->cap_pipe_bytes_read) < ld->cap_pipe_bytes_to_read)
         return 0;
     result = PD_REC_HDR_READ;
     break;
 
   case STATE_EXPECT_DATA:
-    ld->cap_pipe_bytes_read = 0;
+#ifdef USE_THREADS
+    if (g_mutex_trylock(cap_pipe_read_mtx)) {
+#endif
+
     ld->cap_pipe_state = STATE_READ_DATA;
+    ld->cap_pipe_bytes_to_read = ld->cap_pipe_rechdr.hdr.incl_len;
+    ld->cap_pipe_bytes_read = 0;
+
+#ifdef USE_THREADS
+      ld->cap_pipe_buf = (char *) data;
+      g_async_queue_push(cap_pipe_pending_q, ld->cap_pipe_buf);
+      g_mutex_unlock(cap_pipe_read_mtx);
+    }
+#endif
     /* Fall through */
 
   case STATE_READ_DATA:
+#ifndef USE_THREADS
     b = read(ld->cap_pipe_fd, data+ld->cap_pipe_bytes_read,
-             ld->cap_pipe_rechdr.hdr.incl_len - ld->cap_pipe_bytes_read);
+             ld->cap_pipe_bytes_to_read - ld->cap_pipe_bytes_read);
     if (b <= 0) {
       if (b == 0)
         result = PD_PIPE_EOF;
@@ -951,8 +2025,24 @@ cap_pipe_dispatch(loop_data *ld, guchar *data, char *errmsg, int errmsgl)
         result = PD_PIPE_ERR;
       break;
     }
-    if ((ld->cap_pipe_bytes_read += b) < ld->cap_pipe_rechdr.hdr.incl_len)
+    ld->cap_pipe_bytes_read += b;
+#else /* USE_THREADS */
+    g_get_current_time(&wait_time);
+    g_time_val_add(&wait_time, THREAD_READ_TIMEOUT);
+    q_status = g_async_queue_timed_pop(cap_pipe_done_q, &wait_time);
+    if (ld->cap_pipe_err == PIPEOF) {
+      result = PD_PIPE_EOF;
+      break;
+    } else if (ld->cap_pipe_err == PIPERR) {
+      result = PD_PIPE_ERR;
+      break;
+    }
+    if (!q_status) {
       return 0;
+    }
+#endif /* USE_THREADS */
+    if ((ld->cap_pipe_bytes_read) < ld->cap_pipe_bytes_to_read)
+        return 0;
     result = PD_DATA_READ;
     break;
 
@@ -996,8 +2086,17 @@ cap_pipe_dispatch(loop_data *ld, guchar *data, char *errmsg, int errmsgl)
     return -1;
 
   case PD_PIPE_ERR:
+#ifdef _WIN32
+    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+      NULL, GetLastError(), 0, (LPTSTR) &err_str, 0, NULL);
+    g_snprintf(errmsg, errmsgl,
+        "Error reading from pipe: %s (error %d)",
+        utf_16to8(err_str), GetLastError());
+    LocalFree(err_str);
+#else
     g_snprintf(errmsg, errmsgl, "Error reading from pipe: %s",
       strerror(errno));
+#endif
     /* Fall through */
   case PD_ERR:
     break;
@@ -1018,19 +2117,12 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
 {
   gchar       open_err_str[PCAP_ERRBUF_SIZE];
   gchar      *sync_msg_str;
-  static const char ppamsg[] = "can't find PPA for ";
-  const char *set_linktype_err_str;
-  const char  *libpcap_warn;
 #ifdef _WIN32
-  gchar      *sync_secondary_msg_str;
   int         err;
+  gchar      *sync_secondary_msg_str;
   WORD        wVersionRequested;
   WSADATA     wsaData;
 #endif
-#ifdef HAVE_PCAP_REMOTE
-  struct pcap_rmtauth auth;
-#endif
-
 
   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_open_input : %s", capture_opts->iface);
 
@@ -1048,86 +2140,51 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
     switch (err) {
 
     case WSASYSNOTREADY:
-      g_snprintf(errmsg, errmsg_len,
+      g_snprintf(errmsg, (gulong) errmsg_len,
         "Couldn't initialize Windows Sockets: Network system not ready for network communication");
       break;
 
     case WSAVERNOTSUPPORTED:
-      g_snprintf(errmsg, errmsg_len,
+      g_snprintf(errmsg, (gulong) errmsg_len,
         "Couldn't initialize Windows Sockets: Windows Sockets version %u.%u not supported",
         LOBYTE(wVersionRequested), HIBYTE(wVersionRequested));
       break;
 
     case WSAEINPROGRESS:
-      g_snprintf(errmsg, errmsg_len,
+      g_snprintf(errmsg, (gulong) errmsg_len,
         "Couldn't initialize Windows Sockets: Blocking operation is in progress");
       break;
 
     case WSAEPROCLIM:
-      g_snprintf(errmsg, errmsg_len,
+      g_snprintf(errmsg, (gulong) errmsg_len,
         "Couldn't initialize Windows Sockets: Limit on the number of tasks supported by this WinSock implementation has been reached");
       break;
 
     case WSAEFAULT:
-      g_snprintf(errmsg, errmsg_len,
+      g_snprintf(errmsg, (gulong) errmsg_len,
         "Couldn't initialize Windows Sockets: Bad pointer passed to WSAStartup");
       break;
 
     default:
-      g_snprintf(errmsg, errmsg_len,
+      g_snprintf(errmsg, (gulong) errmsg_len,
         "Couldn't initialize Windows Sockets: error %d", err);
       break;
     }
-    g_snprintf(secondary_errmsg, secondary_errmsg_len, please_report);
+    g_snprintf(secondary_errmsg, (gulong) secondary_errmsg_len, please_report);
     return FALSE;
   }
 #endif
 
-  /* Open the network interface to capture from it.
-     Some versions of libpcap may put warnings into the error buffer
-     if they succeed; to tell if that's happened, we have to clear
-     the error buffer, and check if it's still a null string.  */
-  open_err_str[0] = '\0';
-#ifdef HAVE_PCAP_OPEN
-  auth.type = capture_opts->auth_type == CAPTURE_AUTH_PWD ?
-                    RPCAP_RMTAUTH_PWD : RPCAP_RMTAUTH_NULL;
-  auth.username = capture_opts->auth_username;
-  auth.password = capture_opts->auth_password;
-
-  ld->pcap_h = pcap_open(capture_opts->iface,
-               capture_opts->has_snaplen ? capture_opts->snaplen :
-                          WTAP_MAX_PACKET_SIZE,
-               /* flags */
-               (capture_opts->promisc_mode ? PCAP_OPENFLAG_PROMISCUOUS : 0) |
-               (capture_opts->datatx_udp ? PCAP_OPENFLAG_DATATX_UDP : 0) |
-               (capture_opts->nocap_rpcap ? PCAP_OPENFLAG_NOCAPTURE_RPCAP : 0),
-               CAP_READ_TIMEOUT, &auth, open_err_str);
-#else
-  ld->pcap_h = pcap_open_live(capture_opts->iface,
-                      capture_opts->has_snaplen ? capture_opts->snaplen :
-                                                 WTAP_MAX_PACKET_SIZE,
-                      capture_opts->promisc_mode, CAP_READ_TIMEOUT,
-                      open_err_str);
-#endif
-
-/* If not using libcap: we now can now set euid/egid to ruid/rgid         */
-/*  to remove any suid privileges.                                        */
-/* If using libcap: we can now remove NET_RAW and NET_ADMIN capabilities  */
-/*  (euid/egid have already previously been set to ruid/rgid.             */
-/* (See comment in main() for details)                                    */
-#ifndef HAVE_LIBCAP
-  relinquish_special_privs_perm();
-#else
-  relinquish_all_capabilities();
-#endif
+  ld->pcap_h = open_capture_device(capture_opts, &open_err_str);
 
   if (ld->pcap_h != NULL) {
     /* we've opened "iface" as a network device */
 #ifdef _WIN32
     /* try to set the capture buffer size */
-    if (pcap_setbuff(ld->pcap_h, capture_opts->buffer_size * 1024 * 1024) != 0) {
+    if (capture_opts->buffer_size > 1 &&
+        pcap_setbuff(ld->pcap_h, capture_opts->buffer_size * 1024 * 1024) != 0) {
         sync_secondary_msg_str = g_strdup_printf(
-          "The capture buffer size of %luMB seems to be too high for your machine,\n"
+          "The capture buffer size of %dMB seems to be too high for your machine,\n"
           "the default of 1MB will be used.\n"
           "\n"
           "Nonetheless, the capture is started.\n",
@@ -1139,7 +2196,8 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
 #endif
 
 #if defined(HAVE_PCAP_REMOTE) && defined(HAVE_PCAP_SETSAMPLING)
-    if (capture_opts->sampling_method != CAPTURE_SAMP_NONE)
+    if ((capture_opts->sampling_method != CAPTURE_SAMP_NONE) &&
+        (strncmp (capture_opts->iface, "rpcap://", 8) == 0))
     {
         struct pcap_samp *samp;
 
@@ -1176,75 +2234,29 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
 #endif
 
     /* setting the data link type only works on real interfaces */
-    if (capture_opts->linktype != -1) {
-      set_linktype_err_str = set_pcap_linktype(ld->pcap_h, capture_opts->iface,
-       capture_opts->linktype);
-      if (set_linktype_err_str != NULL) {
-       g_snprintf(errmsg, errmsg_len, "Unable to set data link type (%s).",
-                  set_linktype_err_str);
-        g_snprintf(secondary_errmsg, secondary_errmsg_len, please_report);
-       return FALSE;
-      }
-    }
+    if (!set_pcap_linktype(ld->pcap_h, capture_opts, errmsg, errmsg_len,
+                           secondary_errmsg, secondary_errmsg_len))
+      return FALSE;
     ld->linktype = get_pcap_linktype(ld->pcap_h, capture_opts->iface);
   } else {
     /* We couldn't open "iface" as a network device. */
     /* Try to open it as a pipe */
-    ld->cap_pipe_fd = cap_pipe_open_live(capture_opts->iface, &ld->cap_pipe_hdr, ld, errmsg, errmsg_len);
+    cap_pipe_open_live(capture_opts->iface, &ld->cap_pipe_hdr, ld, errmsg, (int) errmsg_len);
 
+#ifndef _WIN32
     if (ld->cap_pipe_fd == -1) {
+#else
+    if (ld->cap_pipe_h == INVALID_HANDLE_VALUE) {
+#endif
 
       if (ld->cap_pipe_err == PIPNEXIST) {
-       /* Pipe doesn't exist, so output message for interface */
-
-       /* If we got a "can't find PPA for X" message, warn the user (who
-          is running (T)Wireshark 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 X" rather than "can't find PPA for X"). */
-       if (strncmp(open_err_str, ppamsg, sizeof ppamsg - 1) == 0)
-         libpcap_warn =
-           "\n\n"
-           "You are running (T)Wireshark with a version of the libpcap library\n"
-           "that doesn't handle HP-UX network devices well; this means that\n"
-           "(T)Wireshark 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 = "";
-       g_snprintf(errmsg, errmsg_len,
-         "The capture session could not be initiated (%s).", open_err_str);
-#ifndef _WIN32
-       g_snprintf(secondary_errmsg, secondary_errmsg_len,
-"Please check to make sure you have sufficient permissions, and that you have "
-"the proper interface or pipe specified.%s", libpcap_warn);
-#else
-    g_snprintf(secondary_errmsg, secondary_errmsg_len,
-"\n"
-"Please check that \"%s\" is the proper interface.\n"
-"\n"
-"\n"
-"Help can be found at:\n"
-"\n"
-"       http://wiki.wireshark.org/CaptureSetup\n"
-"\n"
-"64-bit Windows:\n"
-"WinPcap does not support 64-bit Windows; you will have to use some other\n"
-"tool to capture traffic, such as netcap.\n"
-"For netcap details see: http://support.microsoft.com/?id=310875\n"
-"\n"
-"Modem (PPP/WAN):\n"
-"Note that version 3.0 of WinPcap, and earlier versions of WinPcap, don't\n"
-"support capturing on PPP/WAN interfaces on Windows NT 4.0 / 2000 / XP /\n"
-"Server 2003.\n"
-"WinPcap 3.1 has support for it on Windows 2000 / XP / Server 2003, but has no\n"
-"support for it on Windows NT 4.0 or Windows Vista (Beta 1).",
-    capture_opts->iface);
-#endif /* _WIN32 */
+        /* Pipe doesn't exist, so output message for interface */
+        get_capture_device_open_failure_messages(open_err_str,
+                                                 capture_opts->iface,
+                                                 errmsg,
+                                                 errmsg_len,
+                                                 secondary_errmsg,
+                                                 secondary_errmsg_len);
       }
       /*
        * Else pipe (or file) does exist and cap_pipe_open_live() has
@@ -1279,22 +2291,28 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
   return TRUE;
 }
 
-
 /* close the capture input file (pcap or capture pipe) */
 static void capture_loop_close_input(loop_data *ld) {
 
   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_close_input");
 
   /* if open, close the capture pipe "input file" */
+#ifndef _WIN32
   if (ld->cap_pipe_fd >= 0) {
     g_assert(ld->from_cap_pipe);
-    eth_close(ld->cap_pipe_fd);
+    ws_close(ld->cap_pipe_fd);
     ld->cap_pipe_fd = 0;
   }
+#else
+  if (ld->cap_pipe_h != INVALID_HANDLE_VALUE) {
+    CloseHandle(ld->cap_pipe_h);
+    ld->cap_pipe_h = INVALID_HANDLE_VALUE;
+  }
+#endif
 
   /* if open, close the pcap "input file" */
   if(ld->pcap_h != NULL) {
-    g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_close_input: closing %p", ld->pcap_h);
+    g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_close_input: closing %p", (void *)ld->pcap_h);
     g_assert(!ld->from_cap_pipe);
     pcap_close(ld->pcap_h);
     ld->pcap_h = NULL;
@@ -1311,32 +2329,17 @@ static void capture_loop_close_input(loop_data *ld) {
 
 /* init the capture filter */
 static initfilter_status_t
-capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe, gchar * iface, gchar * cfilter) {
-  bpf_u_int32 netnum, netmask;
-  gchar       lookup_net_err_str[PCAP_ERRBUF_SIZE];
+capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe,
+                         gchar * iface, gchar * cfilter)
+{
   struct bpf_program fcode;
 
-
   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_init_filter: %s", cfilter);
 
   /* capture filters only work on real interfaces */
   if (cfilter && !from_cap_pipe) {
     /* A capture filter was specified; set it up. */
-    if (pcap_lookupnet(iface, &netnum, &netmask, lookup_net_err_str) < 0) {
-      /*
-       * Well, we can't get the netmask for this interface; it's used
-       * only for filters that check for broadcast IP addresses, so
-       * we just punt and use 0.  It might be nice to warn the user,
-       * but that's a pain in a GUI application, as it'd involve popping
-       * up a message box, and it's not clear how often this would make
-       * a difference (only filters that check for IP broadcast addresses
-       * use the netmask).
-       */
-      /*cmdarg_err(
-        "Warning:  Couldn't obtain netmask info (%s).", lookup_net_err_str);*/
-      netmask = 0;
-    }
-    if (pcap_compile(pcap_h, &fcode, cfilter, 1, netmask) < 0) {
+    if (!compile_capture_filter(iface, pcap_h, &fcode, cfilter)) {
       /* Treat this specially - our caller might try to compile this
          as a display filter and, if that succeeds, warn the user that
          the display and capture filter syntaxes are different. */
@@ -1359,8 +2362,7 @@ capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe, gchar * iface,
 
 /* set up to write to the already-opened capture output file/files */
 static gboolean
-capture_loop_init_output(capture_options *capture_opts, int save_file_fd, loop_data *ld, char *errmsg, int errmsg_len) {
-  int         file_snaplen;
+capture_loop_init_output(capture_options *capture_opts, loop_data *ld, char *errmsg, int errmsg_len) {
   int         err;
 
 
@@ -1368,19 +2370,36 @@ capture_loop_init_output(capture_options *capture_opts, int save_file_fd, loop_d
 
   /* get snaplen */
   if (ld->from_cap_pipe) {
-    file_snaplen = ld->cap_pipe_hdr.snaplen;
+    ld->file_snaplen = ld->cap_pipe_hdr.snaplen;
   } else
   {
-    file_snaplen = pcap_snapshot(ld->pcap_h);
+    ld->file_snaplen = pcap_snapshot(ld->pcap_h);
   }
 
   /* Set up to write to the capture file. */
   if (capture_opts->multi_files_on) {
-    ld->pdh = ringbuf_init_libpcap_fdopen(ld->linktype, file_snaplen,
-                                          &ld->bytes_written, &err);
+    ld->pdh = ringbuf_init_libpcap_fdopen(&err);
   } else {
-    ld->pdh = libpcap_fdopen(save_file_fd, ld->linktype, file_snaplen,
-                             &ld->bytes_written, &err);
+    ld->pdh = libpcap_fdopen(ld->save_file_fd, &err);
+  }
+  if (ld->pdh) {
+    gboolean successful;
+
+    ld->bytes_written = 0;
+    if (capture_opts->use_pcapng) {
+      char appname[100];
+
+      g_snprintf(appname, sizeof(appname), "Dumpcap " VERSION "%s", wireshark_svnversion);
+      successful = libpcap_write_session_header_block(ld->pdh, appname, &ld->bytes_written, &err) &&
+                   libpcap_write_interface_description_block(ld->pdh, capture_opts->iface, capture_opts->cfilter, ld->linktype, ld->file_snaplen, &ld->bytes_written, &err);
+    } else {
+      successful = libpcap_write_file_header(ld->pdh, ld->linktype, ld->file_snaplen,
+                                             &ld->bytes_written, &err);
+    }
+    if (!successful) {
+      fclose(ld->pdh);
+      ld->pdh = NULL;
+    }
   }
 
   if (ld->pdh == NULL) {
@@ -1401,14 +2420,14 @@ capture_loop_init_output(capture_options *capture_opts, int save_file_fd, loop_d
     default:
       if (err < 0) {
         g_snprintf(errmsg, errmsg_len,
-                    "The file to which the capture would be"
-                     " saved (\"%s\") could not be opened: Error %d.",
-                       capture_opts->save_file, err);
+                   "The file to which the capture would be"
+                   " saved (\"%s\") could not be opened: Error %d.",
+                   capture_opts->save_file, err);
       } else {
         g_snprintf(errmsg, errmsg_len,
-                    "The file to which the capture would be"
-                     " saved (\"%s\") could not be opened: %s.",
-                       capture_opts->save_file, strerror(err));
+                    "The file to which the capture would be"
+                    " saved (\"%s\") could not be opened: %s.",
+                    capture_opts->save_file, strerror(err));
       }
       break;
     }
@@ -1427,6 +2446,9 @@ capture_loop_close_output(capture_options *capture_opts, loop_data *ld, int *err
   if (capture_opts->multi_files_on) {
     return ringbuf_libpcap_dump_close(&capture_opts->save_file, err_close);
   } else {
+    if (capture_opts->use_pcapng) {
+      libpcap_write_interface_statistics_block(ld->pdh, 0, ld->pcap_h, &ld->bytes_written, err_close);
+    }
     return libpcap_dump_close(ld->pdh, err_close);
   }
 }
@@ -1447,9 +2469,11 @@ capture_loop_dispatch(capture_options *capture_opts _U_, loop_data *ld,
                      char *errmsg, int errmsg_len)
 {
   int       inpkts;
-  int       sel_ret;
   gint      packet_count_before;
   guchar    pcap_data[WTAP_MAX_PACKET_SIZE];
+#ifndef USE_THREADS
+  int       sel_ret;
+#endif
 
   packet_count_before = ld->packet_count;
   if (ld->from_cap_pipe) {
@@ -1457,6 +2481,7 @@ capture_loop_dispatch(capture_options *capture_opts _U_, loop_data *ld,
 #ifdef LOG_CAPTURE_VERBOSE
     g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from capture pipe");
 #endif
+#ifndef USE_THREADS
     sel_ret = cap_pipe_select(ld->cap_pipe_fd);
     if (sel_ret <= 0) {
       inpkts = 0;
@@ -1470,11 +2495,14 @@ capture_loop_dispatch(capture_options *capture_opts _U_, loop_data *ld,
       /*
        * "select()" says we can read from the pipe without blocking
        */
+#endif /* USE_THREADS */
       inpkts = cap_pipe_dispatch(ld, pcap_data, errmsg, errmsg_len);
       if (inpkts < 0) {
         ld->go = FALSE;
       }
+#ifndef USE_THREADS
     }
+#endif
   }
   else
   {
@@ -1511,7 +2539,10 @@ capture_loop_dispatch(capture_options *capture_opts _U_, loop_data *ld,
         inpkts = pcap_dispatch(ld->pcap_h, 1, capture_loop_packet_cb,
                                (u_char *)ld);
         if (inpkts < 0) {
-          ld->pcap_err = TRUE;
+            if (inpkts == -1) {
+                /* Error, rather than pcap_breakloop(). */
+                ld->pcap_err = TRUE;
+            }
           ld->go = FALSE; /* error or pcap_breakloop() - stop capturing */
         }
       } else {
@@ -1598,10 +2629,12 @@ static gboolean
 capture_loop_open_output(capture_options *capture_opts, int *save_file_fd,
                      char *errmsg, int errmsg_len) {
 
-  char tmpname[128+1];
+  char *tmpname;
   gchar *capfile_name;
   gboolean is_tempfile;
-
+#ifndef _WIN32
+  int ret;
+#endif
 
   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_open_output: %s",
       (capture_opts->save_file) ? capture_opts->save_file : "");
@@ -1644,14 +2677,14 @@ capture_loop_open_output(capture_options *capture_opts, int *save_file_fd,
         }
       } else {
         /* Try to open/create the specified file for use as a capture buffer. */
-        *save_file_fd = eth_open(capfile_name, O_RDWR|O_BINARY|O_TRUNC|O_CREAT,
+        *save_file_fd = ws_open(capfile_name, O_RDWR|O_BINARY|O_TRUNC|O_CREAT,
                              0600);
       }
     }
     is_tempfile = FALSE;
   } else {
     /* Choose a random name for the temporary capture buffer */
-    *save_file_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
+    *save_file_fd = create_tempfile(&tmpname, "wireshark");
     capfile_name = g_strdup(tmpname);
     is_tempfile = TRUE;
   }
@@ -1683,114 +2716,157 @@ capture_loop_open_output(capture_options *capture_opts, int *save_file_fd,
   /* capture_opts.save_file is "g_free"ed later, which is equivalent to
      "g_free(capfile_name)". */
 #ifndef _WIN32
-  fchown(*save_file_fd, capture_opts->owner, capture_opts->group);
+  ret = fchown(*save_file_fd, capture_opts->owner, capture_opts->group);
 #endif
 
   return TRUE;
 }
 
 
-static void
-capture_loop_stop_signal_handler(int signo _U_)
-{
-  g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Signal: Stop capture");
-  capture_loop_stop();
-}
-
 #ifdef _WIN32
 #define TIME_GET() GetTickCount()
 #else
 #define TIME_GET() time(NULL)
 #endif
 
+/* Do the work of handling either the file size or file duration capture
+   conditions being reached, and switching files or stopping. */
+static gboolean
+do_file_switch_or_stop(capture_options *capture_opts,
+                       condition *cnd_autostop_files,
+                       condition *cnd_autostop_size,
+                       condition *cnd_file_duration)
+{
+  if (capture_opts->multi_files_on) {
+    if (cnd_autostop_files != NULL &&
+        cnd_eval(cnd_autostop_files, ++global_ld.autostop_files)) {
+      /* no files left: stop here */
+      global_ld.go = FALSE;
+      return FALSE;
+    }
+
+    /* Switch to the next ringbuffer file */
+    if (ringbuf_switch_file(&global_ld.pdh, &capture_opts->save_file,
+                            &global_ld.save_file_fd, &global_ld.err)) {
+      gboolean successful;
+
+      /* File switch succeeded: reset the conditions */
+      global_ld.bytes_written = 0;
+      if (capture_opts->use_pcapng) {
+        char appname[100];
+
+        g_snprintf(appname, sizeof(appname), "Dumpcap " VERSION "%s", wireshark_svnversion);
+        successful = libpcap_write_session_header_block(global_ld.pdh, appname, &global_ld.bytes_written, &global_ld.err) &&
+                     libpcap_write_interface_description_block(global_ld.pdh, capture_opts->iface, capture_opts->cfilter, global_ld.linktype, global_ld.file_snaplen, &global_ld.bytes_written, &global_ld.err);
+      } else {
+        successful = libpcap_write_file_header(global_ld.pdh, global_ld.linktype, global_ld.file_snaplen,
+                                               &global_ld.bytes_written, &global_ld.err);
+      }
+      if (!successful) {
+        fclose(global_ld.pdh);
+        global_ld.pdh = NULL;
+        global_ld.go = FALSE;
+        return FALSE;
+      }
+      if(cnd_autostop_size)
+        cnd_reset(cnd_autostop_size);
+      if(cnd_file_duration)
+        cnd_reset(cnd_file_duration);
+      libpcap_dump_flush(global_ld.pdh, NULL);
+      if (!quiet)
+        report_packet_count(global_ld.inpkts_to_sync_pipe);
+      global_ld.inpkts_to_sync_pipe = 0;
+      report_new_capture_file(capture_opts->save_file);
+    } else {
+      /* File switch failed: stop here */
+      global_ld.go = FALSE;
+      return FALSE;
+    }
+  } else {
+    /* single file, stop now */
+    global_ld.go = FALSE;
+    return FALSE;
+  }
+  return TRUE;
+}
+
 /* Do the low-level work of a capture.
    Returns TRUE if it succeeds, FALSE otherwise. */
 static gboolean
 capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct pcap_stat *stats)
 {
-#ifndef _WIN32
-  struct sigaction act;
-#endif
   time_t      upd_time, cur_time;
   time_t      start_time;
   int         err_close;
   int         inpkts;
-  gint        inpkts_to_sync_pipe = 0;     /* packets not already send out to the sync_pipe */
   condition  *cnd_file_duration = NULL;
   condition  *cnd_autostop_files = NULL;
   condition  *cnd_autostop_size = NULL;
   condition  *cnd_autostop_duration = NULL;
-  guint32     autostop_files = 0;
   gboolean    write_ok;
   gboolean    close_ok;
   gboolean    cfilter_error = FALSE;
-#define MSG_MAX_LENGTH 4096
   char        errmsg[MSG_MAX_LENGTH+1];
   char        secondary_errmsg[MSG_MAX_LENGTH+1];
-  int         save_file_fd = -1;
 
   *errmsg           = '\0';
   *secondary_errmsg = '\0';
 
   /* init the loop data */
-  ld.go                 = TRUE;
-  ld.packet_count       = 0;
+  global_ld.go                  = TRUE;
+  global_ld.packet_count        = 0;
+#ifdef SIGINFO
+  global_ld.report_packet_count = FALSE;
+#endif
   if (capture_opts->has_autostop_packets)
-    ld.packet_max       = capture_opts->autostop_packets;
+    global_ld.packet_max        = capture_opts->autostop_packets;
   else
-    ld.packet_max       = 0;   /* no limit */
-  ld.err                = 0;   /* no error seen yet */
-  ld.wtap_linktype      = WTAP_ENCAP_UNKNOWN;
-  ld.pcap_err           = FALSE;
-  ld.from_cap_pipe      = FALSE;
-  ld.pdh                = NULL;
-  ld.cap_pipe_fd        = -1;
+    global_ld.packet_max        = 0;   /* no limit */
+  global_ld.inpkts_to_sync_pipe = 0;
+  global_ld.err                 = 0;   /* no error seen yet */
+  global_ld.wtap_linktype       = WTAP_ENCAP_UNKNOWN;
+  global_ld.pcap_err            = FALSE;
+  global_ld.from_cap_pipe       = FALSE;
+  global_ld.pdh                 = NULL;
+#ifndef _WIN32
+  global_ld.cap_pipe_fd         = -1;
+#else
+  global_ld.cap_pipe_h          = INVALID_HANDLE_VALUE;
+#endif
 #ifdef MUST_DO_SELECT
-  ld.pcap_fd            = 0;
+  global_ld.pcap_fd             = 0;
 #endif
+  global_ld.autostop_files      = 0;
+  global_ld.save_file_fd        = -1;
 
   /* We haven't yet gotten the capture statistics. */
   *stats_known      = FALSE;
 
-#ifndef _WIN32
-  /*
-   * Catch SIGUSR1, so that we exit cleanly if the parent process
-   * kills us with it due to the user selecting "Capture->Stop".
-   */
-  act.sa_handler = capture_loop_stop_signal_handler;
-  /*
-   * Arrange that system calls not get restarted, because when
-   * our signal handler returns we don't want to restart
-   * a call that was waiting for packets to arrive.
-   */
-  act.sa_flags = 0;
-  sigemptyset(&act.sa_mask);
-  sigaction(SIGUSR1, &act, NULL);
-#endif /* _WIN32 */
-
   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Capture loop starting ...");
   capture_opts_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, capture_opts);
 
   /* open the "input file" from network interface or capture pipe */
-  if (!capture_loop_open_input(capture_opts, &ld, errmsg, sizeof(errmsg),
+  if (!capture_loop_open_input(capture_opts, &global_ld, errmsg, sizeof(errmsg),
                                secondary_errmsg, sizeof(secondary_errmsg))) {
     goto error;
   }
 
   /* init the input filter from the network interface (capture pipe will do nothing) */
-  switch (capture_loop_init_filter(ld.pcap_h, ld.from_cap_pipe, capture_opts->iface, capture_opts->cfilter)) {
+  switch (capture_loop_init_filter(global_ld.pcap_h, global_ld.from_cap_pipe,
+                                   capture_opts->iface,
+                                  capture_opts->cfilter)) {
 
   case INITFILTER_NO_ERROR:
     break;
 
   case INITFILTER_BAD_FILTER:
     cfilter_error = TRUE;
-    g_snprintf(errmsg, sizeof(errmsg), "%s", pcap_geterr(ld.pcap_h));
+    g_snprintf(errmsg, sizeof(errmsg), "%s", pcap_geterr(global_ld.pcap_h));
     goto error;
 
   case INITFILTER_OTHER_ERROR:
     g_snprintf(errmsg, sizeof(errmsg), "Can't install filter (%s).",
-               pcap_geterr(ld.pcap_h));
+               pcap_geterr(global_ld.pcap_h));
     g_snprintf(secondary_errmsg, sizeof(secondary_errmsg), "%s", please_report);
     goto error;
   }
@@ -1798,12 +2874,14 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
   /* If we're supposed to write to a capture file, open it for output
      (temporary/specified name/ringbuffer) */
   if (capture_opts->saving_to_file) {
-    if (!capture_loop_open_output(capture_opts, &save_file_fd, errmsg, sizeof(errmsg))) {
+    if (!capture_loop_open_output(capture_opts, &global_ld.save_file_fd,
+                                  errmsg, sizeof(errmsg))) {
       goto error;
     }
 
     /* set up to write to the already-opened capture output file/files */
-    if (!capture_loop_init_output(capture_opts, save_file_fd, &ld, errmsg, sizeof(errmsg))) {
+    if (!capture_loop_init_output(capture_opts, &global_ld, errmsg,
+                                  sizeof(errmsg))) {
       goto error;
     }
 
@@ -1820,7 +2898,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
        message to our parent so that they'll open the capture file and
        update its windows to indicate that we have a live capture in
        progress. */
-    libpcap_dump_flush(ld.pdh, NULL);
+    libpcap_dump_flush(global_ld.pdh, NULL);
     report_new_capture_file(capture_opts->save_file);
   }
 
@@ -1852,57 +2930,40 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
 
   /* WOW, everything is prepared! */
   /* please fasten your seat belts, we will enter now the actual capture loop */
-  while (ld.go) {
+  while (global_ld.go) {
     /* dispatch incoming packets */
-    inpkts = capture_loop_dispatch(capture_opts, &ld, errmsg, sizeof(errmsg));
+    inpkts = capture_loop_dispatch(capture_opts, &global_ld, errmsg,
+                                   sizeof(errmsg));
+
+#ifdef SIGINFO
+    /* Were we asked to print packet counts by the SIGINFO handler? */
+    if (global_ld.report_packet_count) {
+        fprintf(stderr, "%u packet%s captured\n", global_ld.packet_count,
+                plurality(global_ld.packet_count, "", "s"));
+        global_ld.report_packet_count = FALSE;
+    }
+#endif
 
 #ifdef _WIN32
     /* any news from our parent (signal pipe)? -> just stop the capture */
     if (!signal_pipe_check_running()) {
-      ld.go = FALSE;
+      global_ld.go = FALSE;
     }
 #endif
 
     if (inpkts > 0) {
-      inpkts_to_sync_pipe += inpkts;
+      global_ld.inpkts_to_sync_pipe += inpkts;
 
       /* check capture size condition */
       if (cnd_autostop_size != NULL &&
-          cnd_eval(cnd_autostop_size, (guint32)ld.bytes_written)){
+          cnd_eval(cnd_autostop_size, (guint32)global_ld.bytes_written)) {
         /* Capture size limit reached, do we have another file? */
-        if (capture_opts->multi_files_on) {
-          if (cnd_autostop_files != NULL &&
-              cnd_eval(cnd_autostop_files, ++autostop_files)) {
-             /* no files left: stop here */
-            ld.go = FALSE;
-            continue;
-          }
-
-          /* Switch to the next ringbuffer file */
-          if (ringbuf_switch_file(&ld.pdh, &capture_opts->save_file,
-              &save_file_fd, &ld.bytes_written, &ld.err)) {
-            /* File switch succeeded: reset the conditions */
-            cnd_reset(cnd_autostop_size);
-            if (cnd_file_duration) {
-              cnd_reset(cnd_file_duration);
-            }
-            libpcap_dump_flush(ld.pdh, NULL);
-            report_packet_count(inpkts_to_sync_pipe);
-            inpkts_to_sync_pipe = 0;
-            report_new_capture_file(capture_opts->save_file);
-          } else {
-            /* File switch failed: stop here */
-            ld.go = FALSE;
-            continue;
-          }
-        } else {
-          /* single file, stop now */
-          ld.go = FALSE;
+        if (!do_file_switch_or_stop(capture_opts, cnd_autostop_files,
+                                    cnd_autostop_size, cnd_file_duration))
           continue;
-        }
       } /* cnd_autostop_size */
       if (capture_opts->output_to_pipe) {
-        libpcap_dump_flush(ld.pdh, NULL);
+        libpcap_dump_flush(global_ld.pdh, NULL);
       }
     } /* inpkts */
 
@@ -1922,60 +2983,35 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
       }*/
 
       /* Let the parent process know. */
-      if (inpkts_to_sync_pipe) {
+      if (global_ld.inpkts_to_sync_pipe) {
         /* do sync here */
-        libpcap_dump_flush(ld.pdh, NULL);
+        libpcap_dump_flush(global_ld.pdh, NULL);
 
-        /* Send our parent a message saying we've written out "inpkts_to_sync_pipe"
-           packets to the capture file. */
-        report_packet_count(inpkts_to_sync_pipe);
+        /* Send our parent a message saying we've written out
+           "global_ld.inpkts_to_sync_pipe" packets to the capture file. */
+        if (!quiet)
+          report_packet_count(global_ld.inpkts_to_sync_pipe);
 
-        inpkts_to_sync_pipe = 0;
+        global_ld.inpkts_to_sync_pipe = 0;
       }
 
       /* check capture duration condition */
       if (cnd_autostop_duration != NULL && cnd_eval(cnd_autostop_duration)) {
         /* The maximum capture time has elapsed; stop the capture. */
-        ld.go = FALSE;
+        global_ld.go = FALSE;
         continue;
       }
 
       /* check capture file duration condition */
       if (cnd_file_duration != NULL && cnd_eval(cnd_file_duration)) {
         /* duration limit reached, do we have another file? */
-        if (capture_opts->multi_files_on) {
-          if (cnd_autostop_files != NULL &&
-              cnd_eval(cnd_autostop_files, ++autostop_files)) {
-            /* no files left: stop here */
-            ld.go = FALSE;
-            continue;
-          }
-
-          /* Switch to the next ringbuffer file */
-          if (ringbuf_switch_file(&ld.pdh, &capture_opts->save_file,
-                                  &save_file_fd, &ld.bytes_written, &ld.err)) {
-            /* file switch succeeded: reset the conditions */
-            cnd_reset(cnd_file_duration);
-            if(cnd_autostop_size)
-              cnd_reset(cnd_autostop_size);
-            libpcap_dump_flush(ld.pdh, NULL);
-            report_packet_count(inpkts_to_sync_pipe);
-            inpkts_to_sync_pipe = 0;
-            report_new_capture_file(capture_opts->save_file);
-          } else {
-            /* File switch failed: stop here */
-            ld.go = FALSE;
-            continue;
-          }
-        } else {
-          /* single file, stop now */
-          ld.go = FALSE;
+        if (!do_file_switch_or_stop(capture_opts, cnd_autostop_files,
+                                    cnd_autostop_size, cnd_file_duration))
           continue;
-        }
       } /* cnd_file_duration */
     }
 
-  } /* while (ld.go) */
+  } /* while (global_ld.go) */
 
   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Capture loop stopping ...");
 
@@ -1990,7 +3026,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
     cnd_delete(cnd_autostop_duration);
 
   /* did we had a pcap (input) error? */
-  if (ld.pcap_err) {
+  if (global_ld.pcap_err) {
     /* On Linux, if an interface goes down while you're capturing on it,
        you'll get a "recvfrom: Network is down" error (ENETDOWN).
        (At least you will if strerror() doesn't show a local translation
@@ -2005,7 +3041,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
        These should *not* be reported to the Wireshark developers. */
     char *cap_err_str;
 
-    cap_err_str = pcap_geterr(ld.pcap_h);
+    cap_err_str = pcap_geterr(global_ld.pcap_h);
     if (strcmp(cap_err_str, "recvfrom: Network is down") == 0 ||
         strcmp(cap_err_str, "read: Device not configured") == 0 ||
         strcmp(cap_err_str, "read: I/O error") == 0) {
@@ -2018,30 +3054,31 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
       report_capture_error(errmsg, please_report);
     }
   }
-  else if (ld.from_cap_pipe && ld.cap_pipe_err == PIPERR)
+  else if (global_ld.from_cap_pipe && global_ld.cap_pipe_err == PIPERR)
     report_capture_error(errmsg, "");
 
   /* did we had an error while capturing? */
-  if (ld.err == 0) {
+  if (global_ld.err == 0) {
     write_ok = TRUE;
   } else {
-    capture_loop_get_errmsg(errmsg, sizeof(errmsg), capture_opts->save_file, ld.err,
-                             FALSE);
+    capture_loop_get_errmsg(errmsg, sizeof(errmsg), capture_opts->save_file,
+                            global_ld.err, FALSE);
     report_capture_error(errmsg, please_report);
     write_ok = FALSE;
   }
 
   if (capture_opts->saving_to_file) {
     /* close the wiretap (output) file */
-    close_ok = capture_loop_close_output(capture_opts, &ld, &err_close);
+    close_ok = capture_loop_close_output(capture_opts, &global_ld, &err_close);
   } else
     close_ok = TRUE;
 
   /* there might be packets not yet notified to the parent */
   /* (do this after closing the file, so all packets are already flushed) */
-  if(inpkts_to_sync_pipe) {
-    report_packet_count(inpkts_to_sync_pipe);
-    inpkts_to_sync_pipe = 0;
+  if(global_ld.inpkts_to_sync_pipe) {
+    if (!quiet)
+      report_packet_count(global_ld.inpkts_to_sync_pipe);
+    global_ld.inpkts_to_sync_pipe = 0;
   }
 
   /* If we've displayed a message about a write error, there's no point
@@ -2062,24 +3099,24 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
    */
 
   /* get packet drop statistics from pcap */
-  if(ld.pcap_h != NULL) {
-    g_assert(!ld.from_cap_pipe);
+  if(global_ld.pcap_h != NULL) {
+    g_assert(!global_ld.from_cap_pipe);
     /* Get the capture statistics, so we know how many packets were
        dropped. */
-    if (pcap_stats(ld.pcap_h, stats) >= 0) {
+    if (pcap_stats(global_ld.pcap_h, stats) >= 0) {
       *stats_known = TRUE;
       /* Let the parent process know. */
       report_packet_drops(stats->ps_drop);
     } else {
       g_snprintf(errmsg, sizeof(errmsg),
                "Can't get packet-drop statistics: %s",
-               pcap_geterr(ld.pcap_h));
+               pcap_geterr(global_ld.pcap_h));
       report_capture_error(errmsg, please_report);
     }
   }
 
   /* close the input file (pcap or capture pipe) */
-  capture_loop_close_input(&ld);
+  capture_loop_close_input(&global_ld);
 
   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Capture loop stopped!");
 
@@ -2093,14 +3130,14 @@ error:
   } else {
     /* We can't use the save file, and we have no FILE * for the stream
        to close in order to close it, so close the FD directly. */
-    if(save_file_fd != -1) {
-      eth_close(save_file_fd);
+    if(global_ld.save_file_fd != -1) {
+      ws_close(global_ld.save_file_fd);
     }
 
     /* We couldn't even start the capture, so get rid of the capture
        file. */
     if(capture_opts->save_file != NULL) {
-      eth_unlink(capture_opts->save_file);
+      ws_unlink(capture_opts->save_file);
       g_free(capture_opts->save_file);
     }
   }
@@ -2111,7 +3148,7 @@ error:
     report_capture_error(errmsg, secondary_errmsg);
 
   /* close the input file (pcap or cap_pipe) */
-  capture_loop_close_input(&ld);
+  capture_loop_close_input(&global_ld);
 
   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Capture loop stopped with error");
 
@@ -2122,10 +3159,10 @@ error:
 static void capture_loop_stop(void)
 {
 #ifdef HAVE_PCAP_BREAKLOOP
-  if(ld.pcap_h != NULL)
-    pcap_breakloop(ld.pcap_h);
+  if(global_ld.pcap_h != NULL)
+    pcap_breakloop(global_ld.pcap_h);
 #endif
-  ld.go = FALSE;
+  global_ld.go = FALSE;
 }
 
 
@@ -2193,16 +3230,9 @@ static void
 capture_loop_packet_cb(u_char *user, const struct pcap_pkthdr *phdr,
   const u_char *pd)
 {
-  loop_data *ld = (void *) user;
+  loop_data *ld = (loop_data *) (void *) user;
   int err;
 
-  /* if the user told us to stop after x packets, do we already have enough? */
-  if ((ld->packet_max > 0) && (ld->packet_count >= ld->packet_max))
-  {
-     ld->go = FALSE;
-     return;
-  }
-
   /* We may be called multiple times from pcap_dispatch(); if we've set
      the "stop capturing" flag, ignore this packet, as we're not
      supposed to be saving any more packets. */
@@ -2210,14 +3240,26 @@ capture_loop_packet_cb(u_char *user, const struct pcap_pkthdr *phdr,
     return;
 
   if (ld->pdh) {
+    gboolean successful;
     /* 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 (!libpcap_write_packet(ld->pdh, phdr, pd, &ld->bytes_written, &err)) {
+    if (global_capture_opts.use_pcapng) {
+      successful = libpcap_write_enhanced_packet_block(ld->pdh, phdr, 0, pd, &ld->bytes_written, &err);
+    } else {
+      successful = libpcap_write_packet(ld->pdh, phdr, pd, &ld->bytes_written, &err);
+    }
+    if (!successful) {
       ld->go = FALSE;
       ld->err = err;
-    } else
+    } else {
       ld->packet_count++;
+      /* if the user told us to stop after x packets, do we already have enough? */
+      if ((ld->packet_max > 0) && (ld->packet_count >= ld->packet_max))
+      {
+        ld->go = FALSE;
+      }
+    }
   }
 }
 
@@ -2227,13 +3269,11 @@ int
 main(int argc, char *argv[])
 {
   int                  opt;
-  extern char         *optarg;
   gboolean             arg_error = FALSE;
 
 #ifdef _WIN32
   WSADATA              wsaData;
-#endif  /* _WIN32 */
-#ifndef _WIN32
+#else
   struct sigaction action, oldaction;
 #endif
 
@@ -2243,51 +3283,125 @@ main(int argc, char *argv[])
   GLogLevelFlags       log_flags;
   gboolean             list_interfaces = FALSE;
   gboolean             list_link_layer_types = FALSE;
+#ifdef HAVE_BPF_IMAGE
+  gboolean             print_bpf_code = FALSE;
+#endif
   gboolean             machine_readable = FALSE;
   gboolean             print_statistics = FALSE;
   int                  status, run_once_args = 0;
   gint                 i;
+#if defined(__APPLE__) && defined(__LP64__)
+  struct utsname       osinfo;
+#endif
+
+#ifdef _WIN32
+  /*
+   * Initialize our DLL search path. MUST be called before LoadLibrary
+   * or g_module_open.
+   */
+  ws_init_dll_search_path();
+#endif
 
 #ifdef HAVE_PCAP_REMOTE
-#define OPTSTRING_INIT "a:A:b:c:Df:hi:Lm:MprSs:uvw:y:Z:"
+#define OPTSTRING_A "A:"
+#define OPTSTRING_r "r"
+#define OPTSTRING_u "u"
 #else
-#define OPTSTRING_INIT "a:b:c:Df:hi:LMpSs:vw:y:Z:"
+#define OPTSTRING_A ""
+#define OPTSTRING_r ""
+#define OPTSTRING_u ""
 #endif
 
-#ifdef _WIN32
-#define OPTSTRING_WIN32 "B:"
+#ifdef HAVE_PCAP_SETSAMPLING
+#define OPTSTRING_m "m:"
 #else
-#define OPTSTRING_WIN32 ""
-#endif  /* _WIN32 */
+#define OPTSTRING_m ""
+#endif
+
+#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
+#define OPTSTRING_B "B:"
+#else
+#define OPTSTRING_B ""
+#endif  /* _WIN32 or HAVE_PCAP_CREATE */
+
+#ifdef HAVE_PCAP_CREATE
+#define OPTSTRING_I "I"
+#else
+#define OPTSTRING_I ""
+#endif
+
+#ifdef HAVE_BPF_IMAGE
+#define OPTSTRING_d "d"
+#else
+#define OPTSTRING_d ""
+#endif
 
-  char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_WIN32) - 1] =
-    OPTSTRING_INIT OPTSTRING_WIN32;
+#define OPTSTRING "a:" OPTSTRING_A "b:" OPTSTRING_B "c:" OPTSTRING_d "Df:hi:" OPTSTRING_I "L" OPTSTRING_m "Mnpq" OPTSTRING_r "Ss:" OPTSTRING_u "vw:y:Z:"
 
 #ifdef DEBUG_CHILD_DUMPCAP
-  if ((debug_log = fopen("dumpcap_debug_log.tmp","w")) == NULL) {
+  if ((debug_log = ws_fopen("dumpcap_debug_log.tmp","w")) == NULL) {
           fprintf (stderr, "Unable to open debug log file !\n");
           exit (1);
   }
 #endif
 
-  /* Determine if dumpcap is being requested to run in a special       */
-  /* capture_child mode by going thru the command line args to see if  */
-  /* a -Z is present. (-Z is a hidden option).                         */
-  /* The primary result of running in capture_child mode is that       */
-  /* all messages sent out on stderr are in a special type/len/string  */
-  /* format to allow message processing by type.                       */
-  /* These messages include various 'status' messages which are sent   */
-  /* when an actual capture is in progress. Capture_child mode         */
-  /* would normally be requested by a parent process which invokes     */
-  /* dumpcap and obtains dumpcap stderr output via a pipe to which     */
-  /* dumpcap stderr has been redirected.                               */
-  /* Capture_child mode needs to be determined immediately upon        */
-  /* startup so that any messages generated by dumpcap in this mode    */
-  /* (eg: during initialization) will be formatted properly.           */
+#if defined(__APPLE__) && defined(__LP64__)
+  /*
+   * Is this Mac OS X 10.6.x, other than 10.6.2?  If so, we need a bug
+   * workaround - timeouts less than 1 second don't work with libpcap
+   * in 64-bit code.  (The bug was introduced in 10.6, fixed in 10.6.2,
+   * and re-introduced in 10.6.3.  We don't know whether it'll be fixed
+   * again in a later 10.6.x release; we'll assume that it'll be fixed
+   * in any future major releases.)
+   */
+  if (uname(&osinfo) == 0) {
+    /*
+     * Mac OS X 10.x uses Darwin {x+4}.0.0.  Mac OS X 10.x.y uses Darwin
+     * {x+4}.y.0 (except that 10.6.1 appears to have a uname version
+     * number of 10.0.0, not 10.1.0 - go figure).
+     */
+    if (strncmp(osinfo.release, "10.", 3) == 0) {
+      /*
+       * OK, it's Snow Leopard - which version?
+       */
+      if (strcmp(osinfo.release, "10.2.0") != 0) {
+        /* Not 10.6.2. */
+        need_timeout_workaround = TRUE;
+      }
+    }
+  }
+#endif
+
+  /*
+   * Determine if dumpcap is being requested to run in a special
+   * capture_child mode by going thru the command line args to see if
+   * a -Z is present. (-Z is a hidden option).
+   *
+   * The primary result of running in capture_child mode is that
+   * all messages sent out on stderr are in a special type/len/string
+   * format to allow message processing by type.  These messages include
+   * error messages if dumpcap fails to start the operation it was
+   * requested to do, as well as various "status" messages which are sent
+   * when an actual capture is in progress, and a "success" message sent
+   * if dumpcap was requested to perform an operation other than a
+   * capture.
+   *
+   * Capture_child mode would normally be requested by a parent process
+   * which invokes dumpcap and obtains dumpcap stderr output via a pipe
+   * to which dumpcap stderr has been redirected.  It might also have
+   * another pipe to obtain dumpcap stdout output; for operations other
+   * than a capture, that information is formatted specially for easier
+   * parsing by the parent process.
+   *
+   * Capture_child mode needs to be determined immediately upon
+   * startup so that any messages generated by dumpcap in this mode
+   * (eg: during initialization) will be formatted properly.
+   */
 
   for (i=1; i<argc; i++) {
     if (strcmp("-Z", argv[i]) == 0) {
       capture_child = TRUE;
+      machine_readable = TRUE;  /* request machine-readable output */
 #ifdef _WIN32
       /* set output pipe to binary mode, to avoid ugly text conversions */
       _setmode(2, O_BINARY);
@@ -2336,18 +3450,41 @@ main(int argc, char *argv[])
   WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
 
   /* Set handler for Ctrl+C key */
-  SetConsoleCtrlHandler(capture_cleanup, TRUE);
+  SetConsoleCtrlHandler(capture_cleanup_handler, TRUE);
+
+  /* Prepare to read from a pipe */
+  if (!g_thread_supported ())
+    g_thread_init (NULL);
+  cap_pipe_pending_q = g_async_queue_new();
+  cap_pipe_done_q = g_async_queue_new();
+  cap_pipe_read_mtx = g_mutex_new();
+
 #else
   /* Catch SIGINT and SIGTERM and, if we get either of them, clean up
      and exit. */
-  action.sa_handler = capture_cleanup;
+  action.sa_handler = capture_cleanup_handler;
+  /*
+   * Arrange that system calls not get restarted, because when
+   * our signal handler returns we don't want to restart
+   * a call that was waiting for packets to arrive.
+   */
   action.sa_flags = 0;
   sigemptyset(&action.sa_mask);
   sigaction(SIGTERM, &action, NULL);
   sigaction(SIGINT, &action, NULL);
+  sigaction(SIGPIPE, &action, NULL);
   sigaction(SIGHUP, NULL, &oldaction);
   if (oldaction.sa_handler == SIG_DFL)
     sigaction(SIGHUP, &action, NULL);
+
+#ifdef SIGINFO
+  /* Catch SIGINFO and, if we get it and we're capturing in
+     quiet mode, report the number of packets we've captured. */
+  action.sa_handler = report_counts_siginfo;
+  action.sa_flags = SA_RESTART;
+  sigemptyset(&action.sa_mask);
+  sigaction(SIGINFO, &action, NULL);
+#endif /* SIGINFO */
 #endif  /* _WIN32 */
 
   /* ----------------------------------------------------------------- */
@@ -2406,7 +3543,7 @@ main(int argc, char *argv[])
   /*                                                                   */
   /*        It is therefore conceivable that if dumpcap somehow hangs  */
   /*        in pcap_open_live or before that wireshark will not        */
-  /*        be able to stop dumpcap using a signal (USR1, TERM, etc).  */
+  /*        be able to stop dumpcap using a signal (INT, TERM, etc).  */
   /*        In this case, exiting wireshark will kill the child        */
   /*        dumpcap process.                                           */
   /*                                                                   */
@@ -2432,20 +3569,20 @@ main(int argc, char *argv[])
   relinquish_privs_except_capture();
 #endif
 
-  /* Set the initial values in the capture_opts. This might be overwritten
+  /* Set the initial values in the capture options. This might be overwritten
      by the command line parameters. */
-  capture_opts_init(capture_opts, NULL);
+  capture_opts_init(&global_capture_opts, NULL);
 
   /* Default to capturing the entire packet. */
-  capture_opts->snaplen             = WTAP_MAX_PACKET_SIZE;
+  global_capture_opts.snaplen             = WTAP_MAX_PACKET_SIZE;
 
   /* We always save to a file - if no file was specified, we save to a
      temporary file. */
-  capture_opts->saving_to_file      = TRUE;
-  capture_opts->has_ring_num_files  = TRUE;
+  global_capture_opts.saving_to_file      = TRUE;
+  global_capture_opts.has_ring_num_files  = TRUE;
 
   /* Now get our args */
-  while ((opt = getopt(argc, argv, optstring)) != -1) {
+  while ((opt = getopt(argc, argv, OPTSTRING)) != -1) {
     switch (opt) {
       case 'h':        /* Print help and exit */
         print_usage(TRUE);
@@ -2474,6 +3611,7 @@ main(int argc, char *argv[])
       case 'c':        /* Capture x packets */
       case 'f':        /* capture filter */
       case 'i':        /* Use interface x */
+      case 'n':        /* Use pcapng format */
       case 'p':        /* Don't capture in promiscuous mode */
       case 's':        /* Set the snapshot (capture) length */
       case 'w':        /* Write to capture file x */
@@ -2486,10 +3624,13 @@ main(int argc, char *argv[])
 #ifdef HAVE_PCAP_SETSAMPLING
       case 'm':        /* Sampling */
 #endif
-#ifdef _WIN32
+#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
       case 'B':        /* Buffer size */
-#endif /* _WIN32 */
-        status = capture_opts_add_opt(capture_opts, opt, optarg, &start_capture);
+#endif /* _WIN32 or HAVE_PCAP_CREATE */
+#ifdef HAVE_PCAP_CREATE
+      case 'I':        /* Monitor mode */
+#endif
+        status = capture_opts_add_opt(&global_capture_opts, opt, optarg, &start_capture);
         if(status != 0) {
           exit_main(status);
         }
@@ -2519,6 +3660,10 @@ main(int argc, char *argv[])
 #endif
         break;
 
+      case 'q':        /* Quiet */
+        quiet = TRUE;
+        break;
+
       /*** all non capture option specific ***/
       case 'D':        /* Print a list of capture devices and exit */
         list_interfaces = TRUE;
@@ -2528,11 +3673,17 @@ main(int argc, char *argv[])
         list_link_layer_types = TRUE;
         run_once_args++;
         break;
+#ifdef HAVE_BPF_IMAGE
+      case 'd':        /* Print BPF code for capture filter and exit */
+        print_bpf_code = TRUE;
+        run_once_args++;
+        break;
+#endif
       case 'S':        /* Print interface statistics once a second */
         print_statistics = TRUE;
         run_once_args++;
         break;
-      case 'M':        /* For -D and -L, print machine-readable output */
+      case 'M':        /* For -D, -L, and -S, print machine-readable output */
         machine_readable = TRUE;
         break;
       default:
@@ -2568,60 +3719,141 @@ main(int argc, char *argv[])
   if (run_once_args > 1) {
     cmdarg_err("Only one of -D, -L, or -S may be supplied.");
     exit_main(1);
-  } else if (list_link_layer_types) {
-    /* We're supposed to list the link-layer types for an interface;
-       did the user also specify a capture file to be read? */
-    /* No - did they specify a ring buffer option? */
-    if (capture_opts->multi_files_on) {
+  } else if (run_once_args == 1) {
+    /* We're supposed to print some information, rather than
+       to capture traffic; did they specify a ring buffer option? */
+    if (global_capture_opts.multi_files_on) {
       cmdarg_err("Ring buffer requested, but a capture isn't being done.");
       exit_main(1);
     }
   } else {
-    /* No - was the ring buffer option specified and, if so, does it make
-       sense? */
-    if (capture_opts->multi_files_on) {
+    /* We're supposed to capture traffic; was the ring buffer option
+       specified and, if so, does it make sense? */
+    if (global_capture_opts.multi_files_on) {
       /* Ring buffer works only under certain conditions:
         a) ring buffer does not work with temporary files;
         b) it makes no sense to enable the ring buffer if the maximum
            file size is set to "infinite". */
-      if (capture_opts->save_file == NULL) {
+      if (global_capture_opts.save_file == NULL) {
        cmdarg_err("Ring buffer requested, but capture isn't being saved to a permanent file.");
-       capture_opts->multi_files_on = FALSE;
+       global_capture_opts.multi_files_on = FALSE;
       }
-      if (!capture_opts->has_autostop_filesize && !capture_opts->has_file_duration) {
+      if (!global_capture_opts.has_autostop_filesize && !global_capture_opts.has_file_duration) {
        cmdarg_err("Ring buffer requested, but no maximum capture file size or duration were specified.");
 /* XXX - this must be redesigned as the conditions changed */
-/*     capture_opts->multi_files_on = FALSE;*/
+/*     global_capture_opts.multi_files_on = FALSE;*/
       }
     }
   }
 
-  if (capture_opts_trim_iface(capture_opts, NULL) == FALSE) {
+  /*
+   * "-D" requires no interface to be selected; it's supposed to list
+   * all interfaces.
+   */
+  if (list_interfaces) {
+    /* Get the list of interfaces */
+    GList       *if_list;
+    int         err;
+    gchar       *err_str;
+
+    if_list = capture_interface_list(&err, &err_str);
+    if (if_list == NULL) {
+        switch (err) {
+        case CANT_GET_INTERFACE_LIST:
+            cmdarg_err("%s", err_str);
+            g_free(err_str);
+            exit_main(2);
+            break;
+
+        case NO_INTERFACES_FOUND:
+            /*
+            * If we're being run by another program, just give them
+            * an empty list of interfaces, don't report this as
+            * an error; that lets them decide whether to report
+            * this as an error or not.
+            */
+            if (!machine_readable) {
+                cmdarg_err("There are no interfaces on which a capture can be done");
+                exit_main(2);
+            }
+            break;
+        }
+    }
+
+    if (machine_readable)      /* tab-separated values to stdout */
+      print_machine_readable_interfaces(if_list);
+    else
+      capture_opts_print_interfaces(if_list);
+    free_interface_list(if_list);
+    exit_main(0);
+  }
+
+  /*
+   * "-S" requires no interface to be selected; it gives statistics
+   * for all interfaces.
+   */
+  if (print_statistics) {
+    status = print_statistics_loop(machine_readable);
+    exit_main(status);
+  }
+
+  /*
+   * "-L", "-d", and capturing act on a particular interface, so we have to
+   * have an interface; if none was specified, pick a default.
+   */
+  if (capture_opts_trim_iface(&global_capture_opts, NULL) == FALSE) {
     /* cmdarg_err() already called .... */
     exit_main(1);
   }
 
   /* Let the user know what interface was chosen. */
   /* get_interface_descriptive_name() is not available! */
-  g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Interface: %s\n", capture_opts->iface);
+  g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Interface: %s\n", global_capture_opts.iface);
+
+  if (list_link_layer_types) {
+    /* Get the list of link-layer types for the capture device. */
+    if_capabilities_t *caps;
+    gchar *err_str;
+
+    caps = get_if_capabilities(global_capture_opts.iface,
+                               global_capture_opts.monitor_mode, &err_str);
+    if (caps == NULL) {
+      cmdarg_err("The capabilities of the capture device \"%s\" could not be obtained (%s).\n"
+       "Please check to make sure you have sufficient permissions, and that\n"
+       "you have the proper interface or pipe specified.", global_capture_opts.iface, err_str);
+      g_free(err_str);
+      exit_main(2);
+    }
+    if (caps->data_link_types == NULL) {
+      cmdarg_err("The capture device \"%s\" has no data link types.", global_capture_opts.iface);
+      exit_main(2);
+    }
+    if (machine_readable)      /* tab-separated values to stdout */
+      print_machine_readable_if_capabilities(caps);
+    else
+      capture_opts_print_if_capabilities(caps,
+                                         global_capture_opts.monitor_mode);
+    free_if_capabilities(caps);
+    exit_main(0);
+  }
 
-  if (list_interfaces) {
-    status = capture_opts_list_interfaces(machine_readable);
-    exit_main(status);
-  } else if (list_link_layer_types) {
-    status = capture_opts_list_link_layer_types(capture_opts, machine_readable);
-    exit_main(status);
-  } else if (print_statistics) {
-    status = capture_opts_print_statistics(machine_readable);
-    exit_main(status);
+  /* We're supposed to do a capture, or print the BPF code for a filter.
+     Process the snapshot length, as that affects the generated BPF code. */
+  capture_opts_trim_snaplen(&global_capture_opts, MIN_PACKET_SIZE);
+
+#ifdef HAVE_BPF_IMAGE
+  if (print_bpf_code) {
+    show_filter_code(&global_capture_opts);
+    exit_main(0);
   }
+#endif
 
-  capture_opts_trim_snaplen(capture_opts, MIN_PACKET_SIZE);
-  capture_opts_trim_ring_num_files(capture_opts);
+  /* We're supposed to do a capture.  Process the ring buffer arguments. */
+  capture_opts_trim_ring_num_files(&global_capture_opts);
 
   /* Now start the capture. */
 
-  if(capture_loop_start(capture_opts, &stats_known, &stats) == TRUE) {
+  if(capture_loop_start(&global_capture_opts, &stats_known, &stats) == TRUE) {
     /* capture ok */
     exit_main(0);
   } else {
@@ -2720,7 +3952,7 @@ console_log_handler(const char *log_domain, GLogLevelFlags log_level,
 /* indication report routines */
 
 
-void
+static void
 report_packet_count(int packet_count)
 {
     char tmp[SP_DECISIZE+1+1];
@@ -2745,9 +3977,30 @@ report_new_capture_file(const char *filename)
         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "File: %s", filename);
         pipe_write_block(2, SP_FILE, filename);
     } else {
+#ifdef SIGINFO
+        /*
+         * Prevent a SIGINFO handler from writing to the standard error
+         * while we're doing so; instead, have it just set a flag telling
+         * us to print that information when we're done.
+         */
+        infodelay = TRUE;
+#endif /* SIGINFO */
         fprintf(stderr, "File: %s\n", filename);
         /* stderr could be line buffered */
         fflush(stderr);
+
+#ifdef SIGINFO
+        /*
+         * Allow SIGINFO handlers to write.
+         */
+        infodelay = FALSE;
+
+        /*
+         * If a SIGINFO handler asked us to write out capture counts, do so.
+         */
+        if (infoprint)
+          report_counts();
+#endif /* SIGINFO */
     }
 }
 
@@ -2777,16 +4030,18 @@ report_capture_error(const char *error_msg, const char *secondary_error_msg)
             "Secondary Error: %s", secondary_error_msg);
        sync_pipe_errmsg_to_parent(2, error_msg, secondary_error_msg);
     } else {
-        fprintf(stderr, "%s\n%s\n", error_msg, secondary_error_msg);
+        fprintf(stderr, "%s\n", error_msg);
+        if (secondary_error_msg[0] != '\0')
+          fprintf(stderr, "%s\n", secondary_error_msg);
     }
 }
 
 void
-report_packet_drops(int drops)
+report_packet_drops(guint32 drops)
 {
     char tmp[SP_DECISIZE+1+1];
 
-    g_snprintf(tmp, sizeof(tmp), "%d", drops);
+    g_snprintf(tmp, sizeof(tmp), "%u", drops);
 
     if(capture_child) {
         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Packets dropped: %s", tmp);
@@ -2846,3 +4101,16 @@ signal_pipe_check_running(void)
     }
 }
 #endif
+
+/*
+ * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */