Frame numbers are unsigned.
[obnox/wireshark/wip.git] / capture.c
index bc96b585e31508ccd70ebc2ae1c83b07ca17ffde..74ee00f8e09e074abd4e798877a0f31b473776e3 100644 (file)
--- a/capture.c
+++ b/capture.c
@@ -1,22 +1,22 @@
 /* capture.c
  * Routines for packet capture windows
  *
- * $Id: capture.c,v 1.185 2002/07/16 05:43:39 guy Exp $
+ * $Id: capture.c,v 1.207 2003/05/15 13:33:53 deniel Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
  * Copyright 1998 Gerald Combs
- * 
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #ifdef HAVE_LIBPCAP
 
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
 #ifdef HAVE_SYS_STAT_H
 # include <sys/stat.h>
 #endif
 # define MUST_DO_SELECT
 #endif
 
-#include "gtk/main.h"
-#include "gtk/gtkglobals.h"
 #include <epan/packet.h>
 #include "file.h"
 #include "capture.h"
 #include "packet-ieee80211.h"
 #include "packet-chdlc.h"
 #include "packet-prism.h"
+#include "packet-ipfc.h"
+#include "packet-arcnet.h"
 
-#ifdef WIN32
+#ifdef _WIN32
 #include "capture-wpcap.h"
 #endif
 
@@ -203,8 +199,8 @@ static char *signame(int);
 #endif
 static void capture_delete_cb(GtkWidget *, GdkEvent *, gpointer);
 static void capture_stop_cb(GtkWidget *, gpointer);
-static void capture_pcap_cb(u_char *, const struct pcap_pkthdr *,
-  const u_char *);
+static void capture_pcap_cb(guchar *, const struct pcap_pkthdr *,
+  const guchar *);
 static void get_capture_file_io_error(char *, int, const char *, int, gboolean);
 static void popup_errmsg(const char *);
 static void send_errmsg_to_parent(const char *);
@@ -238,7 +234,7 @@ typedef struct _loop_data {
 static void adjust_header(loop_data *, struct pcap_hdr *, struct pcaprec_hdr *);
 static int pipe_open_live(char *, struct pcap_hdr *, loop_data *, char *, int);
 static int pipe_dispatch(int, loop_data *, struct pcap_hdr *, \
-               struct pcaprec_modified_hdr *, u_char *, char *, int);
+               struct pcaprec_modified_hdr *, guchar *, char *, int);
 #endif
 
 /* Win32 needs the O_BINARY flag for open() */
@@ -293,11 +289,11 @@ quote_encapsulate(const char *string)
 /* Open a specified file, or create a temporary file, and start a capture
    to the file in question. */
 void
-do_capture(char *capfile_name)
+do_capture(const char *save_file)
 {
   char tmpname[128+1];
   gboolean is_tempfile;
-  u_char c;
+  guchar c;
   int i;
   guint byte_count;
   char *msg;
@@ -305,8 +301,14 @@ do_capture(char *capfile_name)
   int capture_succeeded;
   gboolean stats_known;
   struct pcap_stat stats;
-
-  if (capfile_name != NULL) {
+  gchar *capfile_name;
+
+  if (save_file != NULL) {
+    /* If the Sync option is set, we return to the caller while the capture
+     * is in progress.  Therefore we need to take a copy of save_file in
+     * case the caller destroys it after we return.
+     */
+    capfile_name = g_strdup(save_file);
     if (capture_opts.ringbuffer_on) {
       /* ringbuffer is enabled */
       cfile.save_file_fd = ringbuf_init(capfile_name,
@@ -333,13 +335,16 @@ do_capture(char *capfile_name)
         ringbuf_error_cleanup();
       }
       simple_dialog(ESD_TYPE_CRIT, NULL,
-       file_open_error_message(errno, TRUE), capfile_name);
+       file_open_error_message(errno, TRUE, WTAP_FILE_PCAP), capfile_name);
     }
+    g_free(capfile_name);
     return;
   }
   close_cap_file(&cfile);
   g_assert(cfile.save_file == NULL);
   cfile.save_file = capfile_name;
+  /* cfile.save_file is "g_free"ed below, which is equivalent to
+     "g_free(capfile_name)". */
 
   if (capture_opts.sync_mode) {        /* do the capture in a child process */
     char ssnap[24];
@@ -428,6 +433,7 @@ do_capture(char *capfile_name)
     argv = add_arg(argv, &argc, sync_pipe_fd);
 
     /* Convert filter string to a quote delimited string and pass to child */
+    filterstring = NULL;
     if (cfile.cfilter != NULL && strlen(cfile.cfilter) != 0) {
       argv = add_arg(argv, &argc, "-f");
       filterstring = quote_encapsulate(cfile.cfilter);
@@ -437,11 +443,12 @@ do_capture(char *capfile_name)
     /* Spawn process */
     fork_child = spawnvp(_P_NOWAIT, ethereal_path, argv);
     g_free(fontstring);
-    g_free(filterstring);
+    if (filterstring) {
+      g_free(filterstring);
+    }
     /* Keep a copy for later evaluation by _cwait() */
     child_process = fork_child;
 #else
-    signal(SIGCHLD, SIG_IGN);
     if (pipe(sync_pipe) < 0) {
       /* Couldn't create the pipe between parent and child. */
       error = errno;
@@ -680,7 +687,8 @@ do_capture(char *capfile_name)
         case READ_ABORTED:
           /* Exit by leaving the main loop, so that any quit functions
              we registered get called. */
-          gtk_main_quit();
+          if (gtk_main_level() > 0)
+            gtk_main_quit();
           return;
         }
       }
@@ -739,7 +747,7 @@ cap_timer_cb(gpointer data)
 /* There's stuff to read from the sync pipe, meaning the child has sent
    us a message, or the sync pipe has closed, meaning the child has
    closed it (perhaps because it exited). */
-static void 
+static void
 cap_file_input_cb(gpointer data, gint source _U_,
   GdkInputCondition condition _U_)
 {
@@ -760,7 +768,7 @@ cap_file_input_cb(gpointer data, gint source _U_,
        capturing any more packets.  Pick up its exit status, and
        complain if it did anything other than exit with status 0. */
     wait_for_child(FALSE);
-      
+
     /* Read what remains of the capture file, and finish the capture.
        XXX - do something if this fails? */
     switch (finish_tail_cap_file(cf, &err)) {
@@ -839,7 +847,7 @@ cap_file_input_cb(gpointer data, gint source _U_,
       q++;
       nread--;
       break;
-    } 
+    }
   }
 
   /* Read from the capture file the number of records the child told us
@@ -974,7 +982,7 @@ signame(int sig)
     sigmsg = "Segmentation violation";
     break;
 
-  /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO 
+  /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
      Linux is POSIX compliant.  These are not POSIX-defined signals ---
      ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
 
@@ -1025,7 +1033,7 @@ signame(int sig)
 #define        CAP_READ_TIMEOUT        250
 
 #ifndef _WIN32
-/* Take carre of byte order in the libpcap headers read from pipes.
+/* Take care of byte order in the libpcap headers read from pipes.
  * (function taken from wiretap/libpcap.c) */
 static void
 adjust_header(loop_data *ld, struct pcap_hdr *hdr, struct pcaprec_hdr *rechdr)
@@ -1056,7 +1064,7 @@ adjust_header(loop_data *ld, struct pcap_hdr *hdr, struct pcaprec_hdr *rechdr)
   }
 }
 
-/* Mimic pcap_open_live() for pipe captures 
+/* Mimic pcap_open_live() for pipe captures
  * We check if "pipename" is "-" (stdin) or a FIFO, open it, and read the
  * header.
  * N.B. : we can't read the libpcap formats used in RedHat 6.1 or SuSE 6.3
@@ -1130,7 +1138,7 @@ pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
         "Unexpected error from select: %s", strerror(errno));
       goto error;
     } else if (sel_ret > 0) {
-      b = read(fd, &magic+bytes_read, sizeof magic-bytes_read);
+      b = read(fd, ((char *)&magic)+bytes_read, sizeof magic-bytes_read);
       if (b <= 0) {
         if (b == 0)
           snprintf(errmsg, errmsgl, "End of file on pipe during open");
@@ -1231,7 +1239,7 @@ error:
 
 static int
 pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr,
-               struct pcaprec_modified_hdr *rechdr, u_char *data,
+               struct pcaprec_modified_hdr *rechdr, guchar *data,
                char *errmsg, int errmsgl)
 {
   struct pcap_pkthdr phdr;
@@ -1310,9 +1318,9 @@ pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr,
     phdr.ts.tv_usec = rechdr->hdr.ts_usec;
     phdr.caplen = rechdr->hdr.incl_len;
     phdr.len = rechdr->hdr.orig_len;
-  
-    capture_pcap_cb((u_char *)ld, &phdr, data);
-  
+
+    capture_pcap_cb((guchar *)ld, &phdr, data);
+
     ld->pipe_state = STATE_EXPECT_REC_HDR;
     return 1;
 
@@ -1323,9 +1331,9 @@ pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr,
   case PD_PIPE_ERR:
     snprintf(errmsg, errmsgl, "Error reading from pipe: %s",
       strerror(errno));
+    /* Fall through */
   case PD_ERR:
-    /* Fall out */
-
+    break;
   }
 
   ld->pipe_err = PIPERR;
@@ -1346,6 +1354,7 @@ int
 capture(gboolean *stats_known, struct pcap_stat *stats)
 {
   GtkWidget  *cap_w, *main_vb, *stop_bt, *counts_tb;
+  GtkWidget  *counts_fr, *running_tb, *running_label, *running_time;
   pcap_t     *pch;
   int         pcap_encap;
   int         file_snaplen;
@@ -1355,13 +1364,16 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
   bpf_u_int32 netnum, netmask;
   struct bpf_program fcode;
   time_t      upd_time, cur_time;
+  time_t      start_time;
   int         err, inpkts;
   condition  *cnd_stop_capturesize = NULL;
   condition  *cnd_stop_timeout = NULL;
+  condition  *cnd_ring_timeout = NULL;
   unsigned int i;
   static const char capstart_msg = SP_CAPSTART;
   char        errmsg[4096+1];
-  gboolean    dump_ok;
+  gboolean    write_ok;
+  gboolean    close_ok;
   fd_set      set1;
   struct timeval timeout;
   struct {
@@ -1374,6 +1386,7 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
       { "TCP", &ld.counts.tcp, NULL, NULL, NULL },
       { "UDP", &ld.counts.udp, NULL, NULL, NULL },
       { "ICMP", &ld.counts.icmp, NULL, NULL, NULL },
+      { "ARP", &ld.counts.arp, NULL, NULL, NULL },
       { "OSPF", &ld.counts.ospf, NULL, NULL, NULL },
       { "GRE", &ld.counts.gre, NULL, NULL, NULL },
       { "NetBIOS", &ld.counts.netbios, NULL, NULL, NULL },
@@ -1384,9 +1397,9 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
 
 #define N_COUNTS (sizeof counts / sizeof counts[0])
 
-#ifdef _WIN32 
-  WORD wVersionRequested; 
-  WSADATA wsaData; 
+#ifdef _WIN32
+  WORD wVersionRequested;
+  WSADATA wsaData;
 #else
   static const char ppamsg[] = "can't find PPA for ";
   char       *libpcap_warn;
@@ -1394,7 +1407,7 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
   int         pipe_fd = -1;
   struct pcap_hdr hdr;
   struct pcaprec_modified_hdr rechdr;
-  u_char pcap_data[WTAP_MAX_PACKET_SIZE];
+  guchar pcap_data[WTAP_MAX_PACKET_SIZE];
 #endif
 #ifdef MUST_DO_SELECT
   int         pcap_fd = 0;
@@ -1404,18 +1417,18 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
    signed/unsigned 64-bit int */
 #define DECISIZE 20
 
-  /* Initialize Windows Socket if we are in a WIN32 OS 
+  /* Initialize Windows Socket if we are in a WIN32 OS
      This needs to be done before querying the interface for network/netmask */
-#ifdef _WIN32 
-  wVersionRequested = MAKEWORD( 1, 1 ); 
-  err = WSAStartup( wVersionRequested, &wsaData ); 
-  if (err!=0) { 
-    snprintf(errmsg, sizeof errmsg, 
-      "Couldn't initialize Windows Sockets."); 
-       pch=NULL; 
-    goto error; 
-  } 
-#endif 
+#ifdef _WIN32
+  wVersionRequested = MAKEWORD( 1, 1 );
+  err = WSAStartup( wVersionRequested, &wsaData );
+  if (err!=0) {
+    snprintf(errmsg, sizeof errmsg,
+      "Couldn't initialize Windows Sockets.");
+       pch=NULL;
+    goto error;
+  }
+#endif
 
   ld.go             = TRUE;
   ld.counts.total   = 0;
@@ -1438,6 +1451,7 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
   ld.counts.netbios = 0;
   ld.counts.vines   = 0;
   ld.counts.other   = 0;
+  ld.counts.arp     = 0;
   ld.pdh            = NULL;
 
   /* We haven't yet gotten the capture statistics. */
@@ -1455,8 +1469,9 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
                       open_err_str);
 
   if (pch == NULL) {
+    /* We couldn't open "cfile.iface" as a network device. */
 #ifdef _WIN32
-    /* Well, we couldn't start the capture.
+    /* On Windows, we don't support capturing on pipes, so we give up.
        If this is a child process that does the capturing in sync
        mode or fork mode, it shouldn't do any UI stuff until we pop up the
        capture-progress window, and, since we couldn't start the
@@ -1473,8 +1488,8 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
        "The capture session could not be initiated (%s).\n"
        "Please check that you have the proper interface specified.\n"
        "\n"
-       "Note that the driver Ethereal uses for packet capture on Windows\n"
-       "doesn't support capturing on PPP/WAN interfaces in Windows NT/2000/XP/.NET Server.\n",
+       "Note that the driver Ethereal uses for packet capture on Windows doesn't\n"
+       "support capturing on PPP/WAN interfaces in Windows NT/2000/XP/.NET Server.\n",
        open_err_str);
     goto error;
 #else
@@ -1578,7 +1593,7 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
     goto error;
   }
   if (capture_opts.ringbuffer_on) {
-    ld.pdh = ringbuf_init_wtap_dump_fdopen(WTAP_FILE_PCAP, ld.linktype, 
+    ld.pdh = ringbuf_init_wtap_dump_fdopen(WTAP_FILE_PCAP, ld.linktype,
       file_snaplen, &err);
   } else {
     ld.pdh = wtap_dump_fdopen(cfile.save_file_fd, WTAP_FILE_PCAP,
@@ -1650,9 +1665,14 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
   gtk_container_add(GTK_CONTAINER(cap_w), main_vb);
   gtk_widget_show(main_vb);
 
+  counts_fr = gtk_frame_new("Captured Frames");
+  gtk_box_pack_start(GTK_BOX(main_vb), counts_fr, FALSE, FALSE, 3);
+  gtk_widget_show(counts_fr);
+
   /* Individual statistic elements */
   counts_tb = gtk_table_new(N_COUNTS, 3, TRUE);
-  gtk_box_pack_start(GTK_BOX(main_vb), counts_tb, TRUE, TRUE, 3);
+  gtk_container_add(GTK_CONTAINER(counts_fr), counts_tb);
+  gtk_container_border_width(GTK_CONTAINER(counts_tb), 5);
   gtk_widget_show(counts_tb);
 
   for (i = 0; i < N_COUNTS; i++) {
@@ -1680,6 +1700,24 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
       gtk_widget_show(counts[i].percent);
   }
 
+  /* Running time */
+  running_tb = gtk_table_new(1, 3, TRUE);
+  gtk_box_pack_start(GTK_BOX(main_vb), running_tb, FALSE, FALSE, 3);
+  gtk_widget_show(running_tb);
+
+  running_label = gtk_label_new("Running");
+  gtk_misc_set_alignment(GTK_MISC(running_label), 0.0f, 0.0f);
+  gtk_widget_show(running_label);
+  gtk_table_attach_defaults(GTK_TABLE(running_tb),
+                                running_label, 0, 1, 0, 1);
+
+  running_time = gtk_label_new("00:00:00");
+  gtk_misc_set_alignment(GTK_MISC(running_time), 0.0f, 0.0f);
+  gtk_widget_show(running_time);
+  gtk_table_attach(GTK_TABLE(running_tb),
+                       running_time,
+                       1, 2, 0, 1, 0, 0, 5, 0);
+
   /* allow user to either click a stop button, or the close button on
        the window to stop a capture in progress. */
   stop_bt = gtk_button_new_with_label ("Stop");
@@ -1687,7 +1725,7 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
     GTK_SIGNAL_FUNC(capture_stop_cb), (gpointer) &ld);
   gtk_signal_connect(GTK_OBJECT(cap_w), "delete_event",
        GTK_SIGNAL_FUNC(capture_delete_cb), (gpointer) &ld);
-  gtk_box_pack_end(GTK_BOX(main_vb), stop_bt, FALSE, FALSE, 3);
+  gtk_box_pack_start(GTK_BOX(main_vb), stop_bt, FALSE, FALSE, 3);
   GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT);
   gtk_widget_grab_default(stop_bt);
   GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT);
@@ -1696,6 +1734,7 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
 
   gtk_widget_show(cap_w);
 
+  start_time = time(NULL);
   upd_time = time(NULL);
 #ifdef MUST_DO_SELECT
   if (!ld.from_pipe) pcap_fd = pcap_fileno(pch);
@@ -1709,16 +1748,20 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
   if (capture_child)
     signal(SIGUSR1, stop_capture);
 #endif
-  /* initialize capture stop conditions */ 
+  /* initialize capture stop conditions */
   init_capture_stop_conditions();
   /* create stop conditions */
   if (capture_opts.has_autostop_filesize)
     cnd_stop_capturesize =
-        cnd_new(CND_CLASS_CAPTURESIZE,(long)capture_opts.autostop_filesize * 1000); 
+        cnd_new(CND_CLASS_CAPTURESIZE,(long)capture_opts.autostop_filesize * 1000);
   if (capture_opts.has_autostop_duration)
     cnd_stop_timeout =
         cnd_new(CND_CLASS_TIMEOUT,(gint32)capture_opts.autostop_duration);
 
+  if (capture_opts.ringbuffer_on && capture_opts.has_ring_duration)
+    cnd_ring_timeout =
+       cnd_new(CND_CLASS_TIMEOUT, capture_opts.ringbuffer_duration);
+
   while (ld.go) {
     while (gtk_events_pending()) gtk_main_iteration();
 
@@ -1789,7 +1832,7 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
         * "select()" says we can read from it without blocking; go for
         * it.
         */
-       inpkts = pcap_dispatch(pch, 1, capture_pcap_cb, (u_char *) &ld);
+       inpkts = pcap_dispatch(pch, 1, capture_pcap_cb, (guchar *) &ld);
        if (inpkts < 0) {
          ld.pcap_err = TRUE;
          ld.go = FALSE;
@@ -1804,7 +1847,7 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
         }
       }
 #else
-      inpkts = pcap_dispatch(pch, 1, capture_pcap_cb, (u_char *) &ld);
+      inpkts = pcap_dispatch(pch, 1, capture_pcap_cb, (guchar *) &ld);
       if (inpkts < 0) {
         ld.pcap_err = TRUE;
         ld.go = FALSE;
@@ -1815,7 +1858,7 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
     if (inpkts > 0) {
       ld.sync_packets += inpkts;
       /* check capture stop conditons */
-      if (cnd_stop_capturesize != NULL && cnd_eval(cnd_stop_capturesize, 
+      if (cnd_stop_capturesize != NULL && cnd_eval(cnd_stop_capturesize,
                     (guint32)wtap_get_bytes_dumped(ld.pdh))){
         /* Capture file reached its maximum size. */
         if (capture_opts.ringbuffer_on) {
@@ -1823,6 +1866,9 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
           if (ringbuf_switch_file(&cfile, &ld.pdh, &ld.err)) {
             /* File switch succeeded: reset the condition */
             cnd_reset(cnd_stop_capturesize);
+           if (cnd_ring_timeout) {
+             cnd_reset(cnd_ring_timeout);
+           }
           } else {
             /* File switch failed: stop here */
             ld.go = FALSE;
@@ -1840,17 +1886,24 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
     if (cur_time > upd_time) {
       upd_time = cur_time;
 
+      /* calculate and display running time */
+      cur_time -= start_time;
+      snprintf(label_str, sizeof(label_str), "%02ld:%02ld:%02ld", 
+               (long)(cur_time/3600), (long)((cur_time%3600)/60),
+               (long)(cur_time%60));
+      gtk_label_set(GTK_LABEL(running_time), label_str);
+
       if (ld.sync_packets) {
 
         for (i = 0; i < N_COUNTS; i++) {
             snprintf(label_str, sizeof(label_str), "%d",
                      *counts[i].value_ptr);
-  
+
             gtk_label_set(GTK_LABEL(counts[i].value), label_str);
-  
+
             snprintf(label_str, sizeof(label_str), "(%.1f%%)",
                      pct(*counts[i].value_ptr, ld.counts.total));
-  
+
             gtk_label_set(GTK_LABEL(counts[i].percent), label_str);
         }
 
@@ -1873,15 +1926,27 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
       if (cnd_stop_timeout != NULL && cnd_eval(cnd_stop_timeout)) {
         /* The specified capture time has elapsed; stop the capture. */
         ld.go = FALSE;
+      } else if (cnd_ring_timeout != NULL && cnd_eval(cnd_ring_timeout)) {
+       /* time elasped for this ring file, swith to the next */
+       if (ringbuf_switch_file(&cfile, &ld.pdh, &ld.err)) {
+         /* File switch succeeded: reset the condition */
+         cnd_reset(cnd_ring_timeout);
+       } else {
+         /* File switch failed: stop here */
+         ld.go = FALSE;
+       }
       }
     }
+
   } /* while (ld.go) */
-    
+
   /* delete stop conditions */
   if (cnd_stop_capturesize != NULL)
     cnd_delete(cnd_stop_capturesize);
   if (cnd_stop_timeout != NULL)
     cnd_delete(cnd_stop_timeout);
+  if (cnd_ring_timeout != NULL)
+    cnd_delete(cnd_ring_timeout);
 
   if (ld.pcap_err) {
     snprintf(errmsg, sizeof(errmsg), "Error while capturing packets: %s",
@@ -1894,31 +1959,29 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
       popup_errmsg(errmsg);
 #endif
 
-  if (ld.err != 0) {
+  if (ld.err == 0)
+    write_ok = TRUE;
+  else {
     get_capture_file_io_error(errmsg, sizeof(errmsg), cfile.save_file, ld.err,
                              FALSE);
     popup_errmsg(errmsg);
+    write_ok = FALSE;
+  }
 
-    /* A write failed, so we've already told the user there's a problem;
-       if the close fails, there's no point in telling them about that
-       as well. */
-    if (capture_opts.ringbuffer_on) {
-      ringbuf_wtap_dump_close(&cfile, &err);
-    } else {
-      wtap_dump_close(ld.pdh, &err);
-    }
-   } else {
-    if (capture_opts.ringbuffer_on) {
-      dump_ok = ringbuf_wtap_dump_close(&cfile, &err);
-    } else {
-      dump_ok = wtap_dump_close(ld.pdh, &err);
-    }
-    if (!dump_ok) {
-      get_capture_file_io_error(errmsg, sizeof(errmsg), cfile.save_file, err,
-                               TRUE);
-      popup_errmsg(errmsg);
-    }
+  if (capture_opts.ringbuffer_on) {
+    close_ok = ringbuf_wtap_dump_close(&cfile, &err);
+  } else {
+    close_ok = wtap_dump_close(ld.pdh, &err);
+  }
+  /* If we've displayed a message about a write error, there's no point
+     in displaying another message about an error on close. */
+  if (!close_ok && write_ok) {
+    get_capture_file_io_error(errmsg, sizeof(errmsg), cfile.save_file, err,
+               TRUE);
+    popup_errmsg(errmsg);
   }
+  /* Set write_ok to mean the write and the close were successful. */
+  write_ok = (write_ok && close_ok);
 
 #ifndef _WIN32
   /*
@@ -1953,7 +2016,7 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
     pcap_close(pch);
   }
 
-#ifdef WIN32
+#ifdef _WIN32
   /* Shut down windows sockets */
   WSACleanup();
 #endif
@@ -1961,7 +2024,7 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
   gtk_grab_remove(GTK_WIDGET(cap_w));
   gtk_widget_destroy(GTK_WIDGET(cap_w));
 
-  return TRUE;
+  return write_ok;
 
 error:
   if (capture_opts.ringbuffer_on) {
@@ -1980,7 +2043,7 @@ error:
   cfile.save_file = NULL;
   popup_errmsg(errmsg);
 
-#ifndef WIN32
+#ifndef _WIN32
   if (ld.from_pipe) {
     if (pipe_fd >= 0)
       close(pipe_fd);
@@ -2100,7 +2163,7 @@ capture_delete_cb(GtkWidget *w _U_, GdkEvent *event _U_, gpointer data) {
 static void
 capture_stop_cb(GtkWidget *w _U_, gpointer data) {
   loop_data *ld = (loop_data *) data;
-  
+
   ld->go = FALSE;
 }
 
@@ -2129,15 +2192,15 @@ kill_capture_child(void)
 }
 
 static void
-capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
-  const u_char *pd)
+capture_pcap_cb(guchar *user, const struct pcap_pkthdr *phdr,
+  const guchar *pd)
 {
   struct wtap_pkthdr whdr;
   union wtap_pseudo_header pseudo_header;
   loop_data *ld = (loop_data *) user;
   int err;
 
-  if ((++ld->counts.total >= ld->max) && (ld->max > 0)) 
+  if ((++ld->counts.total >= ld->max) && (ld->max > 0))
   {
      ld->go = FALSE;
   }
@@ -2202,9 +2265,18 @@ capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
     case WTAP_ENCAP_LOCALTALK:
       capture_llap(&ld->counts);
       break;
-    case WTAP_ENCAP_ATM_SNIFFER:
+    case WTAP_ENCAP_ATM_PDUS:
       capture_atm(&pseudo_header, pd, whdr.caplen, &ld->counts);
       break;
+    case WTAP_ENCAP_IP_OVER_FC:
+      capture_ipfc(pd, whdr.caplen, &ld->counts);
+      break;
+    case WTAP_ENCAP_ARCNET:
+      capture_arcnet(pd, whdr.caplen, &ld->counts, FALSE, TRUE);
+      break;
+    case WTAP_ENCAP_ARCNET_LINUX:
+      capture_arcnet(pd, whdr.caplen, &ld->counts, TRUE, FALSE);
+      break;
     /* XXX - some ATM drivers on FreeBSD might prepend a 4-byte ATM
        pseudo-header to DLT_ATM_RFC1483, with LLC header following;
        we might have to implement that at some point. */