Put the IGMP type field value into the PIM tree, as is done for other
[obnox/wireshark/wip.git] / tethereal.c
index 3b7527cb33085c9ca24acedc2639bd29c4cd0ef6..ff6722c75f6a53c9d4425630ac57fb44a6a1b638 100644 (file)
@@ -1,9 +1,9 @@
 /* tethereal.c
  *
- * $Id: tethereal.c,v 1.63 2001/01/29 00:09:38 guy Exp $
+ * $Id: tethereal.c,v 1.86 2001/06/08 08:50:49 guy Exp $
  *
  * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
+ * By Gerald Combs <gerald@ethereal.com>
  * Copyright 1998 Gerald Combs
  *
  * Text-mode variant, by Gilbert Ramirez <gram@xiexie.org>.
@@ -32,6 +32,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <locale.h>
+#include <limits.h>
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #include "resolv.h"
 #include "util.h"
 #include "conversation.h"
+#include "reassemble.h"
 #include "plugins.h"
+#include "register.h"
+
+#ifdef WIN32
+#include "capture-wpcap.h"
+#endif
 
 static guint32 firstsec, firstusec;
 static guint32 prevsec, prevusec;
-static gchar   comp_info_str[256];
+static GString *comp_info_str;
 static gboolean verbose;
 static gboolean print_hex;
+static gboolean line_buffered;
 
 #ifdef HAVE_LIBPCAP
 typedef struct _loop_data {
@@ -123,13 +131,13 @@ typedef struct {
 static int load_cap_file(capture_file *, int);
 static void wtap_dispatch_cb_write(u_char *, const struct wtap_pkthdr *, int,
     union wtap_pseudo_header *, const u_char *);
+static void show_capture_file_io_error(const char *, int, gboolean);
 static void wtap_dispatch_cb_print(u_char *, const struct wtap_pkthdr *, int,
     union wtap_pseudo_header *, const u_char *);
 
 packet_info  pi;
 capture_file cfile;
 FILE        *data_out_file = NULL;
-guint        main_ctx, file_ctx;
 ts_type timestamp_type = RELATIVE;
 #ifdef HAVE_LIBPCAP
 static int promisc_mode = TRUE;
@@ -140,17 +148,17 @@ print_usage(void)
 {
   int i;
 
-  fprintf(stderr, "This is GNU t%s %s, compiled with %s\n", PACKAGE,
-         VERSION, comp_info_str);
+  fprintf(stderr, "This is GNU t%s %s, compiled %s\n", PACKAGE, VERSION,
+       comp_info_str->str);
 #ifdef HAVE_LIBPCAP
-  fprintf(stderr, "t%s [ -vVhlp ] [ -c count ] [ -f <capture filter> ]\n", PACKAGE);
-  fprintf(stderr, "\t[ -F <capture file type> ] [ -i interface ] [ -n ]\n");
-  fprintf(stderr, "\t[ -o <preference setting> ] ... [ -r infile ] [ -R <read filter> ]\n");
-  fprintf(stderr, "\t[ -s snaplen ] [ -t <time stamp format> ] [ -w savefile ] [ -x ]\n");
+  fprintf(stderr, "t%s [ -DvVhlp ] [ -c <count> ] [ -f <capture filter> ]\n", PACKAGE);
+  fprintf(stderr, "\t[ -F <capture file type> ] [ -i <interface> ] [ -n ] [ -N <resolving> ]\n");
+  fprintf(stderr, "\t[ -o <preference setting> ] ... [ -r <infile> ] [ -R <read filter> ]\n");
+  fprintf(stderr, "\t[ -s <snaplen> ] [ -t <time stamp format> ] [ -w <savefile> ] [ -x ]\n");
 #else
-  fprintf(stderr, "t%s [ -vVhl ] [ -F <capture file type> ] [ -n ]\n", PACKAGE);
-  fprintf(stderr, "\t[ -o <preference setting> ] ... [ -r infile ] [ -R <read filter> ]\n");
-  fprintf(stderr, "\t[ -t <time stamp format> ] [ -w savefile ] [ -x ]\n");
+  fprintf(stderr, "t%s [ -vVhl ] [ -F <capture file type> ] [ -n ] [ -N <resolving> ]\n", PACKAGE);
+  fprintf(stderr, "\t[ -o <preference setting> ] ... [ -r <infile> ] [ -R <read filter> ]\n");
+  fprintf(stderr, "\t[ -t <time stamp format> ] [ -w <savefile> ] [ -x ]\n");
 #endif
   fprintf(stderr, "Valid file type arguments to the \"-F\" flag:\n");
   for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
@@ -161,6 +169,31 @@ print_usage(void)
   fprintf(stderr, "\tdefault is libpcap\n");
 }
 
+int
+get_positive_int(const char *string, const char *name)
+{
+  long number;
+  char *p;
+
+  number = strtol(string, &p, 10);
+  if (p == string || *p != '\0') {
+    fprintf(stderr, "tethereal: The specified %s \"%s\" is not a decimal number\n",
+           name, string);
+    exit(1);
+  }
+  if (number < 0) {
+    fprintf(stderr, "tethereal: The specified %s \"%s\" is a negative number\n",
+           name, string);
+    exit(1);
+  }
+  if (number > INT_MAX) {
+    fprintf(stderr, "tethereal: The specified %s \"%s\" is too large (greater than %d)\n",
+           name, string, INT_MAX);
+    exit(1);
+  }
+  return number;
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -169,7 +202,7 @@ main(int argc, char *argv[])
   gboolean             arg_error = FALSE;
 #ifdef HAVE_LIBPCAP
 #ifdef WIN32
-  char pcap_version[] = "0.4a6";
+  char pcap_version[] = WPCAP_STRING;
 #else
   extern char          pcap_version[];
 #endif
@@ -185,21 +218,22 @@ main(int argc, char *argv[])
 #ifdef HAVE_LIBPCAP
   gboolean             capture_filter_specified = FALSE;
   int                  packet_count = 0;
-  GList               *if_list;
+  GList               *if_list, *if_entry;
   gchar                err_str[PCAP_ERRBUF_SIZE];
 #else
   gboolean             capture_option_specified = FALSE;
 #endif
-  int                 out_file_type = WTAP_FILE_PCAP;
+  int                  out_file_type = WTAP_FILE_PCAP;
   gchar               *cf_name = NULL, *rfilter = NULL;
-  dfilter             *rfcode = NULL;
+  dfilter_t           *rfcode = NULL;
   e_prefs             *prefs;
+  char                 badopt;
 
   /* Register all dissectors; we must do this before checking for the
      "-G" flag, as the "-G" flag dumps a list of fields registered
      by the dissectors, and we must do it before we read the preferences,
      in case any dissectors register preferences. */
-  epan_init(PLUGIN_DIR);
+  epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs);
 
   /* Now register the preferences for any non-dissector modules.
      We must do that before we read the preferences as well. */
@@ -227,6 +261,11 @@ main(int argc, char *argv[])
     fprintf(stderr, "Can't open your preferences file \"%s\": %s.\n", pf_path,
         strerror(pf_open_errno));
   }
+
+#ifdef WIN32
+  /* Load Wpcap, if possible */
+  load_wpcap();
+#endif
     
   /* Initialize the capture file struct */
   cfile.plist          = NULL;
@@ -249,54 +288,87 @@ main(int argc, char *argv[])
   col_init(&cfile.cinfo, prefs->num_cols);
 
   /* Assemble the compile-time options */
-  snprintf(comp_info_str, 256,
-#ifdef GTK_MAJOR_VERSION
-    "GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
-    GTK_MICRO_VERSION,
+  comp_info_str = g_string_new("");
+
+  g_string_append(comp_info_str, "with ");
+  g_string_sprintfa(comp_info_str,
+#ifdef GLIB_MAJOR_VERSION
+    "GLib %d.%d.%d", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION,
+    GLIB_MICRO_VERSION);
 #else
-    "GTK+ (version unknown), %s%s, %s%s, %s%s",
+    "GLib (version unknown)");
 #endif
 
 #ifdef HAVE_LIBPCAP
-   "with libpcap ", pcap_version,
+  g_string_append(comp_info_str, ", with libpcap ");
+  g_string_append(comp_info_str, pcap_version);
 #else
-   "without libpcap", "",
+  g_string_append(comp_info_str, ", without libpcap");
 #endif
 
 #ifdef HAVE_LIBZ
+  g_string_append(comp_info_str, ", with libz ");
 #ifdef ZLIB_VERSION
-   "with libz ", ZLIB_VERSION,
+  g_string_append(comp_info_str, ZLIB_VERSION);
 #else /* ZLIB_VERSION */
-   "with libz ", "(version unknown)",
+  g_string_append(comp_info_str, "(version unknown)");
 #endif /* ZLIB_VERSION */
 #else /* HAVE_LIBZ */
-   "without libz", "",
+  g_string_append(comp_info_str, ", without libz");
 #endif /* HAVE_LIBZ */
 
 /* Oh, this is pretty */
 #if defined(HAVE_UCD_SNMP_SNMP_H)
+  g_string_append(comp_info_str, ", with UCD SNMP ");
 #ifdef HAVE_UCD_SNMP_VERSION_H
-   "with UCD SNMP ", VersionInfo
+  g_string_append(comp_info_str, VersionInfo);
 #else /* HAVE_UCD_SNMP_VERSION_H */
-   "with UCD SNMP ", "(version unknown)"
+  g_string_append(comp_info_str, "(version unknown)");
 #endif /* HAVE_UCD_SNMP_VERSION_H */
 #elif defined(HAVE_SNMP_SNMP_H)
+  g_string_append(comp_info_str, ", with CMU SNMP ");
 #ifdef HAVE_SNMP_VERSION_H
-   "with CMU SNMP ", snmp_Version()
+  g_string_append(comp_info_str, snmp_Version());
 #else /* HAVE_SNMP_VERSION_H */
-   "with CMU SNMP ", "(version unknown)"
+  g_string_append(comp_info_str, "(version unknown)");
 #endif /* HAVE_SNMP_VERSION_H */
 #else /* no SNMP */
-   "without SNMP", ""
+  g_string_append(comp_info_str, ", without SNMP");
 #endif
-   );
     
   /* Now get our args */
-  while ((opt = getopt(argc, argv, "c:Df:F:hi:lno:pr:R:s:t:vw:Vx")) != EOF) {
+  while ((opt = getopt(argc, argv, "c:Df:F:hi:lnN:o:pr:R:s:t:vw:Vx")) != EOF) {
     switch (opt) {
       case 'c':        /* Capture xxx packets */
 #ifdef HAVE_LIBPCAP
-        packet_count = atoi(optarg);
+        packet_count = get_positive_int(optarg, "packet count");
+#else
+        capture_option_specified = TRUE;
+        arg_error = TRUE;
+#endif
+        break;
+      case 'D':        /* Print a list of capture devices */
+#ifdef HAVE_LIBPCAP
+        if_list = get_interface_list(&err, err_str);
+        if (if_list == NULL) {
+            switch (err) {
+
+            case CANT_GET_INTERFACE_LIST:
+                fprintf(stderr, "tethereal: Can't get list of interfaces: %s\n",
+                       err_str);
+                break;
+
+            case NO_INTERFACES_FOUND:
+                fprintf(stderr, "tethereal: There are no interfaces on which a capture can be done\n");
+                break;
+            }
+            exit(2);
+        }
+        for (if_entry = g_list_first(if_list); if_entry != NULL;
+               if_entry = g_list_next(if_entry))
+          printf("%s\n", (char *)if_entry->data);
+        free_interface_list(if_list);
+        exit(0);
 #else
         capture_option_specified = TRUE;
         arg_error = TRUE;
@@ -331,12 +403,33 @@ main(int argc, char *argv[])
         arg_error = TRUE;
 #endif
         break;
-      case 'l':        /* Line-buffer standard output */
-       setvbuf(stdout, NULL, _IOLBF, 0);
+      case 'l':        /* "Line-buffer" standard output */
+       /* This isn't line-buffering, strictly speaking, it's just
+          flushing the standard output after the information for
+          each packet is printed; however, that should be good
+          enough for all the purposes to which "-l" is put.
+
+          See the comment in "wtap_dispatch_cb_print()" for an
+          explanation of why we do that, and why we don't just
+          use "setvbuf()" to make the standard output line-buffered
+          (short version: in Windows, "line-buffered" is the same
+          as "fully-buffered", and the output buffer is only flushed
+          when it fills up). */
+       line_buffered = TRUE;
        break;
       case 'n':        /* No name resolution */
-       g_resolving_actif = 0;
-       break;
+        prefs->name_resolve = PREFS_RESOLV_NONE;
+        break;
+      case 'N':        /* Select what types of addresses/port #s to resolve */
+        if (prefs->name_resolve == PREFS_RESOLV_ALL)
+          prefs->name_resolve = PREFS_RESOLV_NONE;
+        badopt = string_to_name_resolve(optarg, &prefs->name_resolve);
+        if (badopt != '\0') {
+          fprintf(stderr, "tethereal: -N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'\n",
+                       badopt);
+          exit(1);
+        }
+        break;
       case 'o':        /* Override preference from command line */
         switch (prefs_set_pref(optarg)) {
 
@@ -368,7 +461,7 @@ main(int argc, char *argv[])
         break;
       case 's':        /* Set the snapshot (capture) length */
 #ifdef HAVE_LIBPCAP
-        cfile.snap = atoi(optarg);
+        cfile.snap = get_positive_int(optarg, "snapshot length");
 #else
         capture_option_specified = TRUE;
         arg_error = TRUE;
@@ -392,7 +485,7 @@ main(int argc, char *argv[])
         }
         break;
       case 'v':        /* Show version and exit */
-        printf("t%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
+        printf("t%s %s, %s\n", PACKAGE, VERSION, comp_info_str->str);
         exit(0);
         break;
       case 'w':        /* Write to capture file xxx */
@@ -470,7 +563,7 @@ main(int argc, char *argv[])
     cfile.snap = MIN_PACKET_SIZE;
   
   if (rfilter != NULL) {
-    if (dfilter_compile(rfilter, &rfcode) != 0) {
+    if (!dfilter_compile(rfilter, &rfcode)) {
       fprintf(stderr, "tethereal: %s\n", dfilter_error_msg);
       epan_cleanup();
       exit(2);
@@ -493,6 +586,14 @@ main(int argc, char *argv[])
     /* No capture file specified, so we're supposed to do a live capture;
        do we have support for live captures? */
 #ifdef HAVE_LIBPCAP
+
+#ifdef _WIN32
+    if (!has_wpcap) {
+       fprintf(stderr, "tethereal: Could not load wpcap.dll.\n");
+       exit(2);
+    }
+#endif
+
     /* Yes; did the user specify an interface to use? */
     if (cfile.iface == NULL) {
         /* No - pick the first one from the list of interfaces. */
@@ -524,7 +625,7 @@ main(int argc, char *argv[])
 
   epan_cleanup();
 
-  exit(0);
+  return 0;
 }
 
 #ifdef HAVE_LIBPCAP
@@ -543,6 +644,7 @@ capture(int packet_count, int out_file_type)
   static const char ppamsg[] = "can't find PPA for ";
   char       *libpcap_warn;
 #endif
+  struct pcap_stat stats;
 
   /* Initialize the table of conversations. */
   epan_conversation_init();
@@ -550,6 +652,12 @@ capture(int packet_count, int out_file_type)
   /* Initialize protocol-specific variables */
   init_all_protocols();
 
+  /* Initialize the common data structures for fragment reassembly.
+     Must be done *after* "init_all_protocols()", as "init_all_protocols()"
+     may free up space for fragments, which it finds by using the
+     data structures that "reassemble_init()" frees. */
+  reassemble_init();
+
   ld.linktype       = WTAP_ENCAP_UNKNOWN;
   ld.pdh            = NULL;
 
@@ -574,9 +682,9 @@ capture(int packet_count, int out_file_type)
 #else
       /* If we got a "can't find PPA for XXX" message, warn the user (who
          is running Ethereal on HP-UX) that they don't have a version
-        of libpcap patched to properly handle HP-UX (the patched version
-        says "can't find /dev/dlpi PPA for XXX" rather than "can't find
-        PPA for XXX"). */
+        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)
        libpcap_warn =
          "\n\n"
@@ -584,14 +692,11 @@ capture(int packet_count, int out_file_type)
          "that doesn't handle HP-UX network devices well; this means that\n"
          "Tethereal may not be able to capture packets.\n"
          "\n"
-         "To fix this, you will need to download the source to Tethereal\n"
-         "from www.ethereal.com if you have not already done so, read\n"
-         "the instructions in the \"README.hpux\" file in the source\n"
-         "distribution, download the source to libpcap if you have not\n"
-         "already done so, patch libpcap as per the instructions, rebuild\n"
-         "and install libpcap, and then build Tethereal (if you have already\n"
-         "built Tethereal from source, do a \"make distclean\" and re-run\n"
-         "configure before building).";
+         "To fix this, you should install libpcap 0.6.2, or a later version\n"
+         "of libpcap, rather than libpcap 0.4 or 0.5.x.  It is available in\n"
+         "packaged binary form from the Software Porting And Archive Centre\n"
+         "for HP-UX; the Centre is at http://hpux.connect.org.uk/ - the page\n"
+         "at the URL lists a number of mirror sites.";
       else
        libpcap_warn = "";
     snprintf(errmsg, sizeof errmsg,
@@ -656,16 +761,36 @@ capture(int packet_count, int out_file_type)
 #endif
 
   /* Let the user know what interface was chosen. */
-  printf("Capturing on %s\n", cfile.iface);
+  fprintf(stderr, "Capturing on %s\n", cfile.iface);
+  fflush(stderr);
 
   inpkts = pcap_loop(ld.pch, packet_count, capture_pcap_cb, (u_char *) &ld);
-  pcap_close(ld.pch);
 
-  /* Send a newline if we were printing packet counts to stdout */
   if (cfile.save_file != NULL) {
-    printf("\n");
+    /* We're saving to a file, which means we're printing packet counts
+       to the standard output.  Send a newline so that we move to the
+       line after the packet count. */
+    fprintf(stderr, "\n");
   }
 
+  /* If we got an error while capturing, report it. */
+  if (inpkts < 0) {
+    fprintf(stderr, "tethereal: Error while capturing packets: %s\n",
+       pcap_geterr(ld.pch));
+  }
+
+  /* Get the capture statistics, and, if any packets were dropped, report
+     that. */
+  if (pcap_stats(ld.pch, &stats) >= 0) {
+    if (stats.ps_drop != 0) {
+      fprintf(stderr, "%u packets dropped\n", stats.ps_drop);
+    }
+  } else {
+    fprintf(stderr, "tethereal: Can't get packet-drop statistics: %s\n",
+       pcap_geterr(ld.pch));
+  }
+  pcap_close(ld.pch);
+
   return TRUE;
 
 error:
@@ -696,7 +821,7 @@ capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
   args.pdh = ld->pdh;
   if (ld->pdh) {
     wtap_dispatch_cb_write((u_char *)&args, &whdr, 0, NULL, pd);
-    printf("\r%u ", cfile.count);
+    fprintf(stderr, "\r%u ", cfile.count);
     fflush(stdout);
   } else {
     wtap_dispatch_cb_print((u_char *)&args, &whdr, 0, NULL, pd);
@@ -708,11 +833,14 @@ capture_cleanup(int signum)
 {
   int err;
 
-  printf("\n");
+  fprintf(stderr, "\n");
   pcap_close(ld.pch);
-  if (ld.pdh != NULL)
-    wtap_dump_close(ld.pdh, &err);
-  /* XXX - complain if this fails */
+  if (ld.pdh != NULL) {
+    if (!wtap_dump_close(ld.pdh, &err)) {
+      show_capture_file_io_error(cfile.save_file, err, TRUE);
+      exit(2);
+    }
+  }
   exit(0);
 }
 #endif /* HAVE_LIBPCAP */
@@ -790,28 +918,32 @@ load_cap_file(capture_file *cf, int out_file_type)
 
     case WTAP_ERR_UNSUPPORTED_ENCAP:
       fprintf(stderr,
-"tethereal: The capture file is for a network type that Tethereal doesn't support.\n");
+"tethereal: \"%s\" is a capture file is for a network type that Tethereal doesn't support.\n",
+       cf->filename);
       break;
 
     case WTAP_ERR_CANT_READ:
       fprintf(stderr,
-"tethereal: An attempt to read from the file failed for some unknown reason.\n");
+"tethereal: An attempt to read from \"%s\" failed for some unknown reason.\n",
+       cf->filename);
       break;
 
     case WTAP_ERR_SHORT_READ:
       fprintf(stderr,
-"tethereal: The capture file appears to have been cut short in the middle of a packet.\n");
+"tethereal: \"%s\" appears to have been cut short in the middle of a packet.\n",
+       cf->filename);
       break;
 
     case WTAP_ERR_BAD_RECORD:
       fprintf(stderr,
-"tethereal: The capture file appears to be damaged or corrupt.\n");
+"tethereal: \"%s\" appears to be damaged or corrupt.\n",
+       cf->filename);
       break;
 
     default:
       fprintf(stderr,
-"tethereal: An error occurred while reading the capture file: %s.\n",
-       wtap_strerror(err));
+"tethereal: An error occurred while reading \"%s\": %s.\n",
+       cf->filename, wtap_strerror(err));
       break;
     }
   }
@@ -833,6 +965,7 @@ fill_in_fdata(frame_data *fdata, capture_file *cf,
   fdata->next = NULL;
   fdata->prev = NULL;
   fdata->pfd = NULL;
+  fdata->data_src = NULL;
   fdata->num = cf->count;
   fdata->pkt_len = phdr->len;
   fdata->cap_len = phdr->caplen;
@@ -890,6 +1023,16 @@ fill_in_fdata(frame_data *fdata, capture_file *cf,
   }
 }
 
+/* Free up all data attached to a "frame_data" structure. */
+static void
+clear_fdata(frame_data *fdata)
+{
+  if (fdata->pfd)
+    g_slist_free(fdata->pfd);
+  if (fdata->data_src)
+    g_slist_free(fdata->data_src);
+}
+
 static void
 wtap_dispatch_cb_write(u_char *user, const struct wtap_pkthdr *phdr, int offset,
   union wtap_pseudo_header *pseudo_header, const u_char *buf)
@@ -908,20 +1051,83 @@ wtap_dispatch_cb_write(u_char *user, const struct wtap_pkthdr *phdr, int offset,
     fill_in_fdata(&fdata, cf, phdr, pseudo_header, offset);
     protocol_tree = proto_tree_create_root();
     edt = epan_dissect_new(pseudo_header, buf, &fdata, protocol_tree);
-    passed = dfilter_apply(cf->rfcode, protocol_tree, buf, fdata.cap_len);
+    passed = dfilter_apply_edt(cf->rfcode, edt);
   } else {
     protocol_tree = NULL;
     passed = TRUE;
     edt = NULL;
   }
   if (passed) {
-    /* XXX - do something if this fails */
-    wtap_dump(pdh, phdr, pseudo_header, buf, &err);
+    if (!wtap_dump(pdh, phdr, pseudo_header, buf, &err)) {
+#ifdef HAVE_LIBPCAP
+      if (ld.pch != NULL) {
+       /* We're capturing packets, so we're printing a count of packets
+          captured; move to the line after the count. */
+        fprintf(stderr, "\n");
+      }
+#endif
+      show_capture_file_io_error(cf->save_file, err, FALSE);
+#ifdef HAVE_LIBPCAP
+      if (ld.pch != NULL)
+        pcap_close(ld.pch);
+#endif
+      wtap_dump_close(pdh, &err);
+      exit(2);
+    }
   }
   if (protocol_tree != NULL)
     proto_tree_free(protocol_tree);
   if (edt != NULL)
     epan_dissect_free(edt);
+  if (cf->rfcode)
+    clear_fdata(&fdata);
+}
+
+static void
+show_capture_file_io_error(const char *fname, int err, gboolean is_close)
+{
+  switch (err) {
+
+  case ENOSPC:
+    fprintf(stderr,
+"tethereal: Not all the packets could be written to \"%s\" because there is "
+"no space left on the file system.\n",
+       fname);
+    break;
+
+#ifdef EDQUOT
+  case EDQUOT:
+    fprintf(stderr,
+"tethereal: Not all the packets could be written to \"%s\" because you are "
+"too close to, or over your disk quota.\n",
+       fname);
+  break;
+#endif
+
+  case WTAP_ERR_CANT_CLOSE:
+    fprintf(stderr,
+"tethereal: \"%s\" couldn't be closed for some unknown reason.\n",
+       fname);
+    break;
+
+  case WTAP_ERR_SHORT_WRITE:
+    fprintf(stderr,
+"tethereal: Not all the packets could be written to \"%s\".\n",
+       fname);
+    break;
+
+  default:
+    if (is_close) {
+      fprintf(stderr,
+"tethereal: \"%s\" could not be closed: %s.\n",
+       fname, wtap_strerror(err));
+    } else {
+      fprintf(stderr,
+"tethereal: An error occurred while writing to \"%s\": %s.\n",
+       fname, wtap_strerror(err));
+    }
+    break;
+  }
 }
 
 static void
@@ -952,7 +1158,7 @@ wtap_dispatch_cb_print(u_char *user, const struct wtap_pkthdr *phdr, int offset,
     protocol_tree = NULL;
   edt = epan_dissect_new(pseudo_header, buf, &fdata, protocol_tree);
   if (cf->rfcode)
-    passed = dfilter_apply(cf->rfcode, protocol_tree, buf, fdata.cap_len);
+    passed = dfilter_apply_edt(cf->rfcode, edt);
   if (passed) {
     /* The packet passed the read filter. */
     if (verbose) {
@@ -963,7 +1169,7 @@ wtap_dispatch_cb_print(u_char *user, const struct wtap_pkthdr *phdr, int offset,
       print_args.print_hex = print_hex;
       print_args.expand_all = TRUE;
       proto_tree_print(FALSE, &print_args, (GNode *)protocol_tree,
-                       buf, &fdata, stdout);
+                       &fdata, stdout);
       if (!print_hex) {
         /* "print_hex_data()" will put out a leading blank line, as well
           as a trailing one; print one here, to separate the packets,
@@ -1154,17 +1360,41 @@ wtap_dispatch_cb_print(u_char *user, const struct wtap_pkthdr *phdr, int offset,
       putchar('\n');
     }
     if (print_hex) {
-      print_hex_data(stdout, print_args.format, buf,
-                       fdata.cap_len, fdata.flags.encoding);
+      print_hex_data(stdout, print_args.format, &fdata);
       putchar('\n');
     }
     fdata.cinfo = NULL;
   }
+
+  /* The ANSI C standard does not appear to *require* that a line-buffered
+     stream be flushed to the host environment whenever a newline is
+     written, it just says that, on such a stream, characters "are
+     intended to be transmitted to or from the host environment as a
+     block when a new-line character is encountered".
+
+     The Visual C++ 6.0 C implementation doesn't do what is intended;
+     even if you set a stream to be line-buffered, it still doesn't
+     flush the buffer at the end of every line.
+
+     So, if the "-l" flag was specified, we flush the standard output
+     at the end of a packet.  This will do the right thing if we're
+     printing packet summary lines, and, as we print the entire protocol
+     tree for a single packet without waiting for anything to happen,
+     it should be as good as line-buffered mode if we're printing
+     protocol trees.  (The whole reason for the "-l" flag in either
+     tcpdump or Tethereal is to allow the output of a live capture to
+     be piped to a program or script and to have that script see the
+     information for the packet as soon as it's printed, rather than
+     having to wait until a standard I/O buffer fills up. */
+  if (line_buffered)
+    fflush(stdout);
   if (protocol_tree != NULL)
     proto_tree_free(protocol_tree);
 
   epan_dissect_free(edt);
 
+  clear_fdata(&fdata);
+
   proto_tree_is_visible = FALSE;
 }
 
@@ -1278,6 +1508,12 @@ open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
   /* Initialize protocol-specific variables */
   init_all_protocols();
 
+  /* Initialize the common data structures for fragment reassembly.
+     Must be done *after* "init_all_protocols()", as "init_all_protocols()"
+     may free up space for fragments, which it finds by using the
+     data structures that "reassemble_init()" frees. */
+  reassemble_init();
+
   cf->wth = wth;
   cf->filed = fd;
   cf->f_len = cf_stat.st_size;
@@ -1295,6 +1531,7 @@ open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
 
   cf->cd_t      = wtap_file_type(cf->wth);
   cf->count     = 0;
+  cf->drops_known = FALSE;
   cf->drops     = 0;
   cf->esec      = 0;
   cf->eusec     = 0;