Avoid undefined behavior in overflow check
[metze/wireshark/wip.git] / wiretap / wtap.c
index dcc04716e5336ecd13296eed78450bd7190dc6a7..3dfb42629796aacbe51fa6b53896ebbf5f496e1b 100644 (file)
@@ -1,6 +1,4 @@
 /* wtap.c
- *
- * $Id$
  *
  * Wiretap Library
  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
 #include <sys/types.h>
 #endif
 
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#ifdef HAVE_LIBZ
-#include <zlib.h>
-#endif
-
 #include "wtap-int.h"
 
 #include "file_wrappers.h"
 #include <wsutil/file_util.h>
-#include "buffer.h"
+#include <wsutil/buffer.h>
+#include <wsutil/ws_diag_control.h>
+
+#ifdef HAVE_PLUGINS
+
+#include <wsutil/plugins.h>
+
+/*
+ * List of wiretap plugins.
+ */
+typedef struct {
+       void (*register_wtap_module)(void);  /* routine to call to register a wiretap module */
+} wtap_plugin;
+
+static GSList *wtap_plugins = NULL;
+
+/*
+ * Callback for each plugin found.
+ */
+static gboolean
+check_for_wtap_plugin(GModule *handle)
+{
+       gpointer gp;
+       wtap_plugin *plugin;
+
+       /*
+        * Do we have a register_wtap_module routine?
+        */
+       if (!g_module_symbol(handle, "register_wtap_module", &gp)) {
+               /* No, so this isn't a wiretap module plugin. */
+               return FALSE;
+       }
+
+       /*
+        * Yes - this plugin includes one or more wiretap modules.
+        * Add this one to the list of wiretap module plugins.
+        */
+       plugin = (wtap_plugin *)g_malloc(sizeof (wtap_plugin));
+DIAG_OFF(pedantic)
+       plugin->register_wtap_module = (void (*)(void))gp;
+DIAG_ON(pedantic)
+       wtap_plugins = g_slist_append(wtap_plugins, plugin);
+       return TRUE;
+}
+
+void
+wtap_register_plugin_types(void)
+{
+       add_plugin_type("libwiretap", check_for_wtap_plugin);
+}
+
+static void
+register_wtap_module_plugin(gpointer data, gpointer user_data _U_)
+{
+       wtap_plugin *plugin = (wtap_plugin *)data;
+
+       (plugin->register_wtap_module)();
+}
+
+/*
+ * For all wiretap module plugins, call their register routines.
+ */
+void
+register_all_wiretap_modules(void)
+{
+       g_slist_foreach(wtap_plugins, register_wtap_module_plugin, NULL);
+}
+#endif /* HAVE_PLUGINS */
 
 /*
  * Return the size of the file, as reported by the OS.
@@ -71,9 +128,9 @@ wtap_fstat(wtap *wth, ws_statb64 *statb, int *err)
 }
 
 int
-wtap_file_type(wtap *wth)
+wtap_file_type_subtype(wtap *wth)
 {
-       return wth->file_type;
+       return wth->file_type_subtype;
 }
 
 gboolean
@@ -95,30 +152,87 @@ wtap_file_encap(wtap *wth)
 }
 
 int
-wtap_file_tsprecision(wtap *wth)
+wtap_file_tsprec(wtap *wth)
+{
+       return wth->file_tsprec;
+}
+
+const gchar *
+wtap_file_get_shb_comment(wtap *wth)
+{
+       return wth ? wth->shb_hdr.opt_comment : NULL;
+}
+
+const wtapng_section_t *
+wtap_file_get_shb(wtap *wth)
 {
-       return wth->tsprecision;
+       return wth ? &(wth->shb_hdr) : NULL;
 }
 
 wtapng_section_t *
-wtap_file_get_shb_info(wtap *wth)
+wtap_file_get_shb_for_new_file(wtap *wth)
 {
-       wtapng_section_t                *shb_hdr;
+       wtapng_section_t *shb_hdr;
 
-       if(wth == NULL)
-               return NULL;
-       shb_hdr = g_new(wtapng_section_t,1);
-       shb_hdr->section_length = wth->shb_hdr.section_length;
-       /* options */
-       shb_hdr->opt_comment   =        wth->shb_hdr.opt_comment;       /* NULL if not available */
-       shb_hdr->shb_hardware  =        wth->shb_hdr.shb_hardware;      /* NULL if not available, UTF-8 string containing the description of the hardware used to create this section. */
-       shb_hdr->shb_os        =        wth->shb_hdr.shb_os;            /* NULL if not available, UTF-8 string containing the name of the operating system used to create this section. */
-       shb_hdr->shb_user_appl =        wth->shb_hdr.shb_user_appl;     /* NULL if not available, UTF-8 string containing the name of the application used to create this section. */
+       if (wth == NULL)
+           return NULL;
 
+       shb_hdr = g_new0(wtapng_section_t,1);
+
+       shb_hdr->section_length = -1;
+       /* options */
+       shb_hdr->opt_comment = g_strdup(wth->shb_hdr.opt_comment);
+       /* the rest of the options remain NULL */
 
        return shb_hdr;
 }
 
+const gchar*
+wtap_get_nrb_comment(wtap *wth)
+{
+       g_assert(wth);
+
+       if (wth == NULL)
+               return NULL;
+
+       return wth->nrb_hdr ? wth->nrb_hdr->opt_comment : NULL;
+}
+
+void
+wtap_write_nrb_comment(wtap *wth, gchar *comment)
+{
+       g_assert(wth);
+
+       if (wth == NULL)
+               return;
+
+       if (wth->nrb_hdr == NULL) {
+               wth->nrb_hdr = g_new0(wtapng_name_res_t,1);
+       } else {
+               g_free(wth->nrb_hdr->opt_comment);
+       }
+
+       /*
+        * I'd prefer this function duplicate the passed-in comment,
+        * but wtap_write_shb_comment() assumes the caller duplicated
+        * it so we'll stick with that.
+        */
+       wth->nrb_hdr->opt_comment = comment;
+}
+
+void
+wtap_free_shb(wtapng_section_t *shb_hdr)
+{
+       if (shb_hdr == NULL)
+           return;
+
+       g_free(shb_hdr->opt_comment);
+       g_free(shb_hdr->shb_hardware);
+       g_free(shb_hdr->shb_os);
+       g_free(shb_hdr->shb_user_appl);
+       g_free(shb_hdr);
+}
+
 void
 wtap_write_shb_comment(wtap *wth, gchar *comment)
 {
@@ -134,12 +248,171 @@ wtap_file_get_idb_info(wtap *wth)
 
        idb_info = g_new(wtapng_iface_descriptions_t,1);
 
-       idb_info->number_of_interfaces  = wth->number_of_interfaces;
        idb_info->interface_data        = wth->interface_data;
 
        return idb_info;
 }
 
+static void
+wtap_free_isb_members(wtapng_if_stats_t *isb)
+{
+       if (isb) {
+               g_free(isb->opt_comment);
+       }
+}
+
+static void
+wtap_free_idb_members(wtapng_if_descr_t* idb)
+{
+       if (idb) {
+               g_free(idb->opt_comment);
+               g_free(idb->if_os);
+               g_free(idb->if_name);
+               g_free(idb->if_description);
+               g_free(idb->if_filter_str);
+               g_free(idb->if_filter_bpf_bytes);
+               if (idb->interface_statistics) {
+                       wtapng_if_stats_t *isb;
+                       guint i;
+                       for (i = 0; i < idb->interface_statistics->len; i++) {
+                               isb = &g_array_index(idb->interface_statistics, wtapng_if_stats_t, i);
+                               wtap_free_isb_members(isb);
+                       }
+                       g_array_free(idb->interface_statistics, TRUE);
+               }
+       }
+}
+
+void
+wtap_free_idb_info(wtapng_iface_descriptions_t *idb_info)
+{
+       if (idb_info == NULL)
+           return;
+
+       if (idb_info->interface_data) {
+               guint i;
+               for (i = 0; i < idb_info->interface_data->len; i++) {
+                       wtapng_if_descr_t* idb = &g_array_index(idb_info->interface_data, wtapng_if_descr_t, i);
+                       wtap_free_idb_members(idb);
+               }
+               g_array_free(idb_info->interface_data, TRUE);
+       }
+
+       g_free(idb_info);
+}
+
+gchar *
+wtap_get_debug_if_descr(const wtapng_if_descr_t *if_descr,
+                        const int indent,
+                        const char* line_end)
+{
+       GString *info = g_string_new("");
+
+       g_assert(if_descr);
+
+       g_string_printf(info,
+                       "%*cName = %s%s", indent, ' ',
+                       if_descr->if_name ? if_descr->if_name : "UNKNOWN",
+                       line_end);
+
+       g_string_append_printf(info,
+                       "%*cDescription = %s%s", indent, ' ',
+                       if_descr->if_description ? if_descr->if_description : "NONE",
+                       line_end);
+
+       g_string_append_printf(info,
+                       "%*cEncapsulation = %s (%d/%u - %s)%s", indent, ' ',
+                       wtap_encap_string(if_descr->wtap_encap),
+                       if_descr->wtap_encap,
+                       if_descr->link_type,
+                       wtap_encap_short_string(if_descr->wtap_encap),
+                       line_end);
+
+       g_string_append_printf(info,
+                       "%*cSpeed = %" G_GINT64_MODIFIER "u%s", indent, ' ',
+                       if_descr->if_speed,
+                       line_end);
+
+       g_string_append_printf(info,
+                       "%*cCapture length = %u%s", indent, ' ',
+                       if_descr->snap_len,
+                       line_end);
+
+       g_string_append_printf(info,
+                       "%*cFCS length = %d%s", indent, ' ',
+                       if_descr->if_fcslen,
+                       line_end);
+
+       g_string_append_printf(info,
+                       "%*cTime precision = %s (%d)%s", indent, ' ',
+                       wtap_tsprec_string(if_descr->tsprecision),
+                       if_descr->tsprecision,
+                       line_end);
+
+       g_string_append_printf(info,
+                       "%*cTime ticks per second = %" G_GINT64_MODIFIER "u%s", indent, ' ',
+                       if_descr->time_units_per_second,
+                       line_end);
+
+       g_string_append_printf(info,
+                       "%*cTime resolution = 0x%.2x%s", indent, ' ',
+                       if_descr->if_tsresol,
+                       line_end);
+
+       g_string_append_printf(info,
+                       "%*cFilter string = %s%s", indent, ' ',
+                       if_descr->if_filter_str ? if_descr->if_filter_str : "NONE",
+                       line_end);
+
+       g_string_append_printf(info,
+                       "%*cOperating system = %s%s", indent, ' ',
+                       if_descr->if_os ? if_descr->if_os : "UNKNOWN",
+                       line_end);
+
+       g_string_append_printf(info,
+                       "%*cComment = %s%s", indent, ' ',
+                       if_descr->opt_comment ? if_descr->opt_comment : "NONE",
+                       line_end);
+
+       g_string_append_printf(info,
+                       "%*cBPF filter length = %u%s", indent, ' ',
+                       if_descr->bpf_filter_len,
+                       line_end);
+
+       g_string_append_printf(info,
+                       "%*cNumber of stat entries = %u%s", indent, ' ',
+                       if_descr->num_stat_entries,
+                       line_end);
+
+       return g_string_free(info, FALSE);
+}
+
+wtapng_name_res_t *
+wtap_file_get_nrb_for_new_file(wtap *wth)
+{
+       wtapng_name_res_t *nrb_hdr;
+
+       if (wth == NULL || wth->nrb_hdr == NULL)
+           return NULL;
+
+       nrb_hdr = g_new0(wtapng_name_res_t,1);
+
+       nrb_hdr->opt_comment = g_strdup(wth->nrb_hdr->opt_comment);
+
+       return nrb_hdr;
+}
+
+void
+wtap_free_nrb(wtapng_name_res_t *nrb_hdr)
+{
+       if (nrb_hdr == NULL)
+           return;
+
+       g_free(nrb_hdr->opt_comment);
+       g_free(nrb_hdr);
+}
+
+
 /* Table of the encapsulation types we know about. */
 struct encap_type_info {
        const char *name;
@@ -193,7 +466,7 @@ static struct encap_type_info encap_table_base[] = {
        { "ATM PDUs - untruncated", "atm-pdus-untruncated" },
 
        /* WTAP_ENCAP_NULL */
-       { "NULL", "null" },
+       { "NULL/Loopback", "null" },
 
        /* WTAP_ENCAP_ASCEND */
        { "Lucent/Ascend access equipment", "ascend" },
@@ -546,7 +819,7 @@ static struct encap_type_info encap_table_base[] = {
        /* WTAP_ENCAP_DVBCI */
        { "DVB-CI (Common Interface)", "dvbci"},
 
-       /* WTAP_ENCAP_MUX27010 */
+       /* WTAP_ENCAP_MUX27010 */
        { "MUX27010", "mux27010"},
 
        /* WTAP_ENCAP_MIME */
@@ -578,12 +851,9 @@ static struct encap_type_info encap_table_base[] = {
 
        /* WTAP_ENCAP_BACNET_MS_TP_WITH_PHDR */
        { "BACnet MS/TP with Directional Info", "bacnet-ms-tp-with-direction" },
-       /* WTAP_ENCAP_IXVERIWAVE */
-       { "IxVeriWave header and stats block", "ixveriwave" },
 
-       /* WTAP_ENCAP_IEEE_802_11_AIROPEEK */
-       { "IEEE 802.11 plus AiroPeek radio header", "ieee-802-11-airopeek" },
+       /* WTAP_ENCAP_IXVERIWAVE */
+       { "IxVeriWave header and stats block", "ixveriwave" },
 
        /* WTAP_ENCAP_SDH */
        { "SDH", "sdh" },
@@ -599,12 +869,105 @@ static struct encap_type_info encap_table_base[] = {
 
        /* WTAP_ENCAP_SCTP */
        { "SCTP", "sctp" },
+
+       /* WTAP_ENCAP_INFINIBAND */
+       { "InfiniBand", "infiniband" },
+
+       /* WTAP_ENCAP_JUNIPER_SVCS */
+       { "Juniper Services", "juniper-svcs" },
+
+       /* WTAP_ENCAP_USBPCAP */
+       { "USB packets with USBPcap header", "usb-usbpcap" },
+
+       /* WTAP_ENCAP_RTAC_SERIAL */
+       { "RTAC serial-line", "rtac-serial" },
+
+       /* WTAP_ENCAP_BLUETOOTH_LE_LL */
+       { "Bluetooth Low Energy Link Layer", "bluetooth-le-ll" },
+
+       /* WTAP_ENCAP_WIRESHARK_UPPER_PDU */
+       { "Wireshark Upper PDU export", "wireshark-upper-pdu" },
+
+       /* WTAP_ENCAP_STANAG_4607 */
+       { "STANAG 4607", "s4607" },
+
+       /* WTAP_ENCAP_STANAG_5066_D_PDU */
+       { "STANAG 5066 Data Transfer Sublayer PDUs(D_PDU)", "s5066-dpdu"},
+
+       /* WTAP_ENCAP_NETLINK */
+       { "Linux Netlink", "netlink" },
+
+       /* WTAP_ENCAP_BLUETOOTH_LINUX_MONITOR */
+       { "Bluetooth Linux Monitor", "bluetooth-linux-monitor" },
+
+       /* WTAP_ENCAP_BLUETOOTH_BREDR_BB */
+       { "Bluetooth BR/EDR Baseband RF", "bluetooth-bredr-bb-rf" },
+
+       /* WTAP_ENCAP_BLUETOOTH_LE_LL_WITH_PHDR */
+       { "Bluetooth Low Energy Link Layer RF", "bluetooth-le-ll-rf" },
+
+       /* WTAP_ENCAP_NSTRACE_3_0 */
+       { "NetScaler Encapsulation 3.0 of Ethernet", "nstrace30" },
+
+       /* WTAP_ENCAP_LOGCAT */
+       { "Android Logcat Binary format", "logcat" },
+
+       /* WTAP_ENCAP_LOGCAT_BRIEF */
+       { "Android Logcat Brief text format", "logcat_brief" },
+
+       /* WTAP_ENCAP_LOGCAT_PROCESS */
+       { "Android Logcat Process text format", "logcat_process" },
+
+       /* WTAP_ENCAP_LOGCAT_TAG */
+       { "Android Logcat Tag text format", "logcat_tag" },
+
+       /* WTAP_ENCAP_LOGCAT_THREAD */
+       { "Android Logcat Thread text format", "logcat_thread" },
+
+       /* WTAP_ENCAP_LOGCAT_TIME */
+       { "Android Logcat Time text format", "logcat_time" },
+
+       /* WTAP_ENCAP_LOGCAT_THREADTIME */
+       { "Android Logcat Threadtime text format", "logcat_threadtime" },
+
+       /* WTAP_ENCAP_LOGCAT_LONG */
+       { "Android Logcat Long text format", "logcat_long" },
+
+       /* WTAP_ENCAP_PKTAP */
+       { "Apple PKTAP", "pktap" },
+
+       /* WTAP_ENCAP_EPON */
+       { "Ethernet Passive Optical Network", "epon" },
+
+       /* WTAP_ENCAP_IPMI_TRACE */
+       { "IPMI Trace Data Collection", "ipmi-trace" },
+
+       /* WTAP_ENCAP_LOOP */
+       { "OpenBSD loopback", "loop" },
+
+       /* WTAP_ENCAP_JSON */
+       { "JavaScript Object Notation", "json" },
+
+       /* WTAP_ENCAP_NSTRACE_3_5 */
+       { "NetScaler Encapsulation 3.5 of Ethernet", "nstrace35" },
+
+       /* WTAP_ENCAP_ISO14443 */
+       { "ISO 14443 contactless smartcard standards", "iso14443" },
+
+       /* WTAP_ENCAP_GFP_T */
+       { "ITU-T G.7041/Y.1303 Generic Framing Procedure Transparent mode", "gfp-t" },
+
+       /* WTAP_ENCAP_GFP_F */
+       { "ITU-T G.7041/Y.1303 Generic Framing Procedure Frame-mapped mode", "gfp-f" }
+
 };
 
 WS_DLL_LOCAL
 gint wtap_num_encap_types = sizeof(encap_table_base) / sizeof(struct encap_type_info);
 static GArray* encap_table_arr = NULL;
-static const struct encap_type_info* encap_table = NULL;
+
+#define encap_table_entry(encap)       \
+       g_array_index(encap_table_arr, struct encap_type_info, encap)
 
 static void wtap_init_encap_types(void) {
 
@@ -613,8 +976,6 @@ static void wtap_init_encap_types(void) {
        encap_table_arr = g_array_new(FALSE,TRUE,sizeof(struct encap_type_info));
 
        g_array_append_vals(encap_table_arr,encap_table_base,wtap_num_encap_types);
-
-       encap_table = (void*)encap_table_arr->data;
 }
 
 int wtap_get_num_encap_types(void) {
@@ -632,8 +993,6 @@ int wtap_register_encap_type(const char* name, const char* short_name) {
 
        g_array_append_val(encap_table_arr,e);
 
-       encap_table = (void*)encap_table_arr->data;
-
        return wtap_num_encap_types++;
 }
 
@@ -647,7 +1006,7 @@ wtap_encap_string(int encap)
        else if (encap == WTAP_ENCAP_PER_PACKET)
                return "Per packet";
        else
-               return encap_table[encap].name;
+               return encap_table_entry(encap).name;
 }
 
 /* Name to use in, say, a command-line flag specifying the type. */
@@ -659,7 +1018,7 @@ wtap_encap_short_string(int encap)
        else if (encap == WTAP_ENCAP_PER_PACKET)
                return "per-packet";
        else
-               return encap_table[encap].short_name;
+               return encap_table_entry(encap).short_name;
 }
 
 /* Translate a short name to a capture file type. */
@@ -669,36 +1028,122 @@ wtap_short_string_to_encap(const char *short_name)
        int encap;
 
        for (encap = 0; encap < WTAP_NUM_ENCAP_TYPES; encap++) {
-               if (encap_table[encap].short_name != NULL &&
-                   strcmp(short_name, encap_table[encap].short_name) == 0)
+               if (encap_table_entry(encap).short_name != NULL &&
+                   strcmp(short_name, encap_table_entry(encap).short_name) == 0)
                        return encap;
        }
        return -1;      /* no such encapsulation type */
 }
 
+const char*
+wtap_tsprec_string(int tsprec)
+{
+       const char* s;
+       switch (tsprec) {
+               case WTAP_TSPREC_PER_PACKET:
+                       s = "per-packet";
+                       break;
+               case WTAP_TSPREC_SEC:
+                       s = "seconds";
+                       break;
+               case WTAP_TSPREC_DSEC:
+                       s = "deciseconds";
+                       break;
+               case WTAP_TSPREC_CSEC:
+                       s = "centiseconds";
+                       break;
+               case WTAP_TSPREC_MSEC:
+                       s = "milliseconds";
+                       break;
+               case WTAP_TSPREC_USEC:
+                       s = "microseconds";
+                       break;
+               case WTAP_TSPREC_NSEC:
+                       s = "nanoseconds";
+                       break;
+               case WTAP_TSPREC_UNKNOWN:
+               default:
+                       s = "UNKNOWN";
+                       break;
+       }
+       return s;
+}
+
 static const char *wtap_errlist[] = {
+       /* WTAP_ERR_NOT_REGULAR_FILE */
        "The file isn't a plain file or pipe",
+
+       /* WTAP_ERR_RANDOM_OPEN_PIPE */
        "The file is being opened for random access but is a pipe",
+
+       /* WTAP_ERR_FILE_UNKNOWN_FORMAT */
        "The file isn't a capture file in a known format",
+
+       /* WTAP_ERR_UNSUPPORTED */
        "File contains record data we don't support",
+
+       /* WTAP_ERR_CANT_WRITE_TO_PIPE */
        "That file format cannot be written to a pipe",
+
+       /* WTAP_ERR_CANT_OPEN */
        NULL,
+
+       /* WTAP_ERR_UNWRITABLE_FILE_TYPE */
        "Files can't be saved in that format",
-       "Files from that network type can't be saved in that format",
+
+       /* WTAP_ERR_UNWRITABLE_ENCAP */
+       "Packets with that network type can't be saved in that format",
+
+       /* WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED */
        "That file format doesn't support per-packet encapsulations",
+
+       /* WTAP_ERR_CANT_WRITE */
+       "A write failed for some unknown reason",
+
+       /* WTAP_ERR_CANT_CLOSE */
        NULL,
-       NULL,
+
+       /* WTAP_ERR_SHORT_READ */
        "Less data was read than was expected",
-       "The file appears to be damaged or corrupt.",
+
+       /* WTAP_ERR_BAD_FILE */
+       "The file appears to be damaged or corrupt",
+
+       /* WTAP_ERR_SHORT_WRITE */
        "Less data was written than was requested",
-       "Uncompression error: data oddly truncated",
+
+       /* WTAP_ERR_UNC_OVERFLOW */
        "Uncompression error: data would overflow buffer",
-       "Uncompression error: bad LZ77 offset",
+
+       /* WTAP_ERR_RANDOM_OPEN_STDIN */
        "The standard input cannot be opened for random access",
+
+       /* WTAP_ERR_COMPRESSION_NOT_SUPPORTED */
        "That file format doesn't support compression",
+
+       /* WTAP_ERR_CANT_SEEK */
+       NULL,
+
+       /* WTAP_ERR_CANT_SEEK_COMPRESSED */
        NULL,
+
+       /* WTAP_ERR_DECOMPRESS */
        "Uncompression error",
-       "Internal error"
+
+       /* WTAP_ERR_INTERNAL */
+       "Internal error",
+
+       /* WTAP_ERR_PACKET_TOO_LARGE */
+       "The packet being written is too large for that format",
+
+       /* WTAP_ERR_CHECK_WSLUA */
+       NULL,
+
+       /* WTAP_ERR_UNWRITABLE_REC_TYPE */
+       "That record type cannot be written in that format",
+
+       /* WTAP_ERR_UNWRITABLE_REC_DATA */
+       "That record can't be written in that format"
 };
 #define        WTAP_ERRLIST_SIZE       (sizeof wtap_errlist / sizeof wtap_errlist[0])
 
@@ -741,7 +1186,7 @@ wtap_sequential_close(wtap *wth)
        }
 
        if (wth->frame_buffer) {
-               buffer_free(wth->frame_buffer);
+               ws_buffer_free(wth->frame_buffer);
                g_free(wth->frame_buffer);
                wth->frame_buffer = NULL;
        }
@@ -771,7 +1216,7 @@ wtap_fdclose(wtap *wth)
 void
 wtap_close(wtap *wth)
 {
-       gint i, j;
+       guint i, j;
        wtapng_if_descr_t *wtapng_if_descr;
        wtapng_if_stats_t *if_stats;
 
@@ -790,7 +1235,13 @@ wtap_close(wtap *wth)
                g_ptr_array_foreach(wth->fast_seek, g_fast_seek_item_free, NULL);
                g_ptr_array_free(wth->fast_seek, TRUE);
        }
-       for(i = 0; i < (gint)wth->number_of_interfaces; i++) {
+
+       g_free(wth->shb_hdr.opt_comment);
+       g_free(wth->shb_hdr.shb_hardware);
+       g_free(wth->shb_hdr.shb_os);
+       g_free(wth->shb_hdr.shb_user_appl);
+
+       for(i = 0; i < wth->interface_data->len; i++) {
                wtapng_if_descr = &g_array_index(wth->interface_data, wtapng_if_descr_t, i);
                if(wtapng_if_descr->opt_comment != NULL){
                        g_free(wtapng_if_descr->opt_comment);
@@ -810,19 +1261,17 @@ wtap_close(wtap *wth)
                if(wtapng_if_descr->if_os != NULL){
                        g_free(wtapng_if_descr->if_os);
                }
-               for(j = 0; j < (gint)wtapng_if_descr->num_stat_entries; j++) {
+               for(j = 0; j < wtapng_if_descr->num_stat_entries; j++) {
                        if_stats = &g_array_index(wtapng_if_descr->interface_statistics, wtapng_if_stats_t, j);
                        if(if_stats->opt_comment != NULL){
                                g_free(if_stats->opt_comment);
                        }
                }
                if(wtapng_if_descr->num_stat_entries != 0){
-                        g_array_free(wtapng_if_descr->interface_statistics, TRUE);
+                       g_array_free(wtapng_if_descr->interface_statistics, TRUE);
                }
        }
-       if(wth->number_of_interfaces != 0){
-                g_array_free(wth->interface_data, TRUE);
-       }
+       g_array_free(wth->interface_data, TRUE);
        g_free(wth);
 }
 
@@ -852,9 +1301,14 @@ wtap_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
         * capture file type doesn't have to set it), and if it
         * *is* WTAP_ENCAP_PER_PACKET, the caller needs to set it
         * anyway.
+        *
+        * Do the same for the packet time stamp resolution.
         */
        wth->phdr.pkt_encap = wth->file_encap;
+       wth->phdr.pkt_tsprec = wth->file_tsprec;
 
+       *err = 0;
+       *err_info = NULL;
        if (!wth->subtype_read(wth, err, err_info, data_offset)) {
                /*
                 * If we didn't get an error indication, we read
@@ -888,6 +1342,83 @@ wtap_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
        return TRUE;    /* success */
 }
 
+/*
+ * Read a given number of bytes from a file.
+ *
+ * If we succeed, return TRUE.
+ *
+ * If we get an EOF, return FALSE with *err set to 0, reporting this
+ * as an EOF.
+ *
+ * If we get fewer bytes than the specified number, return FALSE with
+ * *err set to WTAP_ERR_SHORT_READ, reporting this as a short read
+ * error.
+ *
+ * If we get a read error, return FALSE with *err and *err_info set
+ * appropriately.
+ */
+gboolean
+wtap_read_bytes_or_eof(FILE_T fh, void *buf, unsigned int count, int *err,
+    gchar **err_info)
+{
+       int     bytes_read;
+
+       bytes_read = file_read(buf, count, fh);
+       if (bytes_read < 0 || (guint)bytes_read != count) {
+               *err = file_error(fh, err_info);
+               if (*err == 0 && bytes_read > 0)
+                       *err = WTAP_ERR_SHORT_READ;
+               return FALSE;
+       }
+       return TRUE;
+}
+
+/*
+ * Read a given number of bytes from a file.
+ *
+ * If we succeed, return TRUE.
+ *
+ * If we get fewer bytes than the specified number, including getting
+ * an EOF, return FALSE with *err set to WTAP_ERR_SHORT_READ, reporting
+ * this as a short read error.
+ *
+ * If we get a read error, return FALSE with *err and *err_info set
+ * appropriately.
+ */
+gboolean
+wtap_read_bytes(FILE_T fh, void *buf, unsigned int count, int *err,
+    gchar **err_info)
+{
+       int     bytes_read;
+
+       bytes_read = file_read(buf, count, fh);
+       if (bytes_read < 0 || (guint)bytes_read != count) {
+               *err = file_error(fh, err_info);
+               if (*err == 0)
+                       *err = WTAP_ERR_SHORT_READ;
+               return FALSE;
+       }
+       return TRUE;
+}
+
+/*
+ * Read packet data into a Buffer, growing the buffer as necessary.
+ *
+ * This returns an error on a short read, even if the short read hit
+ * the EOF immediately.  (The assumption is that each packet has a
+ * header followed by raw packet data, and that we've already read the
+ * header, so if we get an EOF trying to read the packet data, the file
+ * has been cut short, even if the read didn't read any data at all.)
+ */
+gboolean
+wtap_read_packet_bytes(FILE_T fh, Buffer *buf, guint length, int *err,
+    gchar **err_info)
+{
+       ws_buffer_assure_space(buf, length);
+       return wtap_read_bytes(fh, ws_buffer_start_ptr(buf), length, err,
+           err_info);
+}
+
 /*
  * Return an approximation of the amount of data we've read sequentially
  * from the file so far.  (gint64, in case that's 64 bits.)
@@ -907,25 +1438,69 @@ wtap_phdr(wtap *wth)
 guint8 *
 wtap_buf_ptr(wtap *wth)
 {
-       return buffer_start_ptr(wth->frame_buffer);
+       return ws_buffer_start_ptr(wth->frame_buffer);
+}
+
+void
+wtap_phdr_init(struct wtap_pkthdr *phdr)
+{
+       memset(phdr, 0, sizeof(struct wtap_pkthdr));
+       ws_buffer_init(&phdr->ft_specific_data, 0);
+}
+
+void
+wtap_phdr_cleanup(struct wtap_pkthdr *phdr)
+{
+       ws_buffer_free(&phdr->ft_specific_data);
 }
 
 gboolean
 wtap_seek_read(wtap *wth, gint64 seek_off,
-       struct wtap_pkthdr *phdr, guint8 *pd, int len,
-       int *err, gchar **err_info)
+       struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
 {
-       phdr->presence_flags = 0;
+       /*
+        * Set the packet encapsulation to the file's encapsulation
+        * value; if that's not WTAP_ENCAP_PER_PACKET, it's the
+        * right answer (and means that the read routine for this
+        * capture file type doesn't have to set it), and if it
+        * *is* WTAP_ENCAP_PER_PACKET, the caller needs to set it
+        * anyway.
+        *
+        * Do the same for the packet time stamp resolution.
+        */
        phdr->pkt_encap = wth->file_encap;
-       phdr->len = phdr->caplen = len;
+       phdr->pkt_tsprec = wth->file_tsprec;
 
-       if (!wth->subtype_seek_read(wth, seek_off, phdr, pd, len, err, err_info))
+       if (!wth->subtype_seek_read(wth, seek_off, phdr, buf, err, err_info))
                return FALSE;
 
+       /*
+        * It makes no sense for the captured data length to be bigger
+        * than the actual data length.
+        */
        if (phdr->caplen > phdr->len)
                phdr->caplen = phdr->len;
-                       
-       /* g_assert(phdr->pkt_encap != WTAP_ENCAP_PER_PACKET); */
+
+       /*
+        * Make sure that it's not WTAP_ENCAP_PER_PACKET, as that
+        * probably means the file has that encapsulation type
+        * but the read routine didn't set this packet's
+        * encapsulation type.
+        */
+       g_assert(phdr->pkt_encap != WTAP_ENCAP_PER_PACKET);
 
        return TRUE;
 }
+
+/*
+ * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */