Show the "More Fragments" indicator as such, rather than as a "this is
[obnox/wireshark/wip.git] / capture.c
index 73dc2898829d12c076d8092f2c10d389a22aaf0d..68ea732eaf6ff036c612532ef4ed8b7fb4221ec8 100644 (file)
--- a/capture.c
+++ b/capture.c
@@ -1,12 +1,11 @@
 /* capture.c
  * Routines for packet capture windows
  *
- * $Id: capture.c,v 1.148 2001/04/13 14:59:28 jfoster Exp $
+ * $Id: capture.c,v 1.172 2002/04/08 09:09:47 guy Exp $
  *
  * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
+ * 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
 
 #include "gtk/main.h"
 #include "gtk/gtkglobals.h"
-#include "packet.h"
+#include <epan/packet.h>
 #include "file.h"
 #include "capture.h"
 #include "util.h"
+#include "pcap-util.h"
 #include "simple_dialog.h"
 #include "prefs.h"
 #include "globals.h"
+#include "conditions.h"
+#include "capture_stop_conditions.h"
+#include "ringbuffer.h"
 
 #include "wiretap/libpcap.h"
 #include "wiretap/wtap.h"
 
+#include "packet-atalk.h"
 #include "packet-clip.h"
 #include "packet-eth.h"
 #include "packet-fddi.h"
 #include "packet-tr.h"
 #include "packet-ieee80211.h"
 #include "packet-chdlc.h"
+#include "packet-prism.h"
+
+#ifdef WIN32
+#include "capture-wpcap.h"
+#endif
+
+/*
+ * Capture options.
+ */
+capture_options capture_opts;
 
 static int sync_pipe[2]; /* used to sync father */
 enum PIPES { READ, WRITE }; /* Constants 0 and 1 for READ and WRITE */
 int quit_after_cap; /* Makes a "capture only mode". Implies -k */
 gboolean capture_child;        /* if this is the child for "-S" */
-static int fork_child; /* In parent, process ID of child */
+static int fork_child = -1;    /* If not -1, in parent, process ID of child */
 static guint cap_input_id;
 
 /*
  * Indications sent out on the sync pipe.
  */
 #define SP_CAPSTART    ';'     /* capture start message */
-#define SP_PACKET_COUNT        '*'     /* count of packets captured since last message */
-#define SP_ERROR_MSG   '!'     /* length of error message that follows */
-#define SP_DROPS       '#'     /* count of packets dropped in capture */
+#define SP_PACKET_COUNT        '*'     /* followed by count of packets captured since last message */
+#define SP_ERROR_MSG   '!'     /* followed by length of error message that follows */
+#define SP_DROPS       '#'     /* followed by count of packets dropped in capture */
 
 #ifdef _WIN32
 static guint cap_timer_id;
@@ -195,11 +209,12 @@ static float pct(gint, gint);
 static void stop_capture(int signo);
 
 typedef struct _loop_data {
-  gint           go;           /* TRUE as long as we're supposed to keep capturing */
+  gboolean       go;           /* TRUE as long as we're supposed to keep capturing */
   gint           max;          /* Number of packets we're supposed to capture - 0 means infinite */
   int            err;          /* if non-zero, error seen while capturing */
   gint           linktype;
   gint           sync_packets;
+  gboolean       pcap_err;     /* TRUE if error from pcap */
   gboolean       from_pipe;    /* TRUE if we are capturing data from a pipe */
   gboolean       modified;     /* TRUE if data in the pipe uses modified pcap headers */
   gboolean       byte_swapped; /* TRUE if data in the pipe is byte swapped */
@@ -279,8 +294,15 @@ do_capture(char *capfile_name)
   struct pcap_stat stats;
 
   if (capfile_name != NULL) {
-    /* Try to open/create the specified file for use as a capture buffer. */
-    cfile.save_file_fd = open(capfile_name, O_RDWR|O_BINARY|O_TRUNC|O_CREAT, 0600);
+    if (capture_opts.ringbuffer_on) {
+      /* ringbuffer is enabled */
+      cfile.save_file_fd = ringbuf_init(capfile_name,
+                                       capture_opts.ringbuffer_num_files);
+    } else {
+      /* Try to open/create the specified file for use as a capture buffer. */
+      cfile.save_file_fd = open(capfile_name, O_RDWR|O_BINARY|O_TRUNC|O_CREAT,
+                               0600);
+    }
     is_tempfile = FALSE;
   } else {
     /* Choose a random name for the capture buffer */
@@ -294,18 +316,23 @@ do_capture(char *capfile_name)
        "The temporary file to which the capture would be saved (\"%s\")"
        "could not be opened: %s.", capfile_name, strerror(errno));
     } else {
+      if (capture_opts.ringbuffer_on) {
+        ringbuf_error_cleanup();
+      }
       simple_dialog(ESD_TYPE_CRIT, NULL,
        file_open_error_message(errno, TRUE), capfile_name);
     }
     return;
   }
-  close_cap_file(&cfile, info_bar);
+  close_cap_file(&cfile);
   g_assert(cfile.save_file == NULL);
   cfile.save_file = capfile_name;
 
-  if (prefs.capture_auto_scroll) {     /* do the capture in a child process */
+  if (capture_opts.sync_mode) {        /* do the capture in a child process */
     char ssnap[24];
-    char scount[24];   /* need a constant for len of numbers */
+    char scount[24];                   /* need a constant for len of numbers */
+    char sautostop_filesize[24];       /* need a constant for len of numbers */
+    char sautostop_duration[24];       /* need a constant for len of numbers */
     char save_file_fd[24];
     char errmsg[1024+1];
     int error;
@@ -336,15 +363,31 @@ do_capture(char *capfile_name)
     sprintf(save_file_fd,"%d",cfile.save_file_fd);     /* in lieu of itoa */
     argv = add_arg(argv, &argc, save_file_fd);
 
-    argv = add_arg(argv, &argc, "-c");
-    sprintf(scount,"%d",cfile.count);
-    argv = add_arg(argv, &argc, scount);
+    if (capture_opts.has_autostop_count) {
+      argv = add_arg(argv, &argc, "-c");
+      sprintf(scount,"%d",capture_opts.autostop_count);
+      argv = add_arg(argv, &argc, scount);
+    }
+
+    if (capture_opts.has_snaplen) {
+      argv = add_arg(argv, &argc, "-s");
+      sprintf(ssnap,"%d",capture_opts.snaplen);
+      argv = add_arg(argv, &argc, ssnap);
+    }
+
+    if (capture_opts.has_autostop_filesize) {
+      argv = add_arg(argv, &argc, "-a");
+      sprintf(sautostop_filesize,"filesize:%d",capture_opts.autostop_filesize);
+      argv = add_arg(argv, &argc, sautostop_filesize);
+    }
 
-    argv = add_arg(argv, &argc, "-s");
-    sprintf(ssnap,"%d",cfile.snap);
-    argv = add_arg(argv, &argc, ssnap);
+    if (capture_opts.has_autostop_duration) {
+      argv = add_arg(argv, &argc, "-a");
+      sprintf(sautostop_duration,"duration:%d",capture_opts.autostop_duration);
+      argv = add_arg(argv, &argc, sautostop_duration);
+    }
 
-    if (!prefs.capture_prom_mode)
+    if (!capture_opts.promisc_mode)
       argv = add_arg(argv, &argc, "-p");
 
 #ifdef _WIN32
@@ -536,27 +579,30 @@ do_capture(char *capfile_name)
     } else {
       /* Failure - the child process sent us a message indicating
         what the problem was. */
-      msg = g_malloc(byte_count + 1);
-      if (msg == NULL) {
-       simple_dialog(ESD_TYPE_WARN, NULL,
-               "Capture child process failed, but its error message was too big.");
-      } else if (byte_count == 0) {
-       /* Zero-length message? */
+      if (byte_count == 0) {
+       /* Zero-length message? */
        simple_dialog(ESD_TYPE_WARN, NULL,
                "Capture child process failed, but its error message was empty.");
       } else {
-       i = read(sync_pipe[READ], msg, byte_count);
-       if (i < 0) {
+       msg = g_malloc(byte_count + 1);
+       if (msg == NULL) {
          simple_dialog(ESD_TYPE_WARN, NULL,
+               "Capture child process failed, but its error message was too big.");
+       } else {
+         i = read(sync_pipe[READ], msg, byte_count);
+         msg[byte_count] = '\0';
+         if (i < 0) {
+           simple_dialog(ESD_TYPE_WARN, NULL,
                  "Capture child process failed: Error %s reading its error message.",
                  strerror(errno));
-       } else if (i == 0) {
-         simple_dialog(ESD_TYPE_WARN, NULL,
+         } else if (i == 0) {
+           simple_dialog(ESD_TYPE_WARN, NULL,
                  "Capture child process failed: EOF reading its error message.");
-         wait_for_child(FALSE);
-       } else
-         simple_dialog(ESD_TYPE_WARN, NULL, msg);
-       g_free(msg);
+           wait_for_child(FALSE);
+         } else
+           simple_dialog(ESD_TYPE_WARN, NULL, msg);
+         g_free(msg);
+       }
 
        /* Close the sync pipe. */
        close(sync_pipe[READ]);
@@ -631,7 +677,11 @@ do_capture(char *capfile_name)
     }
     /* We're not doing a capture any more, so we don't have a save
        file. */
-    g_free(cfile.save_file);
+    if (capture_opts.ringbuffer_on) {
+      ringbuf_free();
+    } else {
+      g_free(cfile.save_file);
+    }
     cfile.save_file = NULL;
   }
 }
@@ -858,6 +908,9 @@ wait_for_child(gboolean always_report)
                    "Child capture process died: wait status %#o", wstatus);
     }
   }
+
+  /* No more child process. */
+  fork_child = -1;
 #endif
 }
 
@@ -957,8 +1010,21 @@ signame(int sig)
 
 /*
  * Timeout, in milliseconds, for reads from the stream of captured packets.
+ *
+ * XXX - Michael Tuexen says MacOS X's BPF appears to be broken, in that
+ * if you use a timeout of 250 in "pcap_open_live()", you don't see
+ * packets until a large number of packets arrive; the timeout doesn't
+ * cause a smaller number of packets to be delivered.  Perhaps a timeout
+ * that's less than 1 second acts like no timeout at all, so that you
+ * don't see packets until the BPF buffer fills up?
+ *
+ * The workaround is to use a timeout of 1000 seconds on MacOS X.
  */
+#ifdef __APPLE__
+#define        CAP_READ_TIMEOUT        1000
+#else
 #define        CAP_READ_TIMEOUT        250
+#endif
 
 #ifndef _WIN32
 /* Take carre of byte order in the libpcap headers read from pipes.
@@ -1056,7 +1122,7 @@ pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld, char *ebuf)
     close(fd);
     return -1;
   }
-  while (bytes_read < sizeof(struct pcap_hdr))
+  while ((unsigned) bytes_read < sizeof(struct pcap_hdr))
   {
     b = read(fd, ((char *)&hdr)+bytes_read, sizeof(struct pcap_hdr) - bytes_read);
     if (b <= 0) {
@@ -1123,7 +1189,7 @@ pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr)
     ld->go = FALSE;
     return 0;
   }
-  while (bytes_read < rechdr.hdr.incl_len)
+  while ((unsigned) bytes_read < rechdr.hdr.incl_len)
   {
     b = read(fd, pd+bytes_read, rechdr.hdr.incl_len - bytes_read);
     if (b <= 0) {
@@ -1141,41 +1207,42 @@ pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr)
   whdr.pkt_encap = ld->linktype;
   wtap_dump(ld->pdh, &whdr, NULL, pd, &err);
 
-  /* Set the initial payload to the packet length, and the initial
-     captured payload to the capture length (other protocols may
-     reduce them if their headers say they're less). */
-  pi.len = whdr.len;
-  pi.captured_len = whdr.caplen;
-    
   /* update capture statistics */
   switch (ld->linktype) {
     case WTAP_ENCAP_ETHERNET:
-      capture_eth(pd, 0, &ld->counts);
+      capture_eth(pd, 0, whdr.caplen, &ld->counts);
       break;
     case WTAP_ENCAP_FDDI:
     case WTAP_ENCAP_FDDI_BITSWAPPED:
-      capture_fddi(pd, &ld->counts);
+      capture_fddi(pd, whdr.caplen, &ld->counts);
+      break;
+    case WTAP_ENCAP_PRISM_HEADER:
+      capture_prism(pd, 0, whdr.caplen, &ld->counts);
       break;
     case WTAP_ENCAP_TOKEN_RING:
-      capture_tr(pd, 0, &ld->counts);
+      capture_tr(pd, 0, whdr.caplen, &ld->counts);
       break;
     case WTAP_ENCAP_NULL:
-      capture_null(pd, &ld->counts);
+      capture_null(pd, whdr.caplen, &ld->counts);
       break;
     case WTAP_ENCAP_PPP:
-      capture_ppp_hdlc(pd, 0, &ld->counts);
+      capture_ppp_hdlc(pd, 0, whdr.caplen, &ld->counts);
       break;
     case WTAP_ENCAP_RAW_IP:
-      capture_raw(pd, &ld->counts);
+      capture_raw(pd, whdr.caplen, &ld->counts);
       break;
     case WTAP_ENCAP_LINUX_ATM_CLIP:
-      capture_clip(pd, &ld->counts);
+      capture_clip(pd, whdr.caplen, &ld->counts);
       break;
     case WTAP_ENCAP_IEEE_802_11:
-      capture_ieee80211(pd, 0, &ld->counts);
+    case WTAP_ENCAP_IEEE_802_11_WITH_RADIO:
+      capture_ieee80211(pd, 0, whdr.caplen, &ld->counts);
       break;
     case WTAP_ENCAP_CHDLC:
-      capture_chdlc(pd, 0, &ld->counts);
+      capture_chdlc(pd, 0, whdr.caplen, &ld->counts);
+      break;
+    case WTAP_ENCAP_LOCALTALK:
+      capture_llap(pd, whdr.caplen, &ld->counts);
       break;
     /* XXX - FreeBSD may append 4-byte ATM pseudo-header to DLT_ATM_RFC1483,
        with LLC header following; we should implement it at some
@@ -1200,14 +1267,20 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
   GtkWidget  *cap_w, *main_vb, *stop_bt, *counts_tb;
   pcap_t     *pch;
   int         pcap_encap;
-  int         snaplen;
-  gchar       err_str[PCAP_ERRBUF_SIZE], label_str[64];
+  int         file_snaplen;
+  gchar       open_err_str[PCAP_ERRBUF_SIZE];
+  gchar       lookup_net_err_str[PCAP_ERRBUF_SIZE];
+  gchar       label_str[64];
   bpf_u_int32 netnum, netmask;
   struct bpf_program fcode;
   time_t      upd_time, cur_time;
-  int         err, inpkts, i;
+  int         err, inpkts;
+  condition  *cnd_stop_capturesize = NULL;
+  condition  *cnd_stop_timeout = NULL;
+  unsigned int i;
   static const char capstart_msg = SP_CAPSTART;
   char        errmsg[4096+1];
+  gboolean    dump_ok;
 #ifndef _WIN32
   static const char ppamsg[] = "can't find PPA for ";
   char       *libpcap_warn;
@@ -1230,17 +1303,17 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
       gint *value_ptr;
       GtkWidget *label, *value, *percent;
   } counts[] = {
-      { "Total", &ld.counts.total },
-      { "SCTP", &ld.counts.sctp },
-      { "TCP", &ld.counts.tcp },
-      { "UDP", &ld.counts.udp },
-      { "ICMP", &ld.counts.icmp },
-      { "OSPF", &ld.counts.ospf },
-      { "GRE", &ld.counts.gre },
-      { "NetBIOS", &ld.counts.netbios },
-      { "IPX", &ld.counts.ipx },
-      { "VINES", &ld.counts.vines },
-      { "Other", &ld.counts.other }
+      { "Total", &ld.counts.total, NULL, NULL, NULL },
+      { "SCTP", &ld.counts.sctp, NULL, NULL, NULL },
+      { "TCP", &ld.counts.tcp, NULL, NULL, NULL },
+      { "UDP", &ld.counts.udp, NULL, NULL, NULL },
+      { "ICMP", &ld.counts.icmp, NULL, NULL, NULL },
+      { "OSPF", &ld.counts.ospf, NULL, NULL, NULL },
+      { "GRE", &ld.counts.gre, NULL, NULL, NULL },
+      { "NetBIOS", &ld.counts.netbios, NULL, NULL, NULL },
+      { "IPX", &ld.counts.ipx, NULL, NULL, NULL },
+      { "VINES", &ld.counts.vines, NULL, NULL, NULL },
+      { "Other", &ld.counts.other, NULL, NULL, NULL }
   };
 
 #define N_COUNTS (sizeof counts / sizeof counts[0])
@@ -1260,9 +1333,13 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
 
   ld.go             = TRUE;
   ld.counts.total   = 0;
-  ld.max            = cfile.count;
+  if (capture_opts.has_autostop_count)
+    ld.max          = capture_opts.autostop_count;
+  else
+    ld.max          = 0;       /* no limit */
   ld.err            = 0;       /* no error seen yet */
   ld.linktype       = WTAP_ENCAP_UNKNOWN;
+  ld.pcap_err       = FALSE;
   ld.from_pipe      = FALSE;
   ld.sync_packets   = 0;
   ld.counts.sctp    = 0;
@@ -1280,9 +1357,16 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
   /* We haven't yet gotten the capture statistics. */
   *stats_known      = FALSE;
 
-  /* Open the network interface to capture from it. */
-  pch = pcap_open_live(cfile.iface, cfile.snap, prefs.capture_prom_mode,
-                       CAP_READ_TIMEOUT, err_str);
+  /* 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';
+  pch = pcap_open_live(cfile.iface,
+                      capture_opts.has_snaplen ? capture_opts.snaplen :
+                                                 WTAP_MAX_PACKET_SIZE,
+                      capture_opts.promisc_mode, CAP_READ_TIMEOUT,
+                      open_err_str);
 
   if (pch == NULL) {
 #ifdef _WIN32
@@ -1305,11 +1389,11 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
        "\n"
        "Note that the driver Ethereal uses for packet capture on Windows\n"
        "doesn't support capturing on PPP/WAN interfaces in Windows NT/2000.\n",
-       err_str);
+       open_err_str);
     goto error;
 #else
     /* try to open cfile.iface as a pipe */
-    pipe_fd = pipe_open_live(cfile.iface, &hdr, &ld, err_str);
+    pipe_fd = pipe_open_live(cfile.iface, &hdr, &ld, open_err_str);
 
     if (pipe_fd == -1) {
       /* Well, we couldn't start the capture.
@@ -1326,7 +1410,7 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
         of libpcap that properly handles HP-UX (libpcap 0.6.x and later
         versions, which properly handle HP-UX, say "can't find /dev/dlpi
         PPA for XXX" rather than "can't find PPA for XXX"). */
-      if (strncmp(err_str, ppamsg, sizeof ppamsg - 1) == 0)
+      if (strncmp(open_err_str, ppamsg, sizeof ppamsg - 1) == 0)
        libpcap_warn =
          "\n\n"
          "You are running Ethereal with a version of the libpcap library\n"
@@ -1343,7 +1427,7 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
       snprintf(errmsg, sizeof errmsg,
          "The capture session could not be initiated (%s).\n"
          "Please check to make sure you have sufficient permissions, and that\n"
-         "you have the proper interface or pipe specified.%s", err_str,
+         "you have the proper interface or pipe specified.%s", open_err_str,
          libpcap_warn);
       goto error;
     }
@@ -1353,7 +1437,7 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
   /* capture filters only work on real interfaces */
   if (cfile.cfilter && !ld.from_pipe) {
     /* A capture filter was specified; set it up. */
-    if (pcap_lookupnet (cfile.iface, &netnum, &netmask, err_str) < 0) {
+    if (pcap_lookupnet(cfile.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
@@ -1381,12 +1465,12 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
 #ifndef _WIN32
   if (ld.from_pipe) {
     pcap_encap = hdr.network;
-    snaplen = hdr.snaplen;
+    file_snaplen = hdr.snaplen;
   } else
 #endif
   {
-    pcap_encap = pcap_datalink(pch);
-    snaplen = pcap_snapshot(pch);
+    pcap_encap = get_pcap_linktype(pch, cfile.iface);
+    file_snaplen = pcap_snapshot(pch);
   }
   ld.linktype = wtap_pcap_encap_to_wtap_encap(pcap_encap);
   if (ld.linktype == WTAP_ENCAP_UNKNOWN) {
@@ -1395,8 +1479,13 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
        " that Ethereal doesn't support (data link type %d).", pcap_encap);
     goto error;
   }
-  ld.pdh = wtap_dump_fdopen(cfile.save_file_fd, WTAP_FILE_PCAP,
-      ld.linktype, snaplen, &err);
+  if (capture_opts.ringbuffer_on) {
+    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,
+      ld.linktype, file_snaplen, &err);
+  }
 
   if (ld.pdh == NULL) {
     /* We couldn't set up to write to the capture file. */
@@ -1429,6 +1518,11 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
     goto error;
   }
 
+  /* Does "open_err_str" contain a non-empty string?  If so, "pcap_open_live()"
+     returned a warning; print it, but keep capturing. */
+  if (open_err_str[0] != '\0')
+    g_warning("%s.", open_err_str);
+
   /* XXX - capture SIGTERM and close the capture, in case we're on a
      Linux 2.0[.x] system and you have to explicitly close the capture
      stream in order to turn promiscuous mode off?  We need to do that
@@ -1516,6 +1610,16 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
    */
   signal(SIGUSR1, stop_capture);
 #endif
+  /* 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); 
+  if (capture_opts.has_autostop_duration)
+    cnd_stop_timeout =
+        cnd_new(CND_CLASS_TIMEOUT,(gint32)capture_opts.autostop_duration);
+
   while (ld.go) {
     while (gtk_events_pending()) gtk_main_iteration();
 
@@ -1577,14 +1681,44 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
         * it.
         */
        inpkts = pcap_dispatch(pch, 1, capture_pcap_cb, (u_char *) &ld);
+       if (inpkts < 0) {
+         ld.pcap_err = TRUE;
+         ld.go = FALSE;
+       }
       } else
        inpkts = 0;
 #else
       inpkts = pcap_dispatch(pch, 1, capture_pcap_cb, (u_char *) &ld);
+      if (inpkts < 0) {
+        ld.pcap_err = TRUE;
+        ld.go = FALSE;
+      }
 #endif
     }
     if (inpkts > 0)
       ld.sync_packets += inpkts;
+    /* check capture stop conditons */
+    if (cnd_stop_timeout != NULL && cnd_eval(cnd_stop_timeout)) {
+      /* The specified capture time has elapsed; stop the capture. */
+      ld.go = FALSE;
+    } else if (cnd_stop_capturesize != NULL && cnd_eval(cnd_stop_capturesize, 
+                  (guint32)wtap_get_bytes_dumped(ld.pdh))){
+      /* Capture file reached its maximum size. */
+      if (capture_opts.ringbuffer_on) {
+        /* Switch to the next ringbuffer file */
+        if (ringbuf_switch_file(&cfile, &ld.pdh, &ld.err)) {
+          /* File switch succeeded: reset the condition */
+          cnd_reset(cnd_stop_capturesize);
+        } else {
+          /* File switch failed: stop here */
+          ld.go = FALSE;
+          continue;
+        }
+      } else {
+        /* no ringbuffer - just stop */
+        ld.go = FALSE;
+      }
+    }
     /* Only update once a second so as not to overload slow displays */
     cur_time = time(NULL);
     if (cur_time > upd_time) {
@@ -1616,6 +1750,26 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
     }
   }
     
+  /* delete stop conditions */
+  if (cnd_stop_capturesize != NULL)
+    cnd_delete(cnd_stop_capturesize);
+  if (cnd_stop_timeout != NULL)
+    cnd_delete(cnd_stop_timeout);
+
+  if (ld.pcap_err) {
+    snprintf(errmsg, sizeof(errmsg), "Error while capturing packets: %s",
+      pcap_geterr(pch));
+    if (capture_child) {
+      /* Tell the parent, so that they can pop up the message;
+         we're going to exit, so if we try to pop it up, either
+         it won't pop up or it'll disappear as soon as we exit. */
+      send_errmsg_to_parent(errmsg);
+    } else {
+     /* Just pop up the message ourselves. */
+     simple_dialog(ESD_TYPE_WARN, NULL, "%s", errmsg);
+    }
+  }
+
   if (ld.err != 0) {
     get_capture_file_io_error(errmsg, sizeof(errmsg), cfile.save_file, ld.err,
                              FALSE);
@@ -1632,9 +1786,18 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
     /* 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. */
-    wtap_dump_close(ld.pdh, &err);
-  } else {
-    if (!wtap_dump_close(ld.pdh, &err)) {
+    if (capture_opts.ringbuffer_on) {
+      ringbuf_wtap_dump_close(&cfile, &err);
+    } else {
+      wtap_dump_close(ld.pdh, &err);
+    }
+   } else {
+    if (capture_opts.ringbuffer_on) {
+      dump_ok = ringbuf_wtap_dump_close(&cfile, &err);
+    } else {
+      dump_ok = wtap_dump_close(ld.pdh, &err);
+    }
+    if (!dump_ok) {
       get_capture_file_io_error(errmsg, sizeof(errmsg), cfile.save_file, err,
                                TRUE);
       if (capture_child) {
@@ -1692,14 +1855,19 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
   return TRUE;
 
 error:
-  /* We can't use the save file, and we have no wtap_dump stream
-     to close in order to close it, so close the FD directly. */
-  close(cfile.save_file_fd);
-
-  /* We couldn't even start the capture, so get rid of the capture
-     file. */
-  unlink(cfile.save_file); /* silently ignore error */
-  g_free(cfile.save_file);
+  if (capture_opts.ringbuffer_on) {
+    /* cleanup ringbuffer */
+    ringbuf_error_cleanup();
+  } else {
+    /* We can't use the save file, and we have no wtap_dump stream
+       to close in order to close it, so close the FD directly. */
+    close(cfile.save_file_fd);
+
+    /* We couldn't even start the capture, so get rid of the capture
+       file. */
+    unlink(cfile.save_file); /* silently ignore error */
+    g_free(cfile.save_file);
+  }
   cfile.save_file = NULL;
   if (capture_child) {
     /* This is the child process for a sync mode capture.
@@ -1824,6 +1992,18 @@ capture_stop(void)
 #endif
 }
 
+void
+kill_capture_child(void)
+{
+  /*
+   * XXX - find some way of signaling the child in Win32.
+   */
+#ifndef _WIN32
+  if (fork_child != -1)
+    kill(fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */
+#endif
+}
+
 static void
 capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
   const u_char *pd) {
@@ -1854,37 +2034,37 @@ capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
      }
   }
 
-  /* Set the initial payload to the packet length, and the initial
-     captured payload to the capture length (other protocols may
-     reduce them if their headers say they're less). */
-  pi.len = phdr->len;
-  pi.captured_len = phdr->caplen;
-    
   switch (ld->linktype) {
     case WTAP_ENCAP_ETHERNET:
-      capture_eth(pd, 0, &ld->counts);
+      capture_eth(pd, 0, phdr->len, &ld->counts);
       break;
     case WTAP_ENCAP_FDDI:
     case WTAP_ENCAP_FDDI_BITSWAPPED:
-      capture_fddi(pd, &ld->counts);
+      capture_fddi(pd, phdr->len, &ld->counts);
+      break;
+    case WTAP_ENCAP_PRISM_HEADER:
+      capture_prism(pd, 0, phdr->len, &ld->counts);
       break;
     case WTAP_ENCAP_TOKEN_RING:
-      capture_tr(pd, 0, &ld->counts);
+      capture_tr(pd, 0, phdr->len, &ld->counts);
       break;
     case WTAP_ENCAP_NULL:
-      capture_null(pd, &ld->counts);
+      capture_null(pd, phdr->len, &ld->counts);
       break;
     case WTAP_ENCAP_PPP:
-      capture_ppp_hdlc(pd, 0, &ld->counts);
+      capture_ppp_hdlc(pd, 0, phdr->len, &ld->counts);
       break;
     case WTAP_ENCAP_RAW_IP:
-      capture_raw(pd, &ld->counts);
+      capture_raw(pd, phdr->len, &ld->counts);
       break;
     case WTAP_ENCAP_SLL:
-      capture_sll(pd, &ld->counts);
+      capture_sll(pd, phdr->len, &ld->counts);
       break;
     case WTAP_ENCAP_LINUX_ATM_CLIP:
-      capture_clip(pd, &ld->counts);
+      capture_clip(pd, phdr->len, &ld->counts);
+      break;
+    case WTAP_ENCAP_LOCALTALK:
+      capture_llap(pd, phdr->len, &ld->counts);
       break;
     /* XXX - FreeBSD may append 4-byte ATM pseudo-header to DLT_ATM_RFC1483,
        with LLC header following; we should implement it at some