Make the ERF code in pcap_get_phdr_size() more like the reading code.
[metze/wireshark/wip.git] / wiretap / pcapng.c
index 5b14294cd38125dbaade55f52c6760cd40eea756..fa84530e682839d23efa1cc28a99ad7f9387867a 100644 (file)
@@ -3,28 +3,16 @@
  * Wiretap Library
  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
  *
- * File format support for pcap-ng file format
+ * File format support for pcapng file format
  * Copyright (c) 2007 by Ulf Lamping <ulf.lamping@web.de>
  *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * SPDX-License-Identifier: GPL-2.0-or-later
  */
 
-/* File format reference:
- *   http://www.winpcap.org/ntar/draft/PCAP-DumpFileFormat.html
+/* File format specification:
+ *   https://github.com/pcapng/pcapng
  * Related Wiki page:
- *   http://wiki.wireshark.org/Development/PcapNg
+ *   https://wiki.wireshark.org/Development/PcapNg
  */
 
 #include "config.h"
 #include <string.h>
 #include <errno.h>
 
+#include <wsutil/ws_printf.h>
 
 #include "wtap-int.h"
-#include <epan/addr_resolv.h>
 #include "file_wrappers.h"
-#include <wsutil/buffer.h>
-#include "libpcap.h"
 #include "pcap-common.h"
 #include "pcap-encap.h"
 #include "pcapng.h"
 #include "pcapng_module.h"
 
 #if 0
-#define pcapng_debug0(str) g_warning(str)
-#define pcapng_debug1(str,p1) g_warning(str,p1)
-#define pcapng_debug2(str,p1,p2) g_warning(str,p1,p2)
-#define pcapng_debug3(str,p1,p2,p3) g_warning(str,p1,p2,p3)
+#define pcapng_debug(...) g_warning(__VA_ARGS__)
 #else
-#define pcapng_debug0(str)
-#define pcapng_debug1(str,p1)
-#define pcapng_debug2(str,p1,p2)
-#define pcapng_debug3(str,p1,p2,p3)
+#define pcapng_debug(...)
 #endif
 
 static gboolean
@@ -61,65 +41,21 @@ pcapng_read(wtap *wth, int *err, gchar **err_info,
             gint64 *data_offset);
 static gboolean
 pcapng_seek_read(wtap *wth, gint64 seek_off,
-                 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
+                 wtap_rec *rec, Buffer *buf, int *err, gchar **err_info);
 static void
 pcapng_close(wtap *wth);
 
-
-/* pcapng: common block header for every block type */
-typedef struct pcapng_block_header_s {
-    guint32 block_type;
-    guint32 block_total_length;
-    /* x bytes block_body */
-    /* guint32 block_total_length */
-} pcapng_block_header_t;
-
 /*
  * Minimum block size = size of block header + size of block trailer.
  */
 #define MIN_BLOCK_SIZE  ((guint32)(sizeof(pcapng_block_header_t) + sizeof(guint32)))
 
-/*
- * In order to keep from trying to allocate large chunks of memory,
- * which could either fail or, even if it succeeds, chew up so much
- * address space or memory+backing store as not to leave room for
- * anything else, we impose an upper limit on the size of blocks
- * we're willing to handle.
- *
- * For now, we pick an arbitrary limit of 16MB (OK, fine, 16MiB, but
- * don't try saying that on Wikipedia :-) :-) :-)).
- */
-#define MAX_BLOCK_SIZE  (16*1024*1024)
-
-/* pcapng: section header block */
-typedef struct pcapng_section_header_block_s {
-    /* pcapng_block_header_t */
-    guint32 magic;
-    guint16 version_major;
-    guint16 version_minor;
-    guint64 section_length; /* might be -1 for unknown */
-    /* ... Options ... */
-} pcapng_section_header_block_t;
-
 /*
  * Minimum SHB size = minimum block size + size of fixed length portion of SHB.
  */
 #define MIN_SHB_SIZE    ((guint32)(MIN_BLOCK_SIZE + sizeof(pcapng_section_header_block_t)))
 
-/* pcapng: interface description block */
-typedef struct pcapng_interface_description_block_s {
-    guint16 linktype;
-    guint16 reserved;
-    guint32 snaplen;
-    /* ... Options ... */
-} pcapng_interface_description_block_t;
-
-/*
- * Minimum IDB size = minimum block size + size of fixed length portion of IDB.
- */
-#define MIN_IDB_SIZE    ((guint32)(MIN_BLOCK_SIZE + sizeof(pcapng_interface_description_block_t)))
-
-/* pcapng: packet block (obsolete) */
+/* pcapng: packet block file encoding (obsolete) */
 typedef struct pcapng_packet_block_s {
     guint16 interface_id;
     guint16 drops_count;
@@ -137,7 +73,7 @@ typedef struct pcapng_packet_block_s {
  */
 #define MIN_PB_SIZE     ((guint32)(MIN_BLOCK_SIZE + sizeof(pcapng_packet_block_t)))
 
-/* pcapng: enhanced packet block */
+/* pcapng: enhanced packet block file encoding */
 typedef struct pcapng_enhanced_packet_block_s {
     guint32 interface_id;
     guint32 timestamp_high;
@@ -154,7 +90,7 @@ typedef struct pcapng_enhanced_packet_block_s {
  */
 #define MIN_EPB_SIZE    ((guint32)(MIN_BLOCK_SIZE + sizeof(pcapng_enhanced_packet_block_t)))
 
-/* pcapng: simple packet block */
+/* pcapng: simple packet block file encoding */
 typedef struct pcapng_simple_packet_block_s {
     guint32 packet_len;
     /* ... Packet Data ... */
@@ -166,7 +102,7 @@ typedef struct pcapng_simple_packet_block_s {
  */
 #define MIN_SPB_SIZE    ((guint32)(MIN_BLOCK_SIZE + sizeof(pcapng_simple_packet_block_t)))
 
-/* pcapng: name resolution block */
+/* pcapng: name resolution block file encoding */
 typedef struct pcapng_name_resolution_block_s {
     guint16 record_type;
     guint16 record_len;
@@ -179,20 +115,18 @@ typedef struct pcapng_name_resolution_block_s {
  */
 #define MIN_NRB_SIZE    ((guint32)(MIN_BLOCK_SIZE + sizeof(pcapng_name_resolution_block_t)))
 
-/* pcapng: interface statistics block */
-typedef struct pcapng_interface_statistics_block_s {
-    guint32 interface_id;
-    guint32 timestamp_high;
-    guint32 timestamp_low;
-    /* ... Options ... */
-} pcapng_interface_statistics_block_t;
-
 /*
  * Minimum ISB size = minimum block size + size of fixed length portion of ISB.
  */
 #define MIN_ISB_SIZE    ((guint32)(MIN_BLOCK_SIZE + sizeof(pcapng_interface_statistics_block_t)))
 
-/* pcapng: common option header for every option type */
+/*
+ * Minimum Sysdig size = minimum block size + packed size of sysdig_event_phdr.
+ */
+#define SYSDIG_EVENT_HEADER_SIZE ((16 + 64 + 64 + 32 + 16)/8) /* CPU ID + TS + TID + Event len + Event type */
+#define MIN_SYSDIG_EVENT_SIZE    ((guint32)(MIN_BLOCK_SIZE + SYSDIG_EVENT_HEADER_SIZE))
+
+/* pcapng: common option header file encoding for every option type */
 typedef struct pcapng_option_header_s {
     guint16 option_code;
     guint16 option_length;
@@ -205,88 +139,36 @@ struct option {
     guint16 value_length;
 };
 
-/* Block types */
-#define BLOCK_TYPE_IDB 0x00000001 /* Interface Description Block */
-#define BLOCK_TYPE_PB  0x00000002 /* Packet Block (obsolete) */
-#define BLOCK_TYPE_SPB 0x00000003 /* Simple Packet Block */
-#define BLOCK_TYPE_NRB 0x00000004 /* Name Resolution Block */
-#define BLOCK_TYPE_ISB 0x00000005 /* Interface Statistics Block */
-#define BLOCK_TYPE_EPB 0x00000006 /* Enhanced Packet Block */
-#define BLOCK_TYPE_SHB 0x0A0D0D0A /* Section Header Block */
-
-/* Options */
-#define OPT_EOFOPT        0
-#define OPT_COMMENT       1
-#define OPT_SHB_HARDWARE  2
-#define OPT_SHB_OS        3
-#define OPT_SHB_USERAPPL  4
-#define OPT_EPB_FLAGS     2
-#define OPT_EPB_HASH      3
-#define OPT_EPB_DROPCOUNT 4
-
-/* Capture section */
-#if 0
-/* Moved to wtap.h */
-typedef struct wtapng_section_s {
-    /* mandatory */
-    guint64                         section_length;
-    /* options */
-    gchar                           *opt_comment;   /* NULL if not available */
-    gchar                           *shb_hardware;  /* NULL if not available */
-    gchar                           *shb_os;                /* NULL if not available */
-    gchar                           *shb_user_appl; /* NULL if not available */
-} wtapng_section_t;
-#endif
+/* Option codes: 16-bit field */
+#define OPT_EPB_FLAGS        0x0002
+#define OPT_EPB_HASH         0x0003
+#define OPT_EPB_DROPCOUNT    0x0004
 
-#if 0
-/* Moved to wtap.h */
+#define OPT_NRB_DNSNAME      0x0002
+#define OPT_NRB_DNSV4ADDR    0x0003
+#define OPT_NRB_DNSV6ADDR    0x0004
+
+/* MSBit of option code means "local type" */
+#define OPT_LOCAL_FLAG       0x8000
 
-/* Interface Description
+/*
+ * In order to keep from trying to allocate large chunks of memory,
+ * which could either fail or, even if it succeeds, chew up so much
+ * address space or memory+backing store as not to leave room for
+ * anything else, we impose upper limits on the size of blocks we're
+ * willing to handle.
  *
- * Options:
- * if_name        2  A UTF-8 string containing the name of the device used to capture data. "eth0" / "\Device\NPF_{AD1CE675-96D0-47C5-ADD0-2504B9126B68}" / ...
- * if_description 3  A UTF-8 string containing the description of the device used to capture data. "Broadcom NetXtreme" / "First Ethernet Interface" / ...
- * if_IPv4addr    4  Interface network address and netmask. This option can be repeated multiple times within the same Interface Description Block when multiple IPv4 addresses are assigned to the interface. 192 168 1 1 255 255 255 0
- * if_IPv6addr    5  Interface network address and prefix length (stored in the last byte). This option can be repeated multiple times within the same Interface Description Block when multiple IPv6 addresses are assigned to the interface. 2001:0db8:85a3:08d3:1319:8a2e:0370:7344/64 is written (in hex) as "20 01 0d b8 85 a3 08 d3 13 19 8a 2e 03 70 73 44 40"
- * if_MACaddr     6  Interface Hardware MAC address (48 bits). 00 01 02 03 04 05
- * if_EUIaddr     7  Interface Hardware EUI address (64 bits), if available. TODO: give a good example
- * if_speed       8  Interface speed (in bps). 100000000 for 100Mbps
- * if_tsresol     9  Resolution of timestamps. If the Most Significant Bit is equal to zero, the remaining bits indicates the resolution of the timestamp as as a negative power of 10 (e.g. 6 means microsecond resolution, timestamps are the number of microseconds since 1/1/1970). If the Most Significant Bit is equal to one, the remaining bits indicates the resolution as as negative power of 2 (e.g. 10 means 1/1024 of second). If this option is not present, a resolution of 10^-6 is assumed (i.e. timestamps have the same resolution of the standard 'libpcap' timestamps). 6
- * if_tzone      10  Time zone for GMT support (TODO: specify better). TODO: give a good example
- * if_filter     11  The filter (e.g. "capture only TCP traffic") used to capture traffic. The first byte of the Option Data keeps a code of the filter used (e.g. if this is a libpcap string, or BPF bytecode, and more). More details about this format will be presented in Appendix XXX (TODO). (TODO: better use different options for different fields? e.g. if_filter_pcap, if_filter_bpf, ...) 00 "tcp port 23 and host 10.0.0.5"
- * if_os         12  A UTF-8 string containing the name of the operating system of the machine in which this interface is installed. This can be different from the same information that can be contained by the Section Header Block (Section 3.1 (Section Header Block (mandatory))) because the capture can have been done on a remote machine. "Windows XP SP2" / "openSUSE 10.2" / ...
- * if_fcslen     13  An integer value that specified the length of the Frame Check Sequence (in bits) for this interface. For link layers whose FCS length can change during time, the Packet Block Flags Word can be used (see Appendix A (Packet Block Flags Word)). 4
- * if_tsoffset   14  A 64 bits integer value that specifies an offset (in seconds) that must be added to the timestamp of each packet to obtain the absolute timestamp of a packet. If the option is missing, the timestamps stored in the packet must be considered absolute timestamps. The time zone of the offset can be specified with the option if_tzone. TODO: won't a if_tsoffset_low for fractional second offsets be useful for highly synchronized capture systems? 1234
+ * We pick a limit of an EPB with a maximum-sized D-Bus packet and 128 KiB
+ * worth of options; we use the maximum D-Bus packet size as that's larger
+ * than the maximum packet size for other link-layer types, and the maximum
+ * packet size for other link-layer types is currently small enough that
+ * the resulting block size would be less than the previous 16 MiB limit.
  */
+#define MAX_BLOCK_SIZE (MIN_EPB_SIZE + WTAP_MAX_PACKET_SIZE_DBUS + 131072)
 
-typedef struct wtapng_if_descr_s {
-    /* mandatory */
-    guint16  link_type;
-    guint    encap;
-    guint32  snap_len;
-    /* options */
-    gchar   *opt_comment;       /* NULL if not available */
-    gchar   *if_name;           /* NULL if not available, opt 2 A UTF-8 string containing the name of the device used to capture data. */
-    gchar   *if_description;    /* NULL if not available, opt 3 A UTF-8 string containing the description of the device used to capture data. */
-    /* XXX: if_IPv4addr opt 4  Interface network address and netmask.*/
-    /* XXX: if_IPv6addr opt 5  Interface network address and prefix length (stored in the last byte).*/
-    /* XXX: if_MACaddr  opt 6  Interface Hardware MAC address (48 bits).*/
-    /* XXX: if_EUIaddr  opt 7  Interface Hardware EUI address (64 bits)*/
-    guint64  if_speed;          /* 0 if unknown, opt 8  Interface speed (in bps). 100000000 for 100Mbps */
-    guint8   if_tsresol;     /* default is 6 for microsecond resolution, opt 9  Resolution of timestamps.
-                                                     * If the Most Significant Bit is equal to zero, the remaining bits indicates the resolution of the timestamp as as a negative power of 10
-                                                     */
-    /* XXX: if_tzone      10  Time zone for GMT support (TODO: specify better). */
-    gchar   *if_filter;     /* NULL if not available, opt 11  The filter (e.g. "capture only TCP traffic") used to capture traffic.
-                                                     * The first byte of the Option Data keeps a code of the filter used (e.g. if this is a libpcap string, or BPF bytecode, and more).
-                                                     */
-    gchar   *if_os;             /* NULL if not available, 12  A UTF-8 string containing the name of the operating system of the machine in which this interface is installed. */
-    gint8    if_fcslen;         /* -1 if unknown or changes between packets, opt 13  An integer value that specified the length of the Frame Check Sequence (in bits) for this interface. */
-    /* XXX: guint64 if_tsoffset; opt 14  A 64 bits integer value that specifies an offset (in seconds)...*/
-} wtapng_if_descr_t;
-#endif
+/* Note: many of the defined structures for block data are defined in wtap.h */
 
-/* Packets */
+/* Packet data - used for both Enhanced Packet Block and the obsolete Packet Block data */
 typedef struct wtapng_packet_s {
     /* mandatory */
     guint32                         ts_high;        /* seconds since 1.1.1970 */
@@ -300,7 +182,7 @@ typedef struct wtapng_packet_s {
     /* XXX - put the packet data / pseudo_header here as well? */
 } wtapng_packet_t;
 
-/* Simple Packets */
+/* Simple Packet data */
 typedef struct wtapng_simple_packet_s {
     /* mandatory */
     guint32                         cap_len;        /* data length in the file */
@@ -308,53 +190,6 @@ typedef struct wtapng_simple_packet_s {
     /* XXX - put the packet data / pseudo_header here as well? */
 } wtapng_simple_packet_t;
 
-/* Name Resolution */
-typedef struct wtapng_name_res_s {
-    /* options */
-    gchar                           *opt_comment;   /* NULL if not available */
-    /* XXX */
-} wtapng_name_res_t;
-
-#if 0
-/* Interface Statistics moved to wtap.h*/
-typedef struct wtapng_if_stats_s {
-    /* mandatory */
-    guint32                         interface_id;
-    guint32                         ts_high;
-    guint32                         ts_low;
-    /* options */
-    gchar                           *opt_comment;   /* NULL if not available */
-    guint64                         isb_starttime;
-    guint64                         isb_endtime;
-    guint64                         isb_ifrecv;
-    guint64                         isb_ifdrop;
-    guint64                         isb_filteraccept;
-    guint64                         isb_osdrop;
-    guint64                         isb_usrdeliv;
-} wtapng_if_stats_t;
-#endif
-
-typedef struct wtapng_block_s {
-    guint32                                 type;           /* block_type as defined by pcapng */
-    union {
-        wtapng_section_t        section;
-        wtapng_if_descr_t       if_descr;
-        wtapng_name_res_t       name_res;
-        wtapng_if_stats_t       if_stats;
-    } data;
-
-    /*
-     * XXX - currently don't know how to handle these!
-     *
-     * For one thing, when we're reading a block, they must be
-     * writable, i.e. not const, so that we can read into them,
-     * but, when we're writing a block, they can be const, and,
-     * in fact, they sometimes point to const values.
-     */
-    struct wtap_pkthdr *packet_header;
-    Buffer *frame_buffer;
-} wtapng_block_t;
-
 /* Interface data in private struct */
 typedef struct interface_info_s {
     int wtap_encap;
@@ -364,7 +199,7 @@ typedef struct interface_info_s {
 } interface_info_t;
 
 typedef struct {
-    gboolean shb_read;           /**< Set when first SHB read, second read will fail */
+    gboolean shb_read;           /**< Set when first SHB read */
     gboolean byte_swapped;
     guint16 version_major;
     guint16 version_minor;
@@ -389,18 +224,72 @@ typedef struct {
  * out a block.
  */
 typedef struct {
-    block_reader read;
-    block_writer write;
+    block_reader reader;
+    block_writer writer;
 } block_handler;
 
 static GHashTable *block_handlers;
 
 void
-register_pcapng_block_type_handler(guint block_type, block_reader read,
-                                   block_writer write)
+register_pcapng_block_type_handler(guint block_type, block_reader reader,
+                                   block_writer writer)
 {
     block_handler *handler;
 
+    /*
+     * Is this a known block type?
+     */
+    switch (block_type) {
+
+    case BLOCK_TYPE_SHB:
+    case BLOCK_TYPE_IDB:
+    case BLOCK_TYPE_PB:
+    case BLOCK_TYPE_SPB:
+    case BLOCK_TYPE_NRB:
+    case BLOCK_TYPE_ISB:
+    case BLOCK_TYPE_EPB:
+    case BLOCK_TYPE_SYSDIG_EVENT:
+        /*
+         * Yes; we already handle it, and don't allow a replacement to
+         * be registeted (if there's a bug in our code, or there's
+         * something we don't handle in that block, submit a change
+         * to the main Wireshark source).
+         */
+        g_warning("Attempt to register plugin for block type 0x%08x not allowed",
+                     block_type);
+        return;
+
+    case BLOCK_TYPE_IRIG_TS:
+    case BLOCK_TYPE_ARINC_429:
+    case BLOCK_TYPE_SYSDIG_EVF:
+        /*
+         * Yes, and we don't already handle it.  Allow a plugin to
+         * handle it.
+         *
+         * (But why not submit the plugin source to Wireshark?)
+         */
+        break;
+
+    default:
+        /*
+         * No; is it a local block type?
+         */
+         if (!(block_type & 0x80000000)) {
+             /*
+              * No; don't allow a plugin to be registered for it, as
+              * the block type needs to be registered before it's used.
+              */
+            g_warning("Attempt to register plugin for reserved block type 0x%08x not allowed",
+                         block_type);
+            return;
+         }
+
+         /*
+          * Yes; allow the registration.
+          */
+         break;
+    }
+
     if (block_handlers == NULL) {
         /*
          * Create the table of block handlers.
@@ -412,31 +301,148 @@ register_pcapng_block_type_handler(guint block_type, block_reader read,
                                                g_direct_equal,
                                                NULL, g_free);
     }
-    handler = (block_handler *)g_malloc(sizeof *handler);
-    handler->read = read;
-    handler->write = write;
-    (void)g_hash_table_insert(block_handlers, GUINT_TO_POINTER(block_type),
+    handler = g_new(block_handler, 1);
+    handler->reader = reader;
+    handler->writer = writer;
+    g_hash_table_insert(block_handlers, GUINT_TO_POINTER(block_type),
                               handler);
 }
+
+/*
+ * Tables for plugins to handle particular options for particular block
+ * types.
+ *
+ * An option has a handler routine, which is passed an indication of
+ * whether this section of the file is byte-swapped, the length of the
+ * option, the data of the option, a pointer to an error code, and a
+ * pointer to a pointer variable for an error string.
+ *
+ * It checks whether the length and option are valid, and, if they aren't,
+ * returns FALSE, setting the error code to the appropriate error (normally
+ * WTAP_ERR_BAD_FILE) and the error string to an appropriate string
+ * indicating the problem.
+ *
+ * Otherwise, if this section of the file is byte-swapped, it byte-swaps
+ * multi-byte numerical values, so that it's in the host byte order.
+ */
+
+/*
+ * Block types indices in the table of tables of option handlers.
+ *
+ * Block types are not guaranteed to be sequential, so we map the
+ * block types we support to a sequential set.  Furthermore, all
+ * packet block types have the same set of options.
+ */
+#define BT_INDEX_SHB        0
+#define BT_INDEX_IDB        1
+#define BT_INDEX_PBS        2  /* all packet blocks */
+#define BT_INDEX_NRB        3
+#define BT_INDEX_ISB        4
+#define BT_INDEX_EVT        5
+
+#define NUM_BT_INDICES      6
+
+typedef struct {
+    option_handler_fn hfunc;
+} option_handler;
+
+static GHashTable *option_handlers[NUM_BT_INDICES];
+
+static gboolean
+get_block_type_index(guint block_type, guint *bt_index)
+{
+    g_assert(bt_index);
+
+    switch (block_type) {
+
+        case BLOCK_TYPE_SHB:
+            *bt_index = BT_INDEX_SHB;
+            break;
+
+        case BLOCK_TYPE_IDB:
+            *bt_index = BT_INDEX_IDB;
+            break;
+
+        case BLOCK_TYPE_PB:
+        case BLOCK_TYPE_EPB:
+        case BLOCK_TYPE_SPB:
+            *bt_index = BT_INDEX_PBS;
+            break;
+
+        case BLOCK_TYPE_NRB:
+            *bt_index = BT_INDEX_NRB;
+            break;
+
+        case BLOCK_TYPE_ISB:
+            *bt_index = BT_INDEX_ISB;
+            break;
+
+        case BLOCK_TYPE_SYSDIG_EVENT:
+        /* case BLOCK_TYPE_SYSDIG_EVF: */
+            *bt_index = BT_INDEX_EVT;
+            break;
+
+        default:
+            /*
+             * This is a block type we don't process; either we ignore it,
+             * in which case the options don't get processed, or there's
+             * a plugin routine to handle it, in which case that routine
+             * will do the option processing itself.
+             *
+             * XXX - report an error?
+             */
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
+void
+register_pcapng_option_handler(guint block_type, guint option_code,
+                               option_handler_fn hfunc)
+{
+    guint bt_index;
+    option_handler *handler;
+
+    if (!get_block_type_index(block_type, &bt_index))
+        return;
+
+    if (option_handlers[bt_index] == NULL) {
+        /*
+         * Create the table of option handlers for this block type.
+         *
+         * XXX - there's no "g_uint_hash()" or "g_uint_equal()",
+         * so we use "g_direct_hash()" and "g_direct_equal()".
+         */
+        option_handlers[bt_index] = g_hash_table_new_full(g_direct_hash,
+                                                          g_direct_equal,
+                                                          NULL, g_free);
+    }
+    handler = g_new(option_handler, 1);
+    handler->hfunc = hfunc;
+    g_hash_table_insert(option_handlers[bt_index],
+                              GUINT_TO_POINTER(option_code), handler);
+}
 #endif /* HAVE_PLUGINS */
 
 static int
 pcapng_read_option(FILE_T fh, pcapng_t *pn, pcapng_option_header_t *oh,
-                   char *content, guint len, guint to_read,
-                   int *err, gchar **err_info)
+                   guint8 *content, guint len, guint to_read,
+                   int *err, gchar **err_info, gchar* block_name)
 {
     int     block_read;
 
     /* sanity check: don't run past the end of the block */
     if (to_read < sizeof (*oh)) {
         *err = WTAP_ERR_BAD_FILE;
-        *err_info = g_strdup("pcapng_read_option: option goes past the end of the block");
+        *err_info = g_strdup_printf("pcapng_read_option: Not enough data to read header of the %s block",
+                                    block_name);
         return -1;
     }
 
     /* read option header */
     if (!wtap_read_bytes(fh, oh, sizeof (*oh), err, err_info)) {
-        pcapng_debug0("pcapng_read_option: failed to read option");
+        pcapng_debug("pcapng_read_option: failed to read option");
         return -1;
     }
     block_read = sizeof (*oh);
@@ -448,27 +454,29 @@ pcapng_read_option(FILE_T fh, pcapng_t *pn, pcapng_option_header_t *oh,
     /* sanity check: don't run past the end of the block */
     if (to_read < sizeof (*oh) + oh->option_length) {
         *err = WTAP_ERR_BAD_FILE;
-        *err_info = g_strdup("pcapng_read_option: option goes past the end of the block");
+        *err_info = g_strdup_printf("pcapng_read_option: Not enough data to handle option length (%d) of the %s block",
+                                    oh->option_length, block_name);
         return -1;
     }
 
     /* sanity check: option length */
     if (len < oh->option_length) {
         *err = WTAP_ERR_BAD_FILE;
-        *err_info = g_strdup("pcapng_read_option: option goes past the end of the block");
+        *err_info = g_strdup_printf("pcapng_read_option: option length (%d) to long for %s block",
+                                    len, block_name);
         return -1;
     }
 
     /* read option content */
     if (!wtap_read_bytes(fh, content, oh->option_length, err, err_info)) {
-        pcapng_debug1("pcapng_read_option: failed to read content of option %u", oh->option_code);
+        pcapng_debug("pcapng_read_option: failed to read content of option %u", oh->option_code);
         return -1;
     }
     block_read += oh->option_length;
 
     /* jump over potential padding bytes at end of option */
     if ( (oh->option_length % 4) != 0) {
-        if (!file_skip(fh, 4 - (oh->option_length % 4), err))
+        if (!wtap_read_bytes(fh, NULL, 4 - (oh->option_length % 4), err, err_info))
             return -1;
         block_read += 4 - (oh->option_length % 4);
     }
@@ -476,102 +484,95 @@ pcapng_read_option(FILE_T fh, pcapng_t *pn, pcapng_option_header_t *oh,
     return block_read;
 }
 
+typedef enum {
+    PCAPNG_BLOCK_OK,
+    PCAPNG_BLOCK_NOT_SHB,
+    PCAPNG_BLOCK_ERROR
+} block_return_val;
 
-static void
-pcapng_free_wtapng_block_data(wtapng_block_t *wblock)
-{
-    switch (wblock->type) {
-        case(BLOCK_TYPE_SHB):
-            g_free(wblock->data.section.opt_comment);
-            g_free(wblock->data.section.shb_hardware);
-            g_free(wblock->data.section.shb_os);
-            g_free(wblock->data.section.shb_user_appl);
-            break;
-    }
-}
-
-static int
-pcapng_read_section_header_block(FILE_T fh, gboolean first_block,
-                                 pcapng_block_header_t *bh, pcapng_t *pn,
-                                 wtapng_block_t *wblock, int *err,
-                                 gchar **err_info)
+static block_return_val
+pcapng_read_section_header_block(FILE_T fh, pcapng_block_header_t *bh,
+                                 pcapng_t *pn, wtapng_block_t *wblock,
+                                 int *err, gchar **err_info)
 {
     int     bytes_read;
-    guint   block_read;
+    gboolean byte_swapped;
+    guint16 version_major;
+    guint16 version_minor;
     guint to_read, opt_cont_buf_len;
     pcapng_section_header_block_t shb;
     pcapng_option_header_t oh;
-    char *option_content = NULL; /* Allocate as large as the options block */
+    wtapng_mandatory_section_t* section_data;
+    gchar* tmp_content;
 
-    /*
-     * Is this block long enough to be an SHB?
-     */
-    if (bh->block_total_length < MIN_SHB_SIZE) {
-        /*
-         * No.
-         */
-        if (first_block)
-            return -2;       /* probably not a pcap-ng file */
-        *err = WTAP_ERR_BAD_FILE;
-        *err_info = g_strdup_printf("pcapng_read_section_header_block: total block length %u of an SHB is less than the minimum SHB size %u",
-                                    bh->block_total_length, MIN_SHB_SIZE);
-        return -1;
-    }
+    guint8 *option_content = NULL; /* Allocate as large as the options block */
 
-    /* read block content */
+    /* read fixed-length part of the block */
     if (!wtap_read_bytes(fh, &shb, sizeof shb, err, err_info)) {
         if (*err == WTAP_ERR_SHORT_READ) {
-            if (first_block) {
-                /*
-                 * We're reading this as part of an open,
-                 * and this block is too short to be
-                 * an SHB, so the file is too short
-                 * to be a pcap-ng file.
-                 */
-                return -2;
-            }
+            /*
+             * This block is too short to be an SHB.
+             *
+             * If we're reading this as part of an open,
+             * the file is too short to be a pcapng file.
+             *
+             * If we're not, we treat PCAPNG_BLOCK_NOT_SHB and
+             * PCAPNG_BLOCK_ERROR the same, so we can just return
+             * PCAPNG_BLOCK_NOT_SHB in both cases.
+             */
+            return PCAPNG_BLOCK_NOT_SHB;
         }
-        return -1;
+        return PCAPNG_BLOCK_ERROR;
     }
-    block_read = (guint)sizeof shb;
 
     /* is the magic number one we expect? */
     switch (shb.magic) {
         case(0x1A2B3C4D):
             /* this seems pcapng with correct byte order */
-            pn->byte_swapped                = FALSE;
-            pn->version_major               = shb.version_major;
-            pn->version_minor               = shb.version_minor;
+            byte_swapped                = FALSE;
+            version_major               = shb.version_major;
+            version_minor               = shb.version_minor;
 
-            pcapng_debug3("pcapng_read_section_header_block: SHB (little endian) V%u.%u, len %u",
-                          pn->version_major, pn->version_minor, bh->block_total_length);
+            pcapng_debug("pcapng_read_section_header_block: SHB (our byte order) V%u.%u, len %u",
+                          version_major, version_minor, bh->block_total_length);
             break;
         case(0x4D3C2B1A):
             /* this seems pcapng with swapped byte order */
-            pn->byte_swapped                = TRUE;
-            pn->version_major               = GUINT16_SWAP_LE_BE(shb.version_major);
-            pn->version_minor               = GUINT16_SWAP_LE_BE(shb.version_minor);
+            byte_swapped                = TRUE;
+            version_major               = GUINT16_SWAP_LE_BE(shb.version_major);
+            version_minor               = GUINT16_SWAP_LE_BE(shb.version_minor);
 
             /* tweak the block length to meet current swapping that we know now */
             bh->block_total_length  = GUINT32_SWAP_LE_BE(bh->block_total_length);
 
-            pcapng_debug3("pcapng_read_section_header_block: SHB (big endian) V%u.%u, len %u",
-                          pn->version_major, pn->version_minor, bh->block_total_length);
+            pcapng_debug("pcapng_read_section_header_block: SHB (byte-swapped) V%u.%u, len %u",
+                          version_major, version_minor, bh->block_total_length);
             break;
         default:
             /* Not a "pcapng" magic number we know about. */
-            if (first_block) {
-                /* Not a pcap-ng file. */
-                return -2;
-            }
-
-            /* A bad block */
             *err = WTAP_ERR_BAD_FILE;
             *err_info = g_strdup_printf("pcapng_read_section_header_block: unknown byte-order magic number 0x%08x", shb.magic);
-            return -1;
+
+            /*
+             * See above comment about PCAPNG_BLOCK_NOT_SHB.
+             */
+            return PCAPNG_BLOCK_NOT_SHB;
+    }
+
+    /*
+     * Is this block long enough to be an SHB?
+     */
+    if (bh->block_total_length < MIN_SHB_SIZE) {
+        /*
+         * No.
+         */
+        *err = WTAP_ERR_BAD_FILE;
+        *err_info = g_strdup_printf("pcapng_read_section_header_block: total block length %u of an SHB is less than the minimum SHB size %u",
+                                    bh->block_total_length, MIN_SHB_SIZE);
+        return PCAPNG_BLOCK_ERROR;
     }
 
-    /* OK, at this point we assume it's a pcap-ng file.
+    /* OK, at this point we assume it's a pcapng file.
 
        Don't try to allocate memory for a huge number of options, as
        that might fail and, even if it succeeds, it might not leave
@@ -579,36 +580,34 @@ pcapng_read_section_header_block(FILE_T fh, gboolean first_block,
 
        We do that by imposing a maximum block size of MAX_BLOCK_SIZE.
        We check for this *after* checking the SHB for its byte
-       order magic number, so that non-pcap-ng files are less
-       likely to be treated as bad pcap-ng files. */
+       order magic number, so that non-pcapng files are less
+       likely to be treated as bad pcapng files. */
     if (bh->block_total_length > MAX_BLOCK_SIZE) {
         *err = WTAP_ERR_BAD_FILE;
-        *err_info = g_strdup_printf("pcapng: total block length %u is too large (> %u)",
+        *err_info = g_strdup_printf("pcapng_read_section_header_block: total block length %u is too large (> %u)",
                                     bh->block_total_length, MAX_BLOCK_SIZE);
-        return -1;
-    }
-
-    /* We currently only suport one SHB */
-    if (pn->shb_read == TRUE) {
-        *err = WTAP_ERR_UNSUPPORTED;
-        *err_info = g_strdup_printf("pcapng: multiple section header blocks not supported");
-        return -1;
+        return PCAPNG_BLOCK_ERROR;
     }
 
     /* we currently only understand SHB V1.0 */
-    if (pn->version_major != 1 || pn->version_minor > 0) {
+    if (version_major != 1 || version_minor > 0) {
         *err = WTAP_ERR_UNSUPPORTED;
         *err_info = g_strdup_printf("pcapng_read_section_header_block: unknown SHB version %u.%u",
                                     pn->version_major, pn->version_minor);
-        return -1;
+        return PCAPNG_BLOCK_ERROR;
     }
 
+    pn->byte_swapped  = byte_swapped;
+    pn->version_major = version_major;
+    pn->version_minor = version_minor;
 
+    wblock->block = wtap_block_create(WTAP_BLOCK_NG_SECTION);
+    section_data = (wtapng_mandatory_section_t*)wtap_block_get_mandatory_data(wblock->block);
     /* 64bit section_length (currently unused) */
     if (pn->byte_swapped) {
-        wblock->data.section.section_length = GUINT64_SWAP_LE_BE(shb.section_length);
+        section_data->section_length = GUINT64_SWAP_LE_BE(shb.section_length);
     } else {
-        wblock->data.section.section_length = shb.section_length;
+        section_data->section_length = shb.section_length;
     }
 
     /* Options */
@@ -616,81 +615,93 @@ pcapng_read_section_header_block(FILE_T fh, gboolean first_block,
 
     /* Allocate enough memory to hold all options */
     opt_cont_buf_len = to_read;
-    option_content = (char *)g_try_malloc(opt_cont_buf_len);
+    option_content = (guint8 *)g_try_malloc(opt_cont_buf_len);
     if (opt_cont_buf_len != 0 && option_content == NULL) {
         *err = ENOMEM;  /* we assume we're out of memory */
-        return -1;
+        return PCAPNG_BLOCK_ERROR;
     }
-    pcapng_debug1("pcapng_read_section_header_block: Options %u bytes", to_read);
+    pcapng_debug("pcapng_read_section_header_block: Options %u bytes", to_read);
     while (to_read != 0) {
         /* read option */
-        pcapng_debug1("pcapng_read_section_header_block: Options %u bytes remaining", to_read);
-        bytes_read = pcapng_read_option(fh, pn, &oh, option_content, opt_cont_buf_len, to_read, err, err_info);
+        pcapng_debug("pcapng_read_section_header_block: Options %u bytes remaining", to_read);
+        bytes_read = pcapng_read_option(fh, pn, &oh, option_content, opt_cont_buf_len, to_read, err, err_info, "section_header");
         if (bytes_read <= 0) {
-            pcapng_debug0("pcapng_read_section_header_block: failed to read option");
-            return bytes_read;
+            pcapng_debug("pcapng_read_section_header_block: failed to read option");
+            g_free(option_content);
+            return PCAPNG_BLOCK_ERROR;
         }
-        block_read += bytes_read;
         to_read -= bytes_read;
 
         /* handle option content */
         switch (oh.option_code) {
             case(OPT_EOFOPT):
                 if (to_read != 0) {
-                    pcapng_debug1("pcapng_read_section_header_block: %u bytes after opt_endofopt", to_read);
+                    pcapng_debug("pcapng_read_section_header_block: %u bytes after opt_endofopt", to_read);
                 }
                 /* padding should be ok here, just get out of this */
                 to_read = 0;
                 break;
             case(OPT_COMMENT):
                 if (oh.option_length > 0 && oh.option_length < opt_cont_buf_len) {
-                    g_free(wblock->data.section.opt_comment);
-                    wblock->data.section.opt_comment = g_strndup(option_content, oh.option_length);
-                    pcapng_debug1("pcapng_read_section_header_block: opt_comment %s", wblock->data.section.opt_comment);
+                    tmp_content = g_strndup((char *)option_content, oh.option_length);
+                    wtap_block_add_string_option(wblock->block, OPT_COMMENT, option_content, oh.option_length);
+                    pcapng_debug("pcapng_read_section_header_block: opt_comment %s", tmp_content);
+                    g_free(tmp_content);
                 } else {
-                    pcapng_debug1("pcapng_read_section_header_block: opt_comment length %u seems strange", oh.option_length);
+                    pcapng_debug("pcapng_read_section_header_block: opt_comment length %u seems strange", oh.option_length);
                 }
                 break;
             case(OPT_SHB_HARDWARE):
                 if (oh.option_length > 0 && oh.option_length < opt_cont_buf_len) {
-                    g_free(wblock->data.section.shb_hardware);
-                    wblock->data.section.shb_hardware = g_strndup(option_content, oh.option_length);
-                    pcapng_debug1("pcapng_read_section_header_block: shb_hardware %s", wblock->data.section.shb_hardware);
+                    tmp_content = g_strndup((char *)option_content, oh.option_length);
+                    /* Fails with multiple options; we silently ignore the failure */
+                    wtap_block_add_string_option(wblock->block, OPT_SHB_HARDWARE, option_content, oh.option_length);
+                    pcapng_debug("pcapng_read_section_header_block: shb_hardware %s", tmp_content);
+                    g_free(tmp_content);
                 } else {
-                    pcapng_debug1("pcapng_read_section_header_block: shb_hardware length %u seems strange", oh.option_length);
+                    pcapng_debug("pcapng_read_section_header_block: shb_hardware length %u seems strange", oh.option_length);
                 }
                 break;
             case(OPT_SHB_OS):
                 if (oh.option_length > 0 && oh.option_length < opt_cont_buf_len) {
-                    g_free(wblock->data.section.shb_os);
-                    wblock->data.section.shb_os = g_strndup(option_content, oh.option_length);
-                    pcapng_debug1("pcapng_read_section_header_block: shb_os %s", wblock->data.section.shb_os);
+                    tmp_content = g_strndup((char *)option_content, oh.option_length);
+                    /* Fails with multiple options; we silently ignore the failure */
+                    wtap_block_add_string_option(wblock->block, OPT_SHB_OS, option_content, oh.option_length);
+                    pcapng_debug("pcapng_read_section_header_block: shb_os %s", tmp_content);
+                    g_free(tmp_content);
                 } else {
-                    pcapng_debug2("pcapng_read_section_header_block: shb_os length %u seems strange, opt buffsize %u", oh.option_length,to_read);
+                    pcapng_debug("pcapng_read_section_header_block: shb_os length %u seems strange, opt buffsize %u", oh.option_length,to_read);
                 }
                 break;
             case(OPT_SHB_USERAPPL):
                 if (oh.option_length > 0 && oh.option_length < opt_cont_buf_len) {
-                    g_free(wblock->data.section.shb_user_appl);
-                    wblock->data.section.shb_user_appl = g_strndup(option_content, oh.option_length);
-                    pcapng_debug1("pcapng_read_section_header_block: shb_user_appl %s", wblock->data.section.shb_user_appl);
+                    tmp_content = g_strndup((char *)option_content, oh.option_length);
+                    /* Fails with multiple options; we silently ignore the failure */
+                    wtap_block_add_string_option(wblock->block, OPT_SHB_USERAPPL, option_content, oh.option_length);
+                    pcapng_debug("pcapng_read_section_header_block: shb_user_appl %s", tmp_content);
+                    g_free(tmp_content);
                 } else {
-                    pcapng_debug1("pcapng_read_section_header_block: shb_user_appl length %u seems strange", oh.option_length);
+                    pcapng_debug("pcapng_read_section_header_block: shb_user_appl length %u seems strange", oh.option_length);
                 }
                 break;
             default:
-                pcapng_debug2("pcapng_read_section_header_block: unknown option %u - ignoring %u bytes",
+                pcapng_debug("pcapng_read_section_header_block: unknown option %u - ignoring %u bytes",
                               oh.option_code, oh.option_length);
         }
     }
     g_free(option_content);
 
-    return block_read;
+    /*
+     * We don't return these to the caller in pcapng_read().
+     */
+    wblock->internal = TRUE;
+
+    return PCAPNG_BLOCK_OK;
 }
 
 
 /* "Interface Description Block" */
-static int
+static gboolean
 pcapng_read_if_descr_block(wtap *wth, FILE_T fh, pcapng_block_header_t *bh,
                            pcapng_t *pn, wtapng_block_t *wblock, int *err,
                            gchar **err_info)
@@ -698,11 +709,14 @@ pcapng_read_if_descr_block(wtap *wth, FILE_T fh, pcapng_block_header_t *bh,
     guint64 time_units_per_second = 1000000; /* default = 10^6 */
     int     tsprecision = WTAP_TSPREC_USEC;
     int     bytes_read;
-    guint   block_read;
     guint to_read, opt_cont_buf_len;
     pcapng_interface_description_block_t idb;
+    wtapng_if_descr_mandatory_t* if_descr_mand;
+    guint   link_type;
     pcapng_option_header_t oh;
-    char *option_content = NULL; /* Allocate as large as the options block */
+    guint8 *option_content = NULL; /* Allocate as large as the options block */
+    gchar* tmp_content;
+    guint64 tmp64;
 
     /*
      * Is this block long enough to be an IDB?
@@ -714,151 +728,124 @@ pcapng_read_if_descr_block(wtap *wth, FILE_T fh, pcapng_block_header_t *bh,
         *err = WTAP_ERR_BAD_FILE;
         *err_info = g_strdup_printf("pcapng_read_if_descr_block: total block length %u of an IDB is less than the minimum IDB size %u",
                                     bh->block_total_length, MIN_IDB_SIZE);
-        return -1;
-    }
-
-    /* Don't try to allocate memory for a huge number of options, as
-       that might fail and, even if it succeeds, it might not leave
-       any address space or memory+backing store for anything else.
-
-       We do that by imposing a maximum block size of MAX_BLOCK_SIZE.
-       We check for this *after* checking the SHB for its byte
-       order magic number, so that non-pcap-ng files are less
-       likely to be treated as bad pcap-ng files. */
-    if (bh->block_total_length > MAX_BLOCK_SIZE) {
-        *err = WTAP_ERR_BAD_FILE;
-        *err_info = g_strdup_printf("pcapng: total block length %u is too large (> %u)",
-                                    bh->block_total_length, MAX_BLOCK_SIZE);
-        return -1;
+        return FALSE;
     }
 
     /* read block content */
     if (!wtap_read_bytes(fh, &idb, sizeof idb, err, err_info)) {
-        pcapng_debug0("pcapng_read_if_descr_block: failed to read IDB");
-        return -1;
+        pcapng_debug("pcapng_read_if_descr_block: failed to read IDB");
+        return FALSE;
     }
-    block_read = (guint)sizeof idb;
 
     /* mandatory values */
+    wblock->block = wtap_block_create(WTAP_BLOCK_IF_DESCR);
+    if_descr_mand = (wtapng_if_descr_mandatory_t*)wtap_block_get_mandatory_data(wblock->block);
     if (pn->byte_swapped) {
-        wblock->data.if_descr.link_type = GUINT16_SWAP_LE_BE(idb.linktype);
-        wblock->data.if_descr.snap_len  = GUINT32_SWAP_LE_BE(idb.snaplen);
+        link_type = GUINT16_SWAP_LE_BE(idb.linktype);
+        if_descr_mand->snap_len  = GUINT32_SWAP_LE_BE(idb.snaplen);
     } else {
-        wblock->data.if_descr.link_type = idb.linktype;
-        wblock->data.if_descr.snap_len  = idb.snaplen;
+        link_type = idb.linktype;
+        if_descr_mand->snap_len  = idb.snaplen;
     }
 
-    wblock->data.if_descr.wtap_encap = wtap_pcap_encap_to_wtap_encap(wblock->data.if_descr.link_type);
-    wblock->data.if_descr.time_units_per_second = time_units_per_second;
-    wblock->data.if_descr.tsprecision = tsprecision;
+    if_descr_mand->wtap_encap = wtap_pcap_encap_to_wtap_encap(link_type);
+    if_descr_mand->time_units_per_second = time_units_per_second;
+    if_descr_mand->tsprecision = tsprecision;
 
-    pcapng_debug3("pcapng_read_if_descr_block: IDB link_type %u (%s), snap %u",
-                  wblock->data.if_descr.link_type,
-                  wtap_encap_string(wblock->data.if_descr.wtap_encap),
-                  wblock->data.if_descr.snap_len);
+    pcapng_debug("pcapng_read_if_descr_block: IDB link_type %u (%s), snap %u",
+                  link_type,
+                  wtap_encap_string(if_descr_mand->wtap_encap),
+                  if_descr_mand->snap_len);
 
-    if (wblock->data.if_descr.snap_len > WTAP_MAX_PACKET_SIZE) {
-        /* This is unrealistic, but text2pcap currently uses 102400.
+    if (if_descr_mand->snap_len > wtap_max_snaplen_for_encap(if_descr_mand->wtap_encap)) {
+        /*
          * We do not use this value, maybe we should check the
          * snap_len of the packets against it. For now, only warn.
          */
-        pcapng_debug1("pcapng_read_if_descr_block: snapshot length %u unrealistic.",
-                      wblock->data.if_descr.snap_len);
-        /*wblock->data.if_descr.snap_len = WTAP_MAX_PACKET_SIZE;*/
+        pcapng_debug("pcapng_read_if_descr_block: snapshot length %u unrealistic.",
+                      if_descr_mand->snap_len);
+        /*if_descr_mand->snap_len = WTAP_MAX_PACKET_SIZE_STANDARD;*/
     }
 
-    /* Option defaults */
-    wblock->data.if_descr.opt_comment = NULL;
-    wblock->data.if_descr.if_name = NULL;
-    wblock->data.if_descr.if_description = NULL;
-    /* XXX: if_IPv4addr */
-    /* XXX: if_IPv6addr */
-    /* XXX: if_MACaddr */
-    /* XXX: if_EUIaddr */
-    wblock->data.if_descr.if_speed = 0;                     /* "unknown" */
-    wblock->data.if_descr.if_tsresol = 6;                   /* default is 6 for microsecond resolution */
-    wblock->data.if_descr.if_filter_str = NULL;
-    wblock->data.if_descr.bpf_filter_len = 0;
-    wblock->data.if_descr.if_filter_bpf_bytes = NULL;
-    wblock->data.if_descr.if_os = NULL;
-    wblock->data.if_descr.if_fcslen = -1;                   /* unknown or changes between packets */
-    /* XXX: guint64 if_tsoffset; */
-
-
     /* Options */
     to_read = bh->block_total_length - MIN_IDB_SIZE;
 
     /* Allocate enough memory to hold all options */
     opt_cont_buf_len = to_read;
-    option_content = (char *)g_try_malloc(opt_cont_buf_len);
+    option_content = (guint8 *)g_try_malloc(opt_cont_buf_len);
     if (opt_cont_buf_len != 0 && option_content == NULL) {
         *err = ENOMEM;  /* we assume we're out of memory */
-        return -1;
+        return FALSE;
     }
 
     while (to_read != 0) {
         /* read option */
-        bytes_read = pcapng_read_option(fh, pn, &oh, option_content, opt_cont_buf_len, to_read, err, err_info);
+        bytes_read = pcapng_read_option(fh, pn, &oh, option_content, opt_cont_buf_len, to_read, err, err_info, "if_descr");
         if (bytes_read <= 0) {
-            pcapng_debug0("pcapng_read_if_descr_block: failed to read option");
-            return bytes_read;
+            pcapng_debug("pcapng_read_if_descr_block: failed to read option");
+            g_free(option_content);
+            return FALSE;
         }
-        block_read += bytes_read;
         to_read -= bytes_read;
 
         /* handle option content */
         switch (oh.option_code) {
-            case(0): /* opt_endofopt */
+            case(OPT_EOFOPT): /* opt_endofopt */
                 if (to_read != 0) {
-                    pcapng_debug1("pcapng_read_if_descr_block: %u bytes after opt_endofopt", to_read);
+                    pcapng_debug("pcapng_read_if_descr_block: %u bytes after opt_endofopt", to_read);
                 }
                 /* padding should be ok here, just get out of this */
                 to_read = 0;
                 break;
-            case(1): /* opt_comment */
+            case(OPT_COMMENT): /* opt_comment */
                 if (oh.option_length > 0 && oh.option_length < opt_cont_buf_len) {
-                    wblock->data.if_descr.opt_comment = g_strndup(option_content, oh.option_length);
-                    pcapng_debug1("pcapng_read_if_descr_block: opt_comment %s", wblock->data.if_descr.opt_comment);
+                    tmp_content = g_strndup((char *)option_content, oh.option_length);
+                    wtap_block_add_string_option(wblock->block, oh.option_code, option_content, oh.option_length);
+                    pcapng_debug("pcapng_read_if_descr_block: opt_comment %s", tmp_content);
+                    g_free(tmp_content);
                 } else {
-                    pcapng_debug1("pcapng_read_if_descr_block: opt_comment length %u seems strange", oh.option_length);
+                    pcapng_debug("pcapng_read_if_descr_block: opt_comment length %u seems strange", oh.option_length);
                 }
                 break;
-            case(2): /* if_name */
+            case(OPT_IDB_NAME): /* if_name */
                 if (oh.option_length > 0 && oh.option_length < opt_cont_buf_len) {
-                    wblock->data.if_descr.if_name = g_strndup(option_content, oh.option_length);
-                    pcapng_debug1("pcapng_read_if_descr_block: if_name %s", wblock->data.if_descr.if_name);
+                    tmp_content = g_strndup((char *)option_content, oh.option_length);
+                    /* Fails with multiple options; we silently ignore the failure */
+                    wtap_block_add_string_option(wblock->block, oh.option_code, option_content, oh.option_length);
+                    pcapng_debug("pcapng_read_if_descr_block: if_name %s", tmp_content);
+                    g_free(tmp_content);
                 } else {
-                    pcapng_debug1("pcapng_read_if_descr_block: if_name length %u seems strange", oh.option_length);
+                    pcapng_debug("pcapng_read_if_descr_block: if_name length %u seems strange", oh.option_length);
                 }
                 break;
-            case(3): /* if_description */
+            case(OPT_IDB_DESCR): /* if_description */
                 if (oh.option_length > 0 && oh.option_length < opt_cont_buf_len) {
-                    wblock->data.if_descr.if_description = g_strndup(option_content, oh.option_length);
-                    pcapng_debug1("pcapng_read_if_descr_block: if_description %s", wblock->data.if_descr.if_description);
+                    tmp_content = g_strndup((char *)option_content, oh.option_length);
+                    /* Fails with multiple options; we silently ignore the failure */
+                    wtap_block_add_string_option(wblock->block, oh.option_code, option_content, oh.option_length);
+                    pcapng_debug("pcapng_read_if_descr_block: if_description %s", tmp_content);
+                    g_free(tmp_content);
                 } else {
-                    pcapng_debug1("pcapng_read_if_descr_block: if_description length %u seems strange", oh.option_length);
+                    pcapng_debug("pcapng_read_if_descr_block: if_description length %u seems strange", oh.option_length);
                 }
                 break;
-                /*
-                 * if_IPv4addr    4  Interface network address and netmask. This option can be repeated multiple times within the same Interface Description Block when multiple IPv4 addresses are assigned to the interface. 192 168 1 1 255 255 255 0
-                 * if_IPv6addr    5  Interface network address and prefix length (stored in the last byte). This option can be repeated multiple times within the same Interface Description Block when multiple IPv6 addresses are assigned to the interface. 2001:0db8:85a3:08d3:1319:8a2e:0370:7344/64 is written (in hex) as "20 01 0d b8 85 a3 08 d3 13 19 8a 2e 03 70 73 44 40"
-                 * if_MACaddr     6  Interface Hardware MAC address (48 bits). 00 01 02 03 04 05
-                 * if_EUIaddr     7  Interface Hardware EUI address (64 bits), if available. TODO: give a good example
-                 */
-            case(8): /* if_speed */
+            case(OPT_IDB_SPEED): /* if_speed */
                 if (oh.option_length == 8) {
-                    /*  Don't cast a char[] into a guint64--the
-                     *  char[] may not be aligned correctly.
+                    /*  Don't cast a guint8 * into a guint64 *--the
+                     *  guint8 * may not point to something that's
+                     *  aligned correctly.
                      */
-                    memcpy(&wblock->data.if_descr.if_speed, option_content, sizeof(guint64));
+                    memcpy(&tmp64, option_content, sizeof(guint64));
                     if (pn->byte_swapped)
-                        wblock->data.if_descr.if_speed = GUINT64_SWAP_LE_BE(wblock->data.if_descr.if_speed);
-                    pcapng_debug1("pcapng_read_if_descr_block: if_speed %" G_GINT64_MODIFIER "u (bps)", wblock->data.if_descr.if_speed);
+                        tmp64 = GUINT64_SWAP_LE_BE(tmp64);
+                    /* Fails with multiple options; we silently ignore the failure */
+                    wtap_block_add_uint64_option(wblock->block, oh.option_code, tmp64);
+                    pcapng_debug("pcapng_read_if_descr_block: if_speed %" G_GINT64_MODIFIER "u (bps)", tmp64);
                 } else {
-                    pcapng_debug1("pcapng_read_if_descr_block: if_speed length %u not 8 as expected", oh.option_length);
+                    pcapng_debug("pcapng_read_if_descr_block: if_speed length %u not 8 as expected", oh.option_length);
                 }
                 break;
-            case(9): /* if_tsresol */
+            case(OPT_IDB_TSRESOL): /* if_tsresol */
                 if (oh.option_length == 1) {
                     guint64 base;
                     guint64 result;
@@ -881,10 +868,11 @@ pcapng_read_if_descr_block(wtap *wth, FILE_T fh, pcapng_block_header_t *bh,
                         time_units_per_second = G_MAXUINT64;
                     }
                     if (time_units_per_second > (((guint64)1) << 32)) {
-                        pcapng_debug0("pcapng_open: time conversion might be inaccurate");
+                        pcapng_debug("pcapng_open: time conversion might be inaccurate");
                     }
-                    wblock->data.if_descr.time_units_per_second = time_units_per_second;
-                    wblock->data.if_descr.if_tsresol = if_tsresol;
+                    if_descr_mand->time_units_per_second = time_units_per_second;
+                    /* Fails with multiple options; we silently ignore the failure */
+                    wtap_block_add_uint8_option(wblock->block, oh.option_code, if_tsresol);
                     if (time_units_per_second >= 1000000000)
                         tsprecision = WTAP_TSPREC_NSEC;
                     else if (time_units_per_second >= 1000000)
@@ -897,63 +885,122 @@ pcapng_read_if_descr_block(wtap *wth, FILE_T fh, pcapng_block_header_t *bh,
                         tsprecision = WTAP_TSPREC_DSEC;
                     else
                         tsprecision = WTAP_TSPREC_SEC;
-                    wblock->data.if_descr.tsprecision = tsprecision;
-                    pcapng_debug3("pcapng_read_if_descr_block: if_tsresol %u, units/s %" G_GINT64_MODIFIER "u, tsprecision %d", wblock->data.if_descr.if_tsresol, wblock->data.if_descr.time_units_per_second, tsprecision);
+                    if_descr_mand->tsprecision = tsprecision;
+                    pcapng_debug("pcapng_read_if_descr_block: if_tsresol %u, units/s %" G_GINT64_MODIFIER "u, tsprecision %d", if_tsresol, if_descr_mand->time_units_per_second, tsprecision);
                 } else {
-                    pcapng_debug1("pcapng_read_if_descr_block: if_tsresol length %u not 1 as expected", oh.option_length);
+                    pcapng_debug("pcapng_read_if_descr_block: if_tsresol length %u not 1 as expected", oh.option_length);
                 }
                 break;
                 /*
                  * if_tzone      10  Time zone for GMT support (TODO: specify better). TODO: give a good example
                  */
-            case(11): /* if_filter */
+            case(OPT_IDB_FILTER): /* if_filter */
                 if (oh.option_length > 0 && oh.option_length < opt_cont_buf_len) {
+                    wtapng_if_descr_filter_t if_filter;
+                    memset(&if_filter, 0, sizeof(if_filter));
+
                     /* The first byte of the Option Data keeps a code of the filter used (e.g. if this is a libpcap string,
                      * or BPF bytecode.
                      */
                     if (option_content[0] == 0) {
-                        wblock->data.if_descr.if_filter_str = g_strndup(option_content+1, oh.option_length-1);
-                        pcapng_debug2("pcapng_read_if_descr_block: if_filter_str %s oh.option_length %u", wblock->data.if_descr.if_filter_str, oh.option_length);
+                        if_filter.if_filter_str = g_strndup((char *)option_content+1, oh.option_length-1);
+                        pcapng_debug("pcapng_read_if_descr_block: if_filter_str %s oh.option_length %u", if_filter.if_filter_str, oh.option_length);
                     } else if (option_content[0] == 1) {
-                        wblock->data.if_descr.bpf_filter_len = oh.option_length-1;
-                        wblock->data.if_descr.if_filter_bpf_bytes = (gchar *)g_malloc(oh.option_length-1);
-                        memcpy(&wblock->data.if_descr.if_filter_bpf_bytes, option_content+1, oh.option_length-1);
+                        if_filter.bpf_filter_len = oh.option_length-1;
+                        if_filter.if_filter_bpf_bytes = (guint8 *)option_content+1;
                     }
+                    /* Fails with multiple options; we silently ignore the failure */
+                    wtap_block_add_custom_option(wblock->block, oh.option_code, &if_filter, sizeof if_filter);
+                    g_free(if_filter.if_filter_str);
                 } else {
-                    pcapng_debug1("pcapng_read_if_descr_block: if_filter length %u seems strange", oh.option_length);
+                    pcapng_debug("pcapng_read_if_descr_block: if_filter length %u seems strange", oh.option_length);
                 }
                 break;
-            case(12): /* if_os */
+            case(OPT_IDB_OS): /* if_os */
                 /*
                  * if_os         12  A UTF-8 string containing the name of the operating system of the machine in which this interface is installed.
                  * This can be different from the same information that can be contained by the Section Header Block (Section 3.1 (Section Header Block (mandatory)))
                  * because the capture can have been done on a remote machine. "Windows XP SP2" / "openSUSE 10.2" / ...
                  */
                 if (oh.option_length > 0 && oh.option_length < opt_cont_buf_len) {
-                    wblock->data.if_descr.if_os = g_strndup(option_content, oh.option_length);
-                    pcapng_debug1("pcapng_read_if_descr_block: if_os %s", wblock->data.if_descr.if_os);
+                    tmp_content = g_strndup((char *)option_content, oh.option_length);
+                    /* Fails with multiple options; we silently ignore the failure */
+                    wtap_block_add_string_option(wblock->block, oh.option_code, option_content, oh.option_length);
+                    pcapng_debug("pcapng_read_if_descr_block: if_os %s", tmp_content);
+                    g_free(tmp_content);
                 } else {
-                    pcapng_debug1("pcapng_read_if_descr_block: if_os length %u seems strange", oh.option_length);
+                    pcapng_debug("pcapng_read_if_descr_block: if_os length %u seems strange", oh.option_length);
                 }
                 break;
-            case(13): /* if_fcslen */
+            case(OPT_IDB_FCSLEN): /* if_fcslen */
                 if (oh.option_length == 1) {
-                    wblock->data.if_descr.if_fcslen = option_content[0];
-                    pn->if_fcslen = wblock->data.if_descr.if_fcslen;
-                    pcapng_debug1("pcapng_read_if_descr_block: if_fcslen %u", wblock->data.if_descr.if_fcslen);
+                    /* Fails with multiple options; we silently ignore the failure */
+                    wtap_block_add_uint8_option(wblock->block, oh.option_code, option_content[0]);
+                    pn->if_fcslen = option_content[0];
+                    pcapng_debug("pcapng_read_if_descr_block: if_fcslen %u", pn->if_fcslen);
                     /* XXX - add sanity check */
                 } else {
-                    pcapng_debug1("pcapng_read_if_descr_block: if_fcslen length %u not 1 as expected", oh.option_length);
+                    pcapng_debug("pcapng_read_if_descr_block: if_fcslen length %u not 1 as expected", oh.option_length);
+                }
+                break;
+            case(OPT_IDB_HARDWARE): /* if_hardware */
+                if (oh.option_length > 0 && oh.option_length < opt_cont_buf_len) {
+                    tmp_content = g_strndup((char *)option_content, oh.option_length);
+                    /* Fails with multiple options; we silently ignore the failure */
+                    wtap_block_add_string_option(wblock->block, oh.option_code, option_content, oh.option_length);
+                    pcapng_debug("pcapng_read_if_descr_block: if_hardware %s", tmp_content);
+                    g_free(tmp_content);
+                } else {
+                    pcapng_debug("pcapng_read_if_descr_block: if_description length %u seems strange", oh.option_length);
                 }
                 break;
+
+            /* TODO: process these! */
+            case(OPT_IDB_IP4ADDR):
+                /*
+                 * Interface network address and netmask. This option can be
+                 * repeated multiple times within the same Interface
+                 * Description Block when multiple IPv4 addresses are assigned
+                 * to the interface. 192 168 1 1 255 255 255 0
+                 */
+            case(OPT_IDB_IP6ADDR):
+                /*
+                 * Interface network address and prefix length (stored in the
+                 * last byte). This option can be repeated multiple times
+                 * within the same Interface Description Block when multiple
+                 * IPv6 addresses are assigned to the interface.
+                 * 2001:0db8:85a3:08d3:1319:8a2e:0370:7344/64 is written (in
+                 * hex) as "20 01 0d b8 85 a3 08 d3 13 19 8a 2e 03 70 73 44
+                 * 40"
+                 */
+            case(OPT_IDB_MACADDR):
+                /*
+                 * Interface Hardware MAC address (48 bits). 00 01 02 03 04 05
+                 */
+            case(OPT_IDB_EUIADDR):
+                /*
+                 * Interface Hardware EUI address (64 bits), if available.
+                 * TODO: give a good example
+                 */
+            case(OPT_IDB_TZONE):
+                /*
+                 * Time zone for GMT support. TODO: specify better.
+                 * TODO: give a good example.
+                 */
+            case(OPT_IDB_TSOFFSET):
                 /*
-                 * if_tsoffset   14  A 64 bits integer value that specifies an offset (in seconds) that must be added to the timestamp of each packet
-                 * to obtain the absolute timestamp of a packet. If the option is missing, the timestamps stored in the packet must be considered absolute timestamps.
-                 * The time zone of the offset can be specified with the option if_tzone.
-                 * TODO: won't a if_tsoffset_low for fractional second offsets be useful for highly synchronized capture systems? 1234
+                 * A 64 bits integer value that specifies an offset (in
+                 * seconds) that must be added to the timestamp of each packet
+                 * to obtain the absolute timestamp of a packet. If the option
+                 * is missing, the timestamps stored in the packet must be
+                 * considered absolute timestamps. The time zone of the offset
+                 * can be specified with the option if_tzone.
+                 *
+                 * TODO: won't a if_tsoffset_low for fractional second offsets
+                 * be useful for highly synchronized capture systems? 1234
                  */
             default:
-                pcapng_debug2("pcapng_read_if_descr_block: unknown option %u - ignoring %u bytes",
+                pcapng_debug("pcapng_read_if_descr_block: unknown option %u - ignoring %u bytes",
                               oh.option_code, oh.option_length);
         }
     }
@@ -971,9 +1018,9 @@ pcapng_read_if_descr_block(wtap *wth, FILE_T fh, pcapng_block_header_t *bh,
      * packets in the file.
      */
     if (wth->file_encap == WTAP_ENCAP_UNKNOWN) {
-        wth->file_encap = wblock->data.if_descr.wtap_encap;
+        wth->file_encap = if_descr_mand->wtap_encap;
     } else {
-        if (wth->file_encap != wblock->data.if_descr.wtap_encap) {
+        if (wth->file_encap != if_descr_mand->wtap_encap) {
             wth->file_encap = WTAP_ENCAP_PER_PACKET;
         }
     }
@@ -982,18 +1029,23 @@ pcapng_read_if_descr_block(wtap *wth, FILE_T fh, pcapng_block_header_t *bh,
      * The same applies to the per-file time stamp resolution.
      */
     if (wth->file_tsprec == WTAP_TSPREC_UNKNOWN) {
-        wth->file_tsprec = wblock->data.if_descr.tsprecision;
+        wth->file_tsprec = if_descr_mand->tsprecision;
     } else {
-        if (wth->file_tsprec != wblock->data.if_descr.tsprecision) {
+        if (wth->file_tsprec != if_descr_mand->tsprecision) {
             wth->file_tsprec = WTAP_TSPREC_PER_PACKET;
         }
     }
 
-    return block_read;
+    /*
+     * We don't return these to the caller in pcapng_read().
+     */
+    wblock->internal = TRUE;
+
+    return TRUE;
 }
 
 
-static int
+static gboolean
 pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wtapng_block_t *wblock, int *err, gchar **err_info, gboolean enhanced)
 {
     int bytes_read;
@@ -1006,25 +1058,14 @@ pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wta
     guint32 padding;
     interface_info_t iface_info;
     guint64 ts;
-    pcapng_option_header_t oh;
+    guint8 *opt_ptr;
+    pcapng_option_header_t *oh;
+    guint8 *option_content;
     int pseudo_header_len;
-    char *option_content = NULL; /* Allocate as large as the options block */
     int fcslen;
-
-    /* Don't try to allocate memory for a huge number of options, as
-       that might fail and, even if it succeeds, it might not leave
-       any address space or memory+backing store for anything else.
-
-       We do that by imposing a maximum block size of MAX_BLOCK_SIZE.
-       We check for this *after* checking the SHB for its byte
-       order magic number, so that non-pcap-ng files are less
-       likely to be treated as bad pcap-ng files. */
-    if (bh->block_total_length > MAX_BLOCK_SIZE) {
-        *err = WTAP_ERR_BAD_FILE;
-        *err_info = g_strdup_printf("pcapng: total block length %u is too large (> %u)",
-                                    bh->block_total_length, MAX_BLOCK_SIZE);
-        return -1;
-    }
+#ifdef HAVE_PLUGINS
+    option_handler *handler;
+#endif
 
     /* "(Enhanced) Packet Block" read fixed part */
     if (enhanced) {
@@ -1038,11 +1079,11 @@ pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wta
             *err = WTAP_ERR_BAD_FILE;
             *err_info = g_strdup_printf("pcapng_read_packet_block: total block length %u of an EPB is less than the minimum EPB size %u",
                                         bh->block_total_length, MIN_EPB_SIZE);
-            return -1;
+            return FALSE;
         }
         if (!wtap_read_bytes(fh, &epb, sizeof epb, err, err_info)) {
-            pcapng_debug0("pcapng_read_packet_block: failed to read packet data");
-            return -1;
+            pcapng_debug("pcapng_read_packet_block: failed to read packet data");
+            return FALSE;
         }
         block_read = (guint)sizeof epb;
 
@@ -1061,7 +1102,7 @@ pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wta
             packet.cap_len             = epb.captured_len;
             packet.packet_len          = epb.packet_len;
         }
-        pcapng_debug3("pcapng_read_packet_block: EPB on interface_id %d, cap_len %d, packet_len %d",
+        pcapng_debug("pcapng_read_packet_block: EPB on interface_id %d, cap_len %d, packet_len %d",
                       packet.interface_id, packet.cap_len, packet.packet_len);
     } else {
         /*
@@ -1074,11 +1115,11 @@ pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wta
             *err = WTAP_ERR_BAD_FILE;
             *err_info = g_strdup_printf("pcapng_read_packet_block: total block length %u of a PB is less than the minimum PB size %u",
                                         bh->block_total_length, MIN_PB_SIZE);
-            return -1;
+            return FALSE;
         }
         if (!wtap_read_bytes(fh, &pb, sizeof pb, err, err_info)) {
-            pcapng_debug0("pcapng_read_packet_block: failed to read packet data");
-            return -1;
+            pcapng_debug("pcapng_read_packet_block: failed to read packet data");
+            return FALSE;
         }
         block_read = (guint)sizeof pb;
 
@@ -1097,7 +1138,7 @@ pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wta
             packet.cap_len             = pb.captured_len;
             packet.packet_len          = pb.packet_len;
         }
-        pcapng_debug3("pcapng_read_packet_block: PB on interface_id %d, cap_len %d, packet_len %d",
+        pcapng_debug("pcapng_read_packet_block: PB on interface_id %d, cap_len %d, packet_len %d",
                       packet.interface_id, packet.cap_len, packet.packet_len);
     }
 
@@ -1116,7 +1157,7 @@ pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wta
     } else {
         block_total_length = bh->block_total_length;
     }
-    pcapng_debug1("pcapng_read_packet_block: block_total_length %d", block_total_length);
+    pcapng_debug("pcapng_read_packet_block: block_total_length %d", block_total_length);
 
     /*
      * Is this block long enough to hold the packet data?
@@ -1130,7 +1171,7 @@ pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wta
             *err = WTAP_ERR_BAD_FILE;
             *err_info = g_strdup_printf("pcapng_read_packet_block: total block length %u of EPB is too small for %u bytes of packet data",
                                         block_total_length, packet.cap_len);
-            return -1;
+            return FALSE;
         }
     } else {
         if (block_total_length <
@@ -1141,83 +1182,80 @@ pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wta
             *err = WTAP_ERR_BAD_FILE;
             *err_info = g_strdup_printf("pcapng_read_packet_block: total block length %u of PB is too small for %u bytes of packet data",
                                         block_total_length, packet.cap_len);
-            return -1;
+            return FALSE;
         }
     }
 
-    if (packet.cap_len > WTAP_MAX_PACKET_SIZE) {
-        *err = WTAP_ERR_BAD_FILE;
-        *err_info = g_strdup_printf("pcapng_read_packet_block: cap_len %u is larger than WTAP_MAX_PACKET_SIZE %u",
-                                    packet.cap_len, WTAP_MAX_PACKET_SIZE);
-        return -1;
-    }
-    pcapng_debug3("pcapng_read_packet_block: packet data: packet_len %u captured_len %u interface_id %u",
+    pcapng_debug("pcapng_read_packet_block: packet data: packet_len %u captured_len %u interface_id %u",
                   packet.packet_len,
                   packet.cap_len,
                   packet.interface_id);
 
     if (packet.interface_id >= pn->interfaces->len) {
         *err = WTAP_ERR_BAD_FILE;
-        *err_info = g_strdup_printf("pcapng: interface index %u is not less than interface count %u",
+        *err_info = g_strdup_printf("pcapng_read_packet_block: interface index %u is not less than interface count %u",
                                     packet.interface_id, pn->interfaces->len);
-        return -1;
+        return FALSE;
     }
     iface_info = g_array_index(pn->interfaces, interface_info_t,
                                packet.interface_id);
 
-    wblock->packet_header->rec_type = REC_TYPE_PACKET;
-    wblock->packet_header->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN|WTAP_HAS_INTERFACE_ID;
+    if (packet.cap_len > wtap_max_snaplen_for_encap(iface_info.wtap_encap)) {
+        *err = WTAP_ERR_BAD_FILE;
+        *err_info = g_strdup_printf("pcapng_read_packet_block: cap_len %u is larger than %u",
+                                    packet.cap_len,
+                                    wtap_max_snaplen_for_encap(iface_info.wtap_encap));
+        return FALSE;
+    }
+
+    wblock->rec->rec_type = REC_TYPE_PACKET;
+    wblock->rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN|WTAP_HAS_INTERFACE_ID;
 
-    pcapng_debug3("pcapng_read_packet_block: encapsulation = %d (%s), pseudo header size = %d.",
+    pcapng_debug("pcapng_read_packet_block: encapsulation = %d (%s), pseudo header size = %d.",
                   iface_info.wtap_encap,
                   wtap_encap_string(iface_info.wtap_encap),
-                  pcap_get_phdr_size(iface_info.wtap_encap, &wblock->packet_header->pseudo_header));
-    wblock->packet_header->interface_id = packet.interface_id;
-    wblock->packet_header->pkt_encap = iface_info.wtap_encap;
-    wblock->packet_header->pkt_tsprec = iface_info.tsprecision;
+                  pcap_get_phdr_size(iface_info.wtap_encap, &wblock->rec->rec_header.packet_header.pseudo_header));
+    wblock->rec->rec_header.packet_header.interface_id = packet.interface_id;
+    wblock->rec->rec_header.packet_header.pkt_encap = iface_info.wtap_encap;
+    wblock->rec->tsprec = iface_info.tsprecision;
 
-    memset((void *)&wblock->packet_header->pseudo_header, 0, sizeof(union wtap_pseudo_header));
+    memset((void *)&wblock->rec->rec_header.packet_header.pseudo_header, 0, sizeof(union wtap_pseudo_header));
     pseudo_header_len = pcap_process_pseudo_header(fh,
                                                    WTAP_FILE_TYPE_SUBTYPE_PCAPNG,
                                                    iface_info.wtap_encap,
                                                    packet.cap_len,
-                                                   TRUE,
-                                                   wblock->packet_header,
+                                                   wblock->rec,
                                                    err,
                                                    err_info);
     if (pseudo_header_len < 0) {
-        return pseudo_header_len;
+        return FALSE;
     }
     block_read += pseudo_header_len;
-    if (pseudo_header_len != pcap_get_phdr_size(iface_info.wtap_encap, &wblock->packet_header->pseudo_header)) {
-        pcapng_debug1("pcapng_read_packet_block: Could only read %d bytes for pseudo header.",
-                      pseudo_header_len);
-    }
-    wblock->packet_header->caplen = packet.cap_len - pseudo_header_len;
-    wblock->packet_header->len = packet.packet_len - pseudo_header_len;
+    wblock->rec->rec_header.packet_header.caplen = packet.cap_len - pseudo_header_len;
+    wblock->rec->rec_header.packet_header.len = packet.packet_len - pseudo_header_len;
 
     /* Combine the two 32-bit pieces of the timestamp into one 64-bit value */
     ts = (((guint64)packet.ts_high) << 32) | ((guint64)packet.ts_low);
-    wblock->packet_header->ts.secs = (time_t)(ts / iface_info.time_units_per_second);
-    wblock->packet_header->ts.nsecs = (int)(((ts % iface_info.time_units_per_second) * 1000000000) / iface_info.time_units_per_second);
+    wblock->rec->ts.secs = (time_t)(ts / iface_info.time_units_per_second);
+    wblock->rec->ts.nsecs = (int)(((ts % iface_info.time_units_per_second) * 1000000000) / iface_info.time_units_per_second);
 
     /* "(Enhanced) Packet Block" read capture data */
     if (!wtap_read_packet_bytes(fh, wblock->frame_buffer,
                                 packet.cap_len - pseudo_header_len, err, err_info))
-        return -1;
+        return FALSE;
     block_read += packet.cap_len - pseudo_header_len;
 
     /* jump over potential padding bytes at end of the packet data */
     if (padding != 0) {
-        if (!file_skip(fh, padding, err))
-            return -1;
+        if (!wtap_read_bytes(fh, NULL, padding, err, err_info))
+            return FALSE;
         block_read += padding;
     }
 
     /* Option defaults */
-    wblock->packet_header->opt_comment = NULL;
-    wblock->packet_header->drop_count  = -1;
-    wblock->packet_header->pack_flags  = 0;
+    wblock->rec->opt_comment = NULL;
+    wblock->rec->rec_header.packet_header.drop_count  = -1;
+    wblock->rec->rec_header.packet_header.pack_flags  = 0;
 
     /* FCS length default */
     fcslen = pn->if_fcslen;
@@ -1235,96 +1273,126 @@ pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wta
 
     /* Allocate enough memory to hold all options */
     opt_cont_buf_len = to_read;
-    option_content = (char *)g_try_malloc(opt_cont_buf_len);
-    if (opt_cont_buf_len != 0 && option_content == NULL) {
-        *err = ENOMEM;  /* we assume we're out of memory */
-        return -1;
-    }
+    ws_buffer_assure_space(&wblock->rec->options_buf, opt_cont_buf_len);
+    opt_ptr = ws_buffer_start_ptr(&wblock->rec->options_buf);
 
     while (to_read != 0) {
         /* read option */
-        bytes_read = pcapng_read_option(fh, pn, &oh, option_content, opt_cont_buf_len, to_read, err, err_info);
+        oh = (pcapng_option_header_t *)(void *)opt_ptr;
+        option_content = opt_ptr + sizeof (pcapng_option_header_t);
+        bytes_read = pcapng_read_option(fh, pn, oh, option_content, opt_cont_buf_len, to_read, err, err_info, "packet");
         if (bytes_read <= 0) {
-            pcapng_debug0("pcapng_read_packet_block: failed to read option");
-            return bytes_read;
+            pcapng_debug("pcapng_read_packet_block: failed to read option");
+            /* XXX - free anything? */
+            return FALSE;
         }
-        block_read += bytes_read;
         to_read -= bytes_read;
 
         /* handle option content */
-        switch (oh.option_code) {
+        switch (oh->option_code) {
             case(OPT_EOFOPT):
                 if (to_read != 0) {
-                    pcapng_debug1("pcapng_read_packet_block: %u bytes after opt_endofopt", to_read);
+                    pcapng_debug("pcapng_read_packet_block: %u bytes after opt_endofopt", to_read);
                 }
                 /* padding should be ok here, just get out of this */
                 to_read = 0;
                 break;
             case(OPT_COMMENT):
-                if (oh.option_length > 0 && oh.option_length < opt_cont_buf_len) {
-                    wblock->packet_header->presence_flags |= WTAP_HAS_COMMENTS;
-                    wblock->packet_header->opt_comment = g_strndup(option_content, oh.option_length);
-                    pcapng_debug2("pcapng_read_packet_block: length %u opt_comment '%s'", oh.option_length, wblock->packet_header->opt_comment);
+                if (oh->option_length > 0 && oh->option_length < opt_cont_buf_len) {
+                    wblock->rec->presence_flags |= WTAP_HAS_COMMENTS;
+                    wblock->rec->opt_comment = g_strndup((char *)option_content, oh->option_length);
+                    pcapng_debug("pcapng_read_packet_block: length %u opt_comment '%s'", oh->option_length, wblock->rec->opt_comment);
                 } else {
-                    pcapng_debug1("pcapng_read_packet_block: opt_comment length %u seems strange", oh.option_length);
+                    pcapng_debug("pcapng_read_packet_block: opt_comment length %u seems strange", oh->option_length);
                 }
                 break;
             case(OPT_EPB_FLAGS):
-                if (oh.option_length == 4) {
-                    /*  Don't cast a char[] into a guint32--the
-                     *  char[] may not be aligned correctly.
-                     */
-                    wblock->packet_header->presence_flags |= WTAP_HAS_PACK_FLAGS;
-                    memcpy(&wblock->packet_header->pack_flags, option_content, sizeof(guint32));
-                    if (pn->byte_swapped)
-                        wblock->packet_header->pack_flags = GUINT32_SWAP_LE_BE(wblock->packet_header->pack_flags);
-                    if (wblock->packet_header->pack_flags & 0x000001E0) {
-                        /* The FCS length is present */
-                        fcslen = (wblock->packet_header->pack_flags & 0x000001E0) >> 5;
-                    }
-                    pcapng_debug1("pcapng_read_packet_block: pack_flags %u (ignored)", wblock->packet_header->pack_flags);
-                } else {
-                    pcapng_debug1("pcapng_read_packet_block: pack_flags length %u not 4 as expected", oh.option_length);
+                if (oh->option_length != 4) {
+                    *err = WTAP_ERR_BAD_FILE;
+                    *err_info = g_strdup_printf("pcapng_read_packet_block: packet block flags option length %u is not 4",
+                                                oh->option_length);
+                    /* XXX - free anything? */
+                    return FALSE;
+                }
+                /*  Don't cast a guint8 * into a guint32 *--the
+                 *  guint8 * may not point to something that's
+                 *  aligned correctly.
+                 */
+                wblock->rec->presence_flags |= WTAP_HAS_PACK_FLAGS;
+                memcpy(&wblock->rec->rec_header.packet_header.pack_flags, option_content, sizeof(guint32));
+                if (pn->byte_swapped) {
+                    wblock->rec->rec_header.packet_header.pack_flags = GUINT32_SWAP_LE_BE(wblock->rec->rec_header.packet_header.pack_flags);
+                    memcpy(option_content, &wblock->rec->rec_header.packet_header.pack_flags, sizeof(guint32));
+                }
+                if (wblock->rec->rec_header.packet_header.pack_flags & 0x000001E0) {
+                    /* The FCS length is present */
+                    fcslen = (wblock->rec->rec_header.packet_header.pack_flags & 0x000001E0) >> 5;
                 }
+                pcapng_debug("pcapng_read_packet_block: pack_flags %u (ignored)", wblock->rec->rec_header.packet_header.pack_flags);
                 break;
             case(OPT_EPB_HASH):
-                pcapng_debug2("pcapng_read_packet_block: epb_hash %u currently not handled - ignoring %u bytes",
-                              oh.option_code, oh.option_length);
+                pcapng_debug("pcapng_read_packet_block: epb_hash %u currently not handled - ignoring %u bytes",
+                              oh->option_code, oh->option_length);
                 break;
             case(OPT_EPB_DROPCOUNT):
-                if (oh.option_length == 8) {
-                    /*  Don't cast a char[] into a guint32--the
-                     *  char[] may not be aligned correctly.
-                     */
-                    wblock->packet_header->presence_flags |= WTAP_HAS_DROP_COUNT;
-                    memcpy(&wblock->packet_header->drop_count, option_content, sizeof(guint64));
-                    if (pn->byte_swapped)
-                        wblock->packet_header->drop_count = GUINT64_SWAP_LE_BE(wblock->packet_header->drop_count);
-
-                    pcapng_debug1("pcapng_read_packet_block: drop_count %" G_GINT64_MODIFIER "u", wblock->packet_header->drop_count);
-                } else {
-                    pcapng_debug1("pcapng_read_packet_block: drop_count length %u not 8 as expected", oh.option_length);
+                if (oh->option_length != 8) {
+                    *err = WTAP_ERR_BAD_FILE;
+                    *err_info = g_strdup_printf("pcapng_read_packet_block: packet block drop count option length %u is not 8",
+                                                oh->option_length);
+                    /* XXX - free anything? */
+                    return FALSE;
+                }
+                /*  Don't cast a guint8 * into a guint64 *--the
+                 *  guint8 * may not point to something that's
+                 *  aligned correctly.
+                 */
+                wblock->rec->presence_flags |= WTAP_HAS_DROP_COUNT;
+                memcpy(&wblock->rec->rec_header.packet_header.drop_count, option_content, sizeof(guint64));
+                if (pn->byte_swapped) {
+                    wblock->rec->rec_header.packet_header.drop_count = GUINT64_SWAP_LE_BE(wblock->rec->rec_header.packet_header.drop_count);
+                    memcpy(option_content, &wblock->rec->rec_header.packet_header.drop_count, sizeof(guint64));
                 }
+
+                pcapng_debug("pcapng_read_packet_block: drop_count %" G_GINT64_MODIFIER "u", wblock->rec->rec_header.packet_header.drop_count);
                 break;
             default:
-                pcapng_debug2("pcapng_read_packet_block: unknown option %u - ignoring %u bytes",
-                              oh.option_code, oh.option_length);
+#ifdef HAVE_PLUGINS
+                /*
+                 * Do we have a handler for this packet block option code?
+                 */
+                if (option_handlers[BT_INDEX_PBS] != NULL &&
+                    (handler = (option_handler *)g_hash_table_lookup(option_handlers[BT_INDEX_PBS],
+                                                                   GUINT_TO_POINTER((guint)oh->option_code))) != NULL) {
+                    /* Yes - call the handler. */
+                    if (!handler->hfunc(pn->byte_swapped, oh->option_length,
+                                 option_content, err, err_info))
+                        /* XXX - free anything? */
+                        return FALSE;
+                } else
+#endif
+                {
+                    pcapng_debug("pcapng_read_packet_block: unknown option %u - ignoring %u bytes",
+                                  oh->option_code, oh->option_length);
+                }
         }
     }
 
-    g_free(option_content);
-
     pcap_read_post_process(WTAP_FILE_TYPE_SUBTYPE_PCAPNG, iface_info.wtap_encap,
-                           wblock->packet_header, ws_buffer_start_ptr(wblock->frame_buffer),
+                           wblock->rec, ws_buffer_start_ptr(wblock->frame_buffer),
                            pn->byte_swapped, fcslen);
-    return block_read;
+
+    /*
+     * We return these to the caller in pcapng_read().
+     */
+    wblock->internal = FALSE;
+
+    return TRUE;
 }
 
 
-static int
+static gboolean
 pcapng_read_simple_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wtapng_block_t *wblock, int *err, gchar **err_info)
 {
-    guint block_read;
     interface_info_t iface_info;
     pcapng_simple_packet_block_t spb;
     wtapng_simple_packet_t simple_packet;
@@ -1342,35 +1410,19 @@ pcapng_read_simple_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *
         *err = WTAP_ERR_BAD_FILE;
         *err_info = g_strdup_printf("pcapng_read_simple_packet_block: total block length %u of an SPB is less than the minimum SPB size %u",
                                     bh->block_total_length, MIN_SPB_SIZE);
-        return -1;
-    }
-
-    /* Don't try to allocate memory for a huge number of options, as
-       that might fail and, even if it succeeds, it might not leave
-       any address space or memory+backing store for anything else.
-
-       We do that by imposing a maximum block size of MAX_BLOCK_SIZE.
-       We check for this *after* checking the SHB for its byte
-       order magic number, so that non-pcap-ng files are less
-       likely to be treated as bad pcap-ng files. */
-    if (bh->block_total_length > MAX_BLOCK_SIZE) {
-        *err = WTAP_ERR_BAD_FILE;
-        *err_info = g_strdup_printf("pcapng: total block length %u is too large (> %u)",
-                                    bh->block_total_length, MAX_BLOCK_SIZE);
-        return -1;
+        return FALSE;
     }
 
     /* "Simple Packet Block" read fixed part */
     if (!wtap_read_bytes(fh, &spb, sizeof spb, err, err_info)) {
-        pcapng_debug0("pcapng_read_simple_packet_block: failed to read packet data");
-        return -1;
+        pcapng_debug("pcapng_read_simple_packet_block: failed to read packet data");
+        return FALSE;
     }
-    block_read = (guint)sizeof spb;
 
     if (0 >= pn->interfaces->len) {
         *err = WTAP_ERR_BAD_FILE;
-        *err_info = g_strdup_printf("pcapng: SPB appeared before any IDBs");
-        return -1;
+        *err_info = g_strdup("pcapng_read_simple_packet_block: SPB appeared before any IDBs");
+        return FALSE;
     }
     iface_info = g_array_index(pn->interfaces, interface_info_t, 0);
 
@@ -1383,10 +1435,11 @@ pcapng_read_simple_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *
     /*
      * The captured length is not a field in the SPB; it can be
      * calculated as the minimum of the snapshot length from the
-     * IDB and the packet length, as per the pcap-ng spec.
+     * IDB and the packet length, as per the pcapng spec. An IDB
+     * snapshot length of 0 means no limit.
      */
     simple_packet.cap_len = simple_packet.packet_len;
-    if (simple_packet.cap_len > iface_info.snap_len)
+    if (simple_packet.cap_len > iface_info.snap_len && iface_info.snap_len != 0)
         simple_packet.cap_len = iface_info.snap_len;
 
     /*
@@ -1404,7 +1457,7 @@ pcapng_read_simple_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *
     } else {
         block_total_length = bh->block_total_length;
     }
-    pcapng_debug1("pcapng_read_simple_packet_block: block_total_length %d", block_total_length);
+    pcapng_debug("pcapng_read_simple_packet_block: block_total_length %d", block_total_length);
 
     /*
      * Is this block long enough to hold the packet data?
@@ -1419,73 +1472,72 @@ pcapng_read_simple_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *
         *err = WTAP_ERR_BAD_FILE;
         *err_info = g_strdup_printf("pcapng_read_simple_packet_block: total block length %u of PB is too small for %u bytes of packet data",
                                     block_total_length, simple_packet.packet_len);
-        return -1;
+        return FALSE;
     }
 
-    if (simple_packet.cap_len > WTAP_MAX_PACKET_SIZE) {
+    if (simple_packet.cap_len > wtap_max_snaplen_for_encap(iface_info.wtap_encap)) {
         *err = WTAP_ERR_BAD_FILE;
-        *err_info = g_strdup_printf("pcapng_read_simple_packet_block: cap_len %u is larger than WTAP_MAX_PACKET_SIZE %u",
-                                    simple_packet.cap_len, WTAP_MAX_PACKET_SIZE);
-        return -1;
+        *err_info = g_strdup_printf("pcapng_read_simple_packet_block: cap_len %u is larger than %u",
+                                    simple_packet.cap_len,
+                                    wtap_max_snaplen_for_encap(iface_info.wtap_encap));
+        return FALSE;
     }
-    pcapng_debug1("pcapng_read_simple_packet_block: packet data: packet_len %u",
+    pcapng_debug("pcapng_read_simple_packet_block: packet data: packet_len %u",
                   simple_packet.packet_len);
 
-    pcapng_debug1("pcapng_read_simple_packet_block: Need to read pseudo header of size %d",
-                  pcap_get_phdr_size(iface_info.wtap_encap, &wblock->packet_header->pseudo_header));
+    pcapng_debug("pcapng_read_simple_packet_block: Need to read pseudo header of size %d",
+                  pcap_get_phdr_size(iface_info.wtap_encap, &wblock->rec->rec_header.packet_header.pseudo_header));
 
     /* No time stamp in a simple packet block; no options, either */
-    wblock->packet_header->rec_type = REC_TYPE_PACKET;
-    wblock->packet_header->presence_flags = WTAP_HAS_CAP_LEN|WTAP_HAS_INTERFACE_ID;
-    wblock->packet_header->interface_id = 0;
-    wblock->packet_header->pkt_encap = iface_info.wtap_encap;
-    wblock->packet_header->pkt_tsprec = iface_info.tsprecision;
-    wblock->packet_header->ts.secs = 0;
-    wblock->packet_header->ts.nsecs = 0;
-    wblock->packet_header->interface_id = 0;
-    wblock->packet_header->opt_comment = NULL;
-    wblock->packet_header->drop_count = 0;
-    wblock->packet_header->pack_flags = 0;
-
-    memset((void *)&wblock->packet_header->pseudo_header, 0, sizeof(union wtap_pseudo_header));
+    wblock->rec->rec_type = REC_TYPE_PACKET;
+    wblock->rec->presence_flags = WTAP_HAS_CAP_LEN|WTAP_HAS_INTERFACE_ID;
+    wblock->rec->rec_header.packet_header.interface_id = 0;
+    wblock->rec->rec_header.packet_header.pkt_encap = iface_info.wtap_encap;
+    wblock->rec->tsprec = iface_info.tsprecision;
+    wblock->rec->ts.secs = 0;
+    wblock->rec->ts.nsecs = 0;
+    wblock->rec->rec_header.packet_header.interface_id = 0;
+    wblock->rec->opt_comment = NULL;
+    wblock->rec->rec_header.packet_header.drop_count = 0;
+    wblock->rec->rec_header.packet_header.pack_flags = 0;
+
+    memset((void *)&wblock->rec->rec_header.packet_header.pseudo_header, 0, sizeof(union wtap_pseudo_header));
     pseudo_header_len = pcap_process_pseudo_header(fh,
                                                    WTAP_FILE_TYPE_SUBTYPE_PCAPNG,
                                                    iface_info.wtap_encap,
                                                    simple_packet.cap_len,
-                                                   TRUE,
-                                                   wblock->packet_header,
+                                                   wblock->rec,
                                                    err,
                                                    err_info);
     if (pseudo_header_len < 0) {
-        return pseudo_header_len;
-    }
-    wblock->packet_header->caplen = simple_packet.cap_len - pseudo_header_len;
-    wblock->packet_header->len = simple_packet.packet_len - pseudo_header_len;
-    block_read += pseudo_header_len;
-    if (pseudo_header_len != pcap_get_phdr_size(iface_info.wtap_encap, &wblock->packet_header->pseudo_header)) {
-        pcapng_debug1("pcapng_read_simple_packet_block: Could only read %d bytes for pseudo header.",
-                      pseudo_header_len);
+        return FALSE;
     }
+    wblock->rec->rec_header.packet_header.caplen = simple_packet.cap_len - pseudo_header_len;
+    wblock->rec->rec_header.packet_header.len = simple_packet.packet_len - pseudo_header_len;
 
-    memset((void *)&wblock->packet_header->pseudo_header, 0, sizeof(union wtap_pseudo_header));
+    memset((void *)&wblock->rec->rec_header.packet_header.pseudo_header, 0, sizeof(union wtap_pseudo_header));
 
     /* "Simple Packet Block" read capture data */
     if (!wtap_read_packet_bytes(fh, wblock->frame_buffer,
                                 simple_packet.cap_len, err, err_info))
-        return -1;
-    block_read += simple_packet.cap_len;
+        return FALSE;
 
     /* jump over potential padding bytes at end of the packet data */
     if ((simple_packet.cap_len % 4) != 0) {
-        if (!file_skip(fh, 4 - (simple_packet.cap_len % 4), err))
-            return -1;
-        block_read += 4 - (simple_packet.cap_len % 4);
+        if (!wtap_read_bytes(fh, NULL, 4 - (simple_packet.cap_len % 4), err, err_info))
+            return FALSE;
     }
 
     pcap_read_post_process(WTAP_FILE_TYPE_SUBTYPE_PCAPNG, iface_info.wtap_encap,
-                           wblock->packet_header, ws_buffer_start_ptr(wblock->frame_buffer),
+                           wblock->rec, ws_buffer_start_ptr(wblock->frame_buffer),
                            pn->byte_swapped, pn->if_fcslen);
-    return block_read;
+
+    /*
+     * We return these to the caller in pcapng_read().
+     */
+    wblock->internal = FALSE;
+
+    return TRUE;
 }
 
 #define NRES_ENDOFRECORD 0
@@ -1532,17 +1584,24 @@ name_resolution_block_find_name_end(const char *p, guint record_len, int *err,
     return namelen + 1;
 }
 
-static int
-pcapng_read_name_resolution_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wtapng_block_t *wblock _U_,int *err, gchar **err_info)
+static gboolean
+pcapng_read_name_resolution_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wtapng_block_t *wblockint *err, gchar **err_info)
 {
-    int block_read = 0;
+    int block_read;
     int to_read;
     pcapng_name_resolution_block_t nrb;
     Buffer nrb_rec;
     guint32 v4_addr;
-    guint record_len;
+    guint record_len, opt_cont_buf_len;
     char *namep;
     int namelen;
+    int bytes_read;
+    pcapng_option_header_t oh;
+    guint8 *option_content;
+#ifdef HAVE_PLUGINS
+    option_handler *handler;
+#endif
+    gchar* tmp_content;
 
     /*
      * Is this block long enough to be an NRB?
@@ -1554,33 +1613,24 @@ pcapng_read_name_resolution_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t
         *err = WTAP_ERR_BAD_FILE;
         *err_info = g_strdup_printf("pcapng_read_name_resolution_block: total block length %u of an NRB is less than the minimum NRB size %u",
                                     bh->block_total_length, MIN_NRB_SIZE);
-        return -1;
+        return FALSE;
     }
 
-    /* Don't try to allocate memory for a huge number of options, as
-       that might fail and, even if it succeeds, it might not leave
-       any address space or memory+backing store for anything else.
-
-       We do that by imposing a maximum block size of MAX_BLOCK_SIZE.
-       We check for this *after* checking the SHB for its byte
-       order magic number, so that non-pcap-ng files are less
-       likely to be treated as bad pcap-ng files. */
-    if (bh->block_total_length > MAX_BLOCK_SIZE) {
-        *err = WTAP_ERR_BAD_FILE;
-        *err_info = g_strdup_printf("pcapng: total block length %u is too large (> %u)",
-                                    bh->block_total_length, MAX_BLOCK_SIZE);
-        return -1;
-    }
+    to_read = bh->block_total_length - 8 - 4; /* We have read the header and should not read the final block_total_length */
 
-    to_read = bh->block_total_length - 8 - 4; /* We have read the header adn should not read the final block_total_length */
+    pcapng_debug("pcapng_read_name_resolution_block, total %d bytes", bh->block_total_length);
 
-    pcapng_debug1("pcapng_read_name_resolution_block, total %d bytes", bh->block_total_length);
+    /* Ensure we have a name resolution block */
+    if (wblock->block == NULL) {
+        wblock->block = wtap_block_create(WTAP_BLOCK_NG_NRB);
+    }
 
     /*
      * Start out with a buffer big enough for an IPv6 address and one
      * 64-byte name; we'll make the buffer bigger if necessary.
      */
     ws_buffer_init(&nrb_rec, INITIAL_NRB_REC_SIZE);
+    block_read = 0;
     while (block_read < to_read) {
         /*
          * There must be at least one record's worth of data
@@ -1592,12 +1642,12 @@ pcapng_read_name_resolution_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t
             *err_info = g_strdup_printf("pcapng_read_name_resolution_block: %d bytes left in the block < NRB record header size %u",
                                         to_read - block_read,
                                         (guint)sizeof nrb);
-            return -1;
+            return FALSE;
         }
         if (!wtap_read_bytes(fh, &nrb, sizeof nrb, err, err_info)) {
             ws_buffer_free(&nrb_rec);
-            pcapng_debug0("pcapng_read_name_resolution_block: failed to read record header");
-            return -1;
+            pcapng_debug("pcapng_read_name_resolution_block: failed to read record header");
+            return FALSE;
         }
         block_read += (int)sizeof nrb;
 
@@ -1612,12 +1662,12 @@ pcapng_read_name_resolution_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t
             *err_info = g_strdup_printf("pcapng_read_name_resolution_block: %d bytes left in the block < NRB record length + padding %u",
                                         to_read - block_read,
                                         nrb.record_len + PADDING4(nrb.record_len));
-            return -1;
+            return FALSE;
         }
         switch (nrb.record_type) {
             case NRES_ENDOFRECORD:
-                /* There shouldn't be any more data */
-                to_read = 0;
+                /* There shouldn't be any more data - but there MAY be options */
+                goto read_options;
                 break;
             case NRES_IP4RECORD:
                 /*
@@ -1625,7 +1675,7 @@ pcapng_read_name_resolution_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t
                  * a 4-byte IPv4 address, hence a minimum
                  * of 4 bytes.
                  *
-                 * (The pcap-NG spec really indicates
+                 * (The pcapng spec really indicates
                  * that it must be at least 5 bytes,
                  * as there must be at least one name,
                  * and it really must be at least 6
@@ -1639,14 +1689,14 @@ pcapng_read_name_resolution_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t
                     *err = WTAP_ERR_BAD_FILE;
                     *err_info = g_strdup_printf("pcapng_read_name_resolution_block: NRB record length for IPv4 record %u < minimum length 4",
                                                 nrb.record_len);
-                    return -1;
+                    return FALSE;
                 }
                 ws_buffer_assure_space(&nrb_rec, nrb.record_len);
                 if (!wtap_read_bytes(fh, ws_buffer_start_ptr(&nrb_rec),
                                      nrb.record_len, err, err_info)) {
                     ws_buffer_free(&nrb_rec);
-                    pcapng_debug0("pcapng_read_name_resolution_block: failed to read IPv4 record data");
-                    return -1;
+                    pcapng_debug("pcapng_read_name_resolution_block: failed to read IPv4 record data");
+                    return FALSE;
                 }
                 block_read += nrb.record_len;
 
@@ -1657,8 +1707,8 @@ pcapng_read_name_resolution_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t
                      */
                     memcpy(&v4_addr,
                            ws_buffer_start_ptr(&nrb_rec), 4);
-                    if (pn->byte_swapped)
-                        v4_addr = GUINT32_SWAP_LE_BE(v4_addr);
+                    /* IPv4 address is in big-endian order in the file always, which is how we store
+                       it internally as well, so don't byte-swap it */
                     for (namep = (char *)ws_buffer_start_ptr(&nrb_rec) + 4, record_len = nrb.record_len - 4;
                          record_len != 0;
                          namep += namelen, record_len -= namelen) {
@@ -1669,15 +1719,15 @@ pcapng_read_name_resolution_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t
                         namelen = name_resolution_block_find_name_end(namep, record_len, err, err_info);
                         if (namelen == -1) {
                             ws_buffer_free(&nrb_rec);
-                            return -1;      /* fail */
+                            return FALSE;      /* fail */
                         }
                         pn->add_new_ipv4(v4_addr, namep);
                     }
                 }
 
-                if (!file_skip(fh, PADDING4(nrb.record_len), err)) {
+                if (!wtap_read_bytes(fh, NULL, PADDING4(nrb.record_len), err, err_info)) {
                     ws_buffer_free(&nrb_rec);
-                    return -1;
+                    return FALSE;
                 }
                 block_read += PADDING4(nrb.record_len);
                 break;
@@ -1687,7 +1737,7 @@ pcapng_read_name_resolution_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t
                  * a 16-byte IPv6 address, hence a minimum
                  * of 16 bytes.
                  *
-                 * (The pcap-NG spec really indicates
+                 * (The pcapng spec really indicates
                  * that it must be at least 17 bytes,
                  * as there must be at least one name,
                  * and it really must be at least 18
@@ -1701,20 +1751,20 @@ pcapng_read_name_resolution_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t
                     *err = WTAP_ERR_BAD_FILE;
                     *err_info = g_strdup_printf("pcapng_read_name_resolution_block: NRB record length for IPv6 record %u < minimum length 16",
                                                 nrb.record_len);
-                    return -1;
+                    return FALSE;
                 }
                 if (to_read < nrb.record_len) {
                     ws_buffer_free(&nrb_rec);
                     *err = WTAP_ERR_BAD_FILE;
                     *err_info = g_strdup_printf("pcapng_read_name_resolution_block: NRB record length for IPv6 record %u > remaining data in NRB",
                                                 nrb.record_len);
-                    return -1;
+                    return FALSE;
                 }
                 ws_buffer_assure_space(&nrb_rec, nrb.record_len);
                 if (!wtap_read_bytes(fh, ws_buffer_start_ptr(&nrb_rec),
                                      nrb.record_len, err, err_info)) {
                     ws_buffer_free(&nrb_rec);
-                    return -1;
+                    return FALSE;
                 }
                 block_read += nrb.record_len;
 
@@ -1729,43 +1779,128 @@ pcapng_read_name_resolution_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t
                         namelen = name_resolution_block_find_name_end(namep, record_len, err, err_info);
                         if (namelen == -1) {
                             ws_buffer_free(&nrb_rec);
-                            return -1;      /* fail */
+                            return FALSE;      /* fail */
                         }
                         pn->add_new_ipv6(ws_buffer_start_ptr(&nrb_rec),
                                          namep);
                     }
                 }
 
-                if (!file_skip(fh, PADDING4(nrb.record_len), err)) {
+                if (!wtap_read_bytes(fh, NULL, PADDING4(nrb.record_len), err, err_info)) {
                     ws_buffer_free(&nrb_rec);
-                    return -1;
+                    return FALSE;
                 }
                 block_read += PADDING4(nrb.record_len);
                 break;
             default:
-                pcapng_debug1("pcapng_read_name_resolution_block: unknown record type 0x%x", nrb.record_type);
-                if (!file_skip(fh, nrb.record_len + PADDING4(nrb.record_len), err)) {
+                pcapng_debug("pcapng_read_name_resolution_block: unknown record type 0x%x", nrb.record_type);
+                if (!wtap_read_bytes(fh, NULL, nrb.record_len + PADDING4(nrb.record_len), err, err_info)) {
                     ws_buffer_free(&nrb_rec);
-                    return -1;
+                    return FALSE;
                 }
                 block_read += nrb.record_len + PADDING4(nrb.record_len);
                 break;
         }
     }
 
+
+read_options:
+    to_read -= block_read;
+
+    /* Options
+     * opt_comment    1
+     *
+     * TODO:
+     * ns_dnsname     2
+     * ns_dnsIP4addr  3
+     * ns_dnsIP6addr  4
+     */
+
+    /* Allocate enough memory to hold all options */
+    opt_cont_buf_len = to_read;
+    option_content = (guint8 *)g_try_malloc(opt_cont_buf_len);
+    if (opt_cont_buf_len != 0 && option_content == NULL) {
+        *err = ENOMEM;  /* we assume we're out of memory */
+        ws_buffer_free(&nrb_rec);
+        return FALSE;
+    }
+
+    while (to_read != 0) {
+        /* read option */
+        bytes_read = pcapng_read_option(fh, pn, &oh, option_content, opt_cont_buf_len, to_read, err, err_info, "name_resolution");
+        if (bytes_read <= 0) {
+            pcapng_debug("pcapng_read_name_resolution_block: failed to read option");
+            g_free(option_content);
+            ws_buffer_free(&nrb_rec);
+            return FALSE;
+        }
+        to_read -= bytes_read;
+
+        /* handle option content */
+        switch (oh.option_code) {
+            case(OPT_EOFOPT):
+                if (to_read != 0) {
+                    pcapng_debug("pcapng_read_name_resolution_block: %u bytes after opt_endofopt", to_read);
+                }
+                /* padding should be ok here, just get out of this */
+                to_read = 0;
+                break;
+            case(OPT_COMMENT):
+                if (oh.option_length > 0 && oh.option_length < opt_cont_buf_len) {
+                    tmp_content = g_strndup((char *)option_content, oh.option_length);
+                    wtap_block_add_string_option(wblock->block, OPT_COMMENT, option_content, oh.option_length);
+                    pcapng_debug("pcapng_read_name_resolution_block: length %u opt_comment '%s'", oh.option_length, tmp_content);
+                    g_free(tmp_content);
+                } else {
+                    pcapng_debug("pcapng_read_name_resolution_block: opt_comment length %u seems strange", oh.option_length);
+                }
+                break;
+            default:
+#ifdef HAVE_PLUGINS
+                /*
+                 * Do we have a handler for this network resolution block option code?
+                 */
+                if (option_handlers[BT_INDEX_NRB] != NULL &&
+                    (handler = (option_handler *)g_hash_table_lookup(option_handlers[BT_INDEX_NRB],
+                                                                   GUINT_TO_POINTER((guint)oh.option_code))) != NULL) {
+                    /* Yes - call the handler. */
+                    if (!handler->hfunc(pn->byte_swapped, oh.option_length,
+                                 option_content, err, err_info)) {
+
+                        g_free(option_content);
+                        ws_buffer_free(&nrb_rec);
+                        return FALSE;
+                    }
+                } else
+#endif
+                {
+                    pcapng_debug("pcapng_read_name_resolution_block: unknown option %u - ignoring %u bytes",
+                                  oh.option_code, oh.option_length);
+                }
+        }
+    }
+
+    g_free(option_content);
     ws_buffer_free(&nrb_rec);
-    return block_read;
+
+    /*
+     * We don't return these to the caller in pcapng_read().
+     */
+    wblock->internal = TRUE;
+
+    return TRUE;
 }
 
-static int
+static gboolean
 pcapng_read_interface_statistics_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wtapng_block_t *wblock,int *err, gchar **err_info)
 {
     int bytes_read;
-    guint block_read;
     guint to_read, opt_cont_buf_len;
     pcapng_interface_statistics_block_t isb;
     pcapng_option_header_t oh;
-    char *option_content = NULL; /* Allocate as large as the options block */
+    guint8 *option_content = NULL; /* Allocate as large as the options block */
+    wtapng_if_stats_mandatory_t* if_stats_mand;
+    char* tmp_content;
 
     /*
      * Is this block long enough to be an ISB?
@@ -1777,95 +1912,77 @@ pcapng_read_interface_statistics_block(FILE_T fh, pcapng_block_header_t *bh, pca
         *err = WTAP_ERR_BAD_FILE;
         *err_info = g_strdup_printf("pcapng_read_interface_statistics_block: total block length %u is too small (< %u)",
                                     bh->block_total_length, MIN_ISB_SIZE);
-        return -1;
-    }
-
-    /* Don't try to allocate memory for a huge number of options, as
-       that might fail and, even if it succeeds, it might not leave
-       any address space or memory+backing store for anything else.
-
-       We do that by imposing a maximum block size of MAX_BLOCK_SIZE.
-       We check for this *after* checking the SHB for its byte
-       order magic number, so that non-pcap-ng files are less
-       likely to be treated as bad pcap-ng files. */
-    if (bh->block_total_length > MAX_BLOCK_SIZE) {
-        *err = WTAP_ERR_BAD_FILE;
-        *err_info = g_strdup_printf("pcapng: total block length %u is too large (> %u)",
-                                    bh->block_total_length, MAX_BLOCK_SIZE);
-        return -1;
+        return FALSE;
     }
 
     /* "Interface Statistics Block" read fixed part */
     if (!wtap_read_bytes(fh, &isb, sizeof isb, err, err_info)) {
-        pcapng_debug0("pcapng_read_interface_statistics_block: failed to read packet data");
-        return -1;
+        pcapng_debug("pcapng_read_interface_statistics_block: failed to read packet data");
+        return FALSE;
     }
-    block_read = (guint)sizeof isb;
 
+    wblock->block = wtap_block_create(WTAP_BLOCK_IF_STATS);
+    if_stats_mand = (wtapng_if_stats_mandatory_t*)wtap_block_get_mandatory_data(wblock->block);
     if (pn->byte_swapped) {
-        wblock->data.if_stats.interface_id = GUINT32_SWAP_LE_BE(isb.interface_id);
-        wblock->data.if_stats.ts_high      = GUINT32_SWAP_LE_BE(isb.timestamp_high);
-        wblock->data.if_stats.ts_low       = GUINT32_SWAP_LE_BE(isb.timestamp_low);
+        if_stats_mand->interface_id = GUINT32_SWAP_LE_BE(isb.interface_id);
+        if_stats_mand->ts_high      = GUINT32_SWAP_LE_BE(isb.timestamp_high);
+        if_stats_mand->ts_low       = GUINT32_SWAP_LE_BE(isb.timestamp_low);
     } else {
-        wblock->data.if_stats.interface_id = isb.interface_id;
-        wblock->data.if_stats.ts_high      = isb.timestamp_high;
-        wblock->data.if_stats.ts_low       = isb.timestamp_low;
+        if_stats_mand->interface_id = isb.interface_id;
+        if_stats_mand->ts_high      = isb.timestamp_high;
+        if_stats_mand->ts_low       = isb.timestamp_low;
     }
-    pcapng_debug1("pcapng_read_interface_statistics_block: interface_id %u", wblock->data.if_stats.interface_id);
-
-    /* Option defaults */
-    wblock->data.if_stats.opt_comment          = NULL;
-    wblock->data.if_stats.isb_ifrecv           = -1;
-    wblock->data.if_stats.isb_ifdrop           = -1;
-    wblock->data.if_stats.isb_filteraccept     = -1;
-    wblock->data.if_stats.isb_osdrop           = -1;
-    wblock->data.if_stats.isb_usrdeliv         = -1;
+    pcapng_debug("pcapng_read_interface_statistics_block: interface_id %u", if_stats_mand->interface_id);
 
     /* Options */
     to_read = bh->block_total_length -
-        (MIN_BLOCK_SIZE + block_read);    /* fixed and variable part, including padding */
+        (MIN_BLOCK_SIZE + (guint)sizeof isb);    /* fixed and variable part, including padding */
 
     /* Allocate enough memory to hold all options */
     opt_cont_buf_len = to_read;
-    option_content = (char *)g_try_malloc(opt_cont_buf_len);
+    option_content = (guint8 *)g_try_malloc(opt_cont_buf_len);
     if (opt_cont_buf_len != 0 && option_content == NULL) {
         *err = ENOMEM;  /* we assume we're out of memory */
-        return -1;
+        return FALSE;
     }
 
     while (to_read != 0) {
         /* read option */
-        bytes_read = pcapng_read_option(fh, pn, &oh, option_content, opt_cont_buf_len, to_read, err, err_info);
+        bytes_read = pcapng_read_option(fh, pn, &oh, option_content, opt_cont_buf_len, to_read, err, err_info, "interface_statistics");
         if (bytes_read <= 0) {
-            pcapng_debug0("pcapng_read_interface_statistics_block: failed to read option");
-            return bytes_read;
+            pcapng_debug("pcapng_read_interface_statistics_block: failed to read option");
+            g_free(option_content);
+            return FALSE;
         }
-        block_read += bytes_read;
         to_read -= bytes_read;
 
         /* handle option content */
         switch (oh.option_code) {
-            case(0): /* opt_endofopt */
+            case(OPT_EOFOPT): /* opt_endofopt */
                 if (to_read != 0) {
-                    pcapng_debug1("pcapng_read_interface_statistics_block: %u bytes after opt_endofopt", to_read);
+                    pcapng_debug("pcapng_read_interface_statistics_block: %u bytes after opt_endofopt", to_read);
                 }
                 /* padding should be ok here, just get out of this */
                 to_read = 0;
                 break;
-            case(1): /* opt_comment */
+            case(OPT_COMMENT): /* opt_comment */
                 if (oh.option_length > 0 && oh.option_length < opt_cont_buf_len) {
-                    wblock->data.if_stats.opt_comment = g_strndup(option_content, oh.option_length);
-                    pcapng_debug1("pcapng_read_interface_statistics_block: opt_comment %s", wblock->data.if_stats.opt_comment);
+                    tmp_content = g_strndup((char *)option_content, oh.option_length);
+                    wtap_block_add_string_option(wblock->block, OPT_COMMENT, option_content, oh.option_length);
+                    pcapng_debug("pcapng_read_interface_statistics_block: opt_comment %s", tmp_content);
+                    g_free(tmp_content);
                 } else {
-                    pcapng_debug1("pcapng_read_interface_statistics_block: opt_comment length %u seems strange", oh.option_length);
+                    pcapng_debug("pcapng_read_interface_statistics_block: opt_comment length %u seems strange", oh.option_length);
                 }
                 break;
-            case(2): /* isb_starttime */
+            case(OPT_ISB_STARTTIME): /* isb_starttime */
                 if (oh.option_length == 8) {
                     guint32 high, low;
+                    guint64 starttime;
 
-                    /*  Don't cast a char[] into a guint32--the
-                     *  char[] may not be aligned correctly.
+                    /*  Don't cast a guint8 * into a guint32 *--the
+                     *  guint8 * may not point to something that's
+                     *  aligned correctly.
                      */
                     memcpy(&high, option_content, sizeof(guint32));
                     memcpy(&low, option_content + sizeof(guint32), sizeof(guint32));
@@ -1873,20 +1990,24 @@ pcapng_read_interface_statistics_block(FILE_T fh, pcapng_block_header_t *bh, pca
                         high = GUINT32_SWAP_LE_BE(high);
                         low = GUINT32_SWAP_LE_BE(low);
                     }
-                    wblock->data.if_stats.isb_starttime = (guint64)high;
-                    wblock->data.if_stats.isb_starttime <<= 32;
-                    wblock->data.if_stats.isb_starttime += (guint64)low;
-                    pcapng_debug1("pcapng_read_interface_statistics_block: isb_starttime %" G_GINT64_MODIFIER "u", wblock->data.if_stats.isb_starttime);
+                    starttime = (guint64)high;
+                    starttime <<= 32;
+                    starttime += (guint64)low;
+                    /* Fails with multiple options; we silently ignore the failure */
+                    wtap_block_add_uint64_option(wblock->block, OPT_ISB_STARTTIME, starttime);
+                    pcapng_debug("pcapng_read_interface_statistics_block: isb_starttime %" G_GINT64_MODIFIER "u", starttime);
                 } else {
-                    pcapng_debug1("pcapng_read_interface_statistics_block: isb_starttime length %u not 8 as expected", oh.option_length);
+                    pcapng_debug("pcapng_read_interface_statistics_block: isb_starttime length %u not 8 as expected", oh.option_length);
                 }
                 break;
-            case(3): /* isb_endtime */
+            case(OPT_ISB_ENDTIME): /* isb_endtime */
                 if (oh.option_length == 8) {
                     guint32 high, low;
+                    guint64 endtime;
 
-                    /*  Don't cast a char[] into a guint32--the
-                     *  char[] may not be aligned correctly.
+                    /*  Don't cast a guint8 * into a guint32 *--the
+                     *  guint8 * may not point to something that's
+                     *  aligned correctly.
                      */
                     memcpy(&high, option_content, sizeof(guint32));
                     memcpy(&low, option_content + sizeof(guint32), sizeof(guint32));
@@ -1894,105 +2015,134 @@ pcapng_read_interface_statistics_block(FILE_T fh, pcapng_block_header_t *bh, pca
                         high = GUINT32_SWAP_LE_BE(high);
                         low = GUINT32_SWAP_LE_BE(low);
                     }
-                    wblock->data.if_stats.isb_endtime = (guint64)high;
-                    wblock->data.if_stats.isb_endtime <<= 32;
-                    wblock->data.if_stats.isb_endtime += (guint64)low;
-                    pcapng_debug1("pcapng_read_interface_statistics_block: isb_endtime %" G_GINT64_MODIFIER "u", wblock->data.if_stats.isb_endtime);
+                    endtime = (guint64)high;
+                    endtime <<= 32;
+                    endtime += (guint64)low;
+                    /* Fails with multiple options; we silently ignore the failure */
+                    wtap_block_add_uint64_option(wblock->block, OPT_ISB_ENDTIME, endtime);
+                    pcapng_debug("pcapng_read_interface_statistics_block: isb_endtime %" G_GINT64_MODIFIER "u", endtime);
                 } else {
-                    pcapng_debug1("pcapng_read_interface_statistics_block: isb_starttime length %u not 8 as expected", oh.option_length);
+                    pcapng_debug("pcapng_read_interface_statistics_block: isb_starttime length %u not 8 as expected", oh.option_length);
                 }
                 break;
-            case(4): /* isb_ifrecv */
+            case(OPT_ISB_IFRECV): /* isb_ifrecv */
                 if (oh.option_length == 8) {
-                    /*  Don't cast a char[] into a guint32--the
-                     *  char[] may not be aligned correctly.
+                    guint64 ifrecv;
+                    /*  Don't cast a guint8 * into a guint64 *--the
+                     *  guint8 * may not point to something that's
+                     *  aligned correctly.
                      */
-                    memcpy(&wblock->data.if_stats.isb_ifrecv, option_content, sizeof(guint64));
+                    memcpy(&ifrecv, option_content, sizeof(guint64));
                     if (pn->byte_swapped)
-                        wblock->data.if_stats.isb_ifrecv = GUINT64_SWAP_LE_BE(wblock->data.if_stats.isb_ifrecv);
-                    pcapng_debug1("pcapng_read_interface_statistics_block: isb_ifrecv %" G_GINT64_MODIFIER "u", wblock->data.if_stats.isb_ifrecv);
+                        ifrecv = GUINT64_SWAP_LE_BE(ifrecv);
+                    /* Fails with multiple options; we silently ignore the failure */
+                    wtap_block_add_uint64_option(wblock->block, OPT_ISB_IFRECV, ifrecv);
+                    pcapng_debug("pcapng_read_interface_statistics_block: isb_ifrecv %" G_GINT64_MODIFIER "u", ifrecv);
                 } else {
-                    pcapng_debug1("pcapng_read_interface_statistics_block: isb_ifrecv length %u not 8 as expected", oh.option_length);
+                    pcapng_debug("pcapng_read_interface_statistics_block: isb_ifrecv length %u not 8 as expected", oh.option_length);
                 }
                 break;
-            case(5): /* isb_ifdrop */
+            case(OPT_ISB_IFDROP): /* isb_ifdrop */
                 if (oh.option_length == 8) {
-                    /*  Don't cast a char[] into a guint32--the
-                     *  char[] may not be aligned correctly.
+                    guint64 ifdrop;
+                    /*  Don't cast a guint8 * into a guint64 *--the
+                     *  guint8 * may not point to something that's
+                     *  aligned correctly.
                      */
-                    memcpy(&wblock->data.if_stats.isb_ifdrop, option_content, sizeof(guint64));
+                    memcpy(&ifdrop, option_content, sizeof(guint64));
                     if (pn->byte_swapped)
-                        wblock->data.if_stats.isb_ifdrop = GUINT64_SWAP_LE_BE(wblock->data.if_stats.isb_ifdrop);
-                    pcapng_debug1("pcapng_read_interface_statistics_block: isb_ifdrop %" G_GINT64_MODIFIER "u", wblock->data.if_stats.isb_ifdrop);
+                        ifdrop = GUINT64_SWAP_LE_BE(ifdrop);
+                    /* Fails with multiple options; we silently ignore the failure */
+                    wtap_block_add_uint64_option(wblock->block, OPT_ISB_IFDROP, ifdrop);
+                    pcapng_debug("pcapng_read_interface_statistics_block: isb_ifdrop %" G_GINT64_MODIFIER "u", ifdrop);
                 } else {
-                    pcapng_debug1("pcapng_read_interface_statistics_block: isb_ifdrop length %u not 8 as expected", oh.option_length);
+                    pcapng_debug("pcapng_read_interface_statistics_block: isb_ifdrop length %u not 8 as expected", oh.option_length);
                 }
                 break;
-            case(6): /* isb_filteraccept 6 */
+            case(OPT_ISB_FILTERACCEPT): /* isb_filteraccept 6 */
                 if (oh.option_length == 8) {
-                    /*  Don't cast a char[] into a guint32--the
-                     *  char[] may not be aligned correctly.
+                    guint64 filteraccept;
+                    /*  Don't cast a guint8 * into a guint64 *--the
+                     *  guint8 * may not point to something that's
+                     *  aligned correctly.
                      */
-                    memcpy(&wblock->data.if_stats.isb_filteraccept, option_content, sizeof(guint64));
+                    memcpy(&filteraccept, option_content, sizeof(guint64));
                     if (pn->byte_swapped)
-                        wblock->data.if_stats.isb_ifdrop = GUINT64_SWAP_LE_BE(wblock->data.if_stats.isb_filteraccept);
-                    pcapng_debug1("pcapng_read_interface_statistics_block: isb_filteraccept %" G_GINT64_MODIFIER "u", wblock->data.if_stats.isb_filteraccept);
+                        filteraccept = GUINT64_SWAP_LE_BE(filteraccept);
+                    /* Fails with multiple options; we silently ignore the failure */
+                    wtap_block_add_uint64_option(wblock->block, OPT_ISB_FILTERACCEPT, filteraccept);
+                    pcapng_debug("pcapng_read_interface_statistics_block: isb_filteraccept %" G_GINT64_MODIFIER "u", filteraccept);
                 } else {
-                    pcapng_debug1("pcapng_read_interface_statistics_block: isb_filteraccept length %u not 8 as expected", oh.option_length);
+                    pcapng_debug("pcapng_read_interface_statistics_block: isb_filteraccept length %u not 8 as expected", oh.option_length);
                 }
                 break;
-            case(7): /* isb_osdrop 7 */
+            case(OPT_ISB_OSDROP): /* isb_osdrop 7 */
                 if (oh.option_length == 8) {
-                    /*  Don't cast a char[] into a guint32--the
-                     *  char[] may not be aligned correctly.
+                    guint64 osdrop;
+                    /*  Don't cast a guint8 * into a guint64 *--the
+                     *  guint8 * may not point to something that's
+                     *  aligned correctly.
                      */
-                    memcpy(&wblock->data.if_stats.isb_osdrop, option_content, sizeof(guint64));
+                    memcpy(&osdrop, option_content, sizeof(guint64));
                     if (pn->byte_swapped)
-                        wblock->data.if_stats.isb_osdrop = GUINT64_SWAP_LE_BE(wblock->data.if_stats.isb_osdrop);
-                    pcapng_debug1("pcapng_read_interface_statistics_block: isb_osdrop %" G_GINT64_MODIFIER "u", wblock->data.if_stats.isb_osdrop);
+                        osdrop = GUINT64_SWAP_LE_BE(osdrop);
+                    /* Fails with multiple options; we silently ignore the failure */
+                    wtap_block_add_uint64_option(wblock->block, OPT_ISB_OSDROP, osdrop);
+                    pcapng_debug("pcapng_read_interface_statistics_block: isb_osdrop %" G_GINT64_MODIFIER "u", osdrop);
                 } else {
-                    pcapng_debug1("pcapng_read_interface_statistics_block: isb_osdrop length %u not 8 as expected", oh.option_length);
+                    pcapng_debug("pcapng_read_interface_statistics_block: isb_osdrop length %u not 8 as expected", oh.option_length);
                 }
                 break;
-            case(8): /* isb_usrdeliv 8  */
+            case(OPT_ISB_USRDELIV): /* isb_usrdeliv 8  */
                 if (oh.option_length == 8) {
-                    /*  Don't cast a char[] into a guint32--the
-                     *  char[] may not be aligned correctly.
+                    guint64 usrdeliv;
+                    /*  Don't cast a guint8 * into a guint64 *--the
+                     *  guint8 * may not point to something that's
+                     *  aligned correctly.
                      */
-                    memcpy(&wblock->data.if_stats.isb_usrdeliv, option_content, sizeof(guint64));
+                    memcpy(&usrdeliv, option_content, sizeof(guint64));
                     if (pn->byte_swapped)
-                        wblock->data.if_stats.isb_usrdeliv = GUINT64_SWAP_LE_BE(wblock->data.if_stats.isb_osdrop);
-                    pcapng_debug1("pcapng_read_interface_statistics_block: isb_usrdeliv %" G_GINT64_MODIFIER "u", wblock->data.if_stats.isb_usrdeliv);
+                        usrdeliv = GUINT64_SWAP_LE_BE(usrdeliv);
+                    /* Fails with multiple options; we silently ignore the failure */
+                    wtap_block_add_uint64_option(wblock->block, OPT_ISB_USRDELIV, usrdeliv);
+                    pcapng_debug("pcapng_read_interface_statistics_block: isb_usrdeliv %" G_GINT64_MODIFIER "u", usrdeliv);
                 } else {
-                    pcapng_debug1("pcapng_read_interface_statistics_block: isb_usrdeliv length %u not 8 as expected", oh.option_length);
+                    pcapng_debug("pcapng_read_interface_statistics_block: isb_usrdeliv length %u not 8 as expected", oh.option_length);
                 }
                 break;
             default:
-                pcapng_debug2("pcapng_read_interface_statistics_block: unknown option %u - ignoring %u bytes",
+                pcapng_debug("pcapng_read_interface_statistics_block: unknown option %u - ignoring %u bytes",
                               oh.option_code, oh.option_length);
         }
     }
 
     g_free(option_content);
 
-    return block_read;
-}
+    /*
+     * We don't return these to the caller in pcapng_read().
+     */
+    wblock->internal = TRUE;
 
+    return TRUE;
+}
 
-static int
-pcapng_read_unknown_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn _U_, wtapng_block_t *wblock _U_, int *err, gchar **err_info)
+static gboolean
+pcapng_read_sysdig_event_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wtapng_block_t *wblock, int *err, gchar **err_info)
 {
-    int block_read;
+    unsigned block_read;
     guint32 block_total_length;
-#ifdef HAVE_PLUGINS
-    block_handler *handler;
-#endif
+    guint16 cpu_id;
+    guint64 wire_ts;
+    guint64 ts;
+    guint64 thread_id;
+    guint32 event_len;
+    guint16 event_type;
 
-    if (bh->block_total_length < MIN_BLOCK_SIZE) {
+    if (bh->block_total_length < MIN_SYSDIG_EVENT_SIZE) {
         *err = WTAP_ERR_BAD_FILE;
-        *err_info = g_strdup_printf("pcapng_read_unknown_block: total block length %u of an unknown block type is less than the minimum block size %u",
-                                    bh->block_total_length, MIN_BLOCK_SIZE);
-        return -1;
+        *err_info = g_strdup_printf("%s: total block length %u is too small (< %u)", G_STRFUNC,
+                                    bh->block_total_length, MIN_SYSDIG_EVENT_SIZE);
+        return FALSE;
     }
 
     /* add padding bytes to "block total length" */
@@ -2003,174 +2153,314 @@ pcapng_read_unknown_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn _U_
         block_total_length = bh->block_total_length;
     }
 
-    block_read = block_total_length - MIN_BLOCK_SIZE;
+    pcapng_debug("pcapng_read_sysdig_event_block: block_total_length %u",
+                  bh->block_total_length);
 
-#ifdef HAVE_PLUGINS
-    /*
-     * Do we have a handler for this block type?
-     */
-    handler = (block_handler *)g_hash_table_lookup(block_handlers,
-                                                   GUINT_TO_POINTER(bh->block_type));
-    if (handler != NULL) {
-        /* Yes - call it to read this block type. */
-        if (!handler->read(fh, block_read, pn->byte_swapped,
-                           wblock->packet_header, wblock->frame_buffer,
-                           err, err_info))
-            return -1;
-    } else
+    wblock->rec->rec_type = REC_TYPE_SYSCALL;
+    wblock->rec->rec_header.syscall_header.record_type = BLOCK_TYPE_SYSDIG_EVENT;
+    wblock->rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN /*|WTAP_HAS_INTERFACE_ID */;
+    wblock->rec->tsprec = WTAP_TSPREC_NSEC;
+
+    block_read = block_total_length;
+
+    if (!wtap_read_bytes(fh, &cpu_id, sizeof cpu_id, err, err_info)) {
+        pcapng_debug("pcapng_read_packet_block: failed to read sysdig event cpu id");
+        return FALSE;
+    }
+    if (!wtap_read_bytes(fh, &wire_ts, sizeof wire_ts, err, err_info)) {
+        pcapng_debug("pcapng_read_packet_block: failed to read sysdig event timestamp");
+        return FALSE;
+    }
+    if (!wtap_read_bytes(fh, &thread_id, sizeof thread_id, err, err_info)) {
+        pcapng_debug("pcapng_read_packet_block: failed to read sysdig event thread id");
+        return FALSE;
+    }
+    if (!wtap_read_bytes(fh, &event_len, sizeof event_len, err, err_info)) {
+        pcapng_debug("pcapng_read_packet_block: failed to read sysdig event length");
+        return FALSE;
+    }
+    if (!wtap_read_bytes(fh, &event_type, sizeof event_type, err, err_info)) {
+        pcapng_debug("pcapng_read_packet_block: failed to read sysdig event type");
+        return FALSE;
+    }
+
+    block_read -= MIN_SYSDIG_EVENT_SIZE;
+    wblock->rec->rec_header.syscall_header.byte_order = G_BYTE_ORDER;
+
+    /* XXX Use Gxxx_FROM_LE macros instead? */
+    if (pn->byte_swapped) {
+        wblock->rec->rec_header.syscall_header.byte_order =
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+            G_BIG_ENDIAN;
+#else
+            G_LITTLE_ENDIAN;
 #endif
-    {
-        /* No.  Skip over this unknown block. */
-        if (!file_skip(fh, block_read, err)) {
-            return -1;
-        }
+        wblock->rec->rec_header.syscall_header.cpu_id = GUINT16_SWAP_LE_BE(cpu_id);
+        ts = GUINT64_SWAP_LE_BE(wire_ts);
+        wblock->rec->rec_header.syscall_header.thread_id = GUINT64_SWAP_LE_BE(thread_id);
+        wblock->rec->rec_header.syscall_header.event_len = GUINT32_SWAP_LE_BE(event_len);
+        wblock->rec->rec_header.syscall_header.event_type = GUINT16_SWAP_LE_BE(event_type);
+    } else {
+        wblock->rec->rec_header.syscall_header.cpu_id = cpu_id;
+        ts = wire_ts;
+        wblock->rec->rec_header.syscall_header.thread_id = thread_id;
+        wblock->rec->rec_header.syscall_header.event_len = event_len;
+        wblock->rec->rec_header.syscall_header.event_type = event_type;
     }
 
-    return block_read;
-}
+    wblock->rec->ts.secs = (time_t) (ts / 1000000000);
+    wblock->rec->ts.nsecs = (int) (ts % 1000000000);
 
+    wblock->rec->rec_header.syscall_header.event_filelen = block_read;
 
-static int
-pcapng_read_block(wtap *wth, FILE_T fh, gboolean first_block, pcapng_t *pn, wtapng_block_t *wblock, int *err, gchar **err_info)
-{
-    int block_read;
-    int bytes_read;
-    pcapng_block_header_t bh;
-    guint32 block_total_length;
+    /* "Sysdig Event Block" read event data */
+    if (!wtap_read_packet_bytes(fh, wblock->frame_buffer,
+                                block_read, err, err_info))
+        return FALSE;
 
-    memset(&(wblock->data), 0, sizeof(wblock->data));
+    /* XXX Read comment? */
 
-    /* Try to read the (next) block header */
-    if (!wtap_read_bytes_or_eof(fh, &bh, sizeof bh, err, err_info)) {
-        pcapng_debug1("pcapng_read_block: wtap_read_bytes_or_eof() failed, err = %d.", *err);
-        if (*err == 0 || *err == WTAP_ERR_SHORT_READ) {
-            if (first_block) {
-                /* short read or EOF, probably not a pcap-ng file */
-                return -2;
-            }
-            if (*err == 0) {
-                return 0;  /* EOF */
-            }
-        }
-        return -1;
+    /*
+     * We return these to the caller in pcapng_read().
+     */
+    wblock->internal = FALSE;
+
+    return TRUE;
+}
+
+static gboolean
+pcapng_read_unknown_block(FILE_T fh, pcapng_block_header_t *bh,
+#
+#ifdef HAVE_PLUGINS
+    pcapng_t *pn,
+#else
+    pcapng_t *pn _U_,
+#endif
+    wtapng_block_t *wblock,
+    int *err, gchar **err_info)
+{
+    guint32 block_read;
+    guint32 block_total_length;
+#ifdef HAVE_PLUGINS
+    block_handler *handler;
+#endif
+
+    if (bh->block_total_length < MIN_BLOCK_SIZE) {
+        *err = WTAP_ERR_BAD_FILE;
+        *err_info = g_strdup_printf("pcapng_read_unknown_block: total block length %u of an unknown block type is less than the minimum block size %u",
+                                    bh->block_total_length, MIN_BLOCK_SIZE);
+        return FALSE;
     }
 
-    block_read = sizeof bh;
-    if (pn->byte_swapped) {
-        bh.block_type         = GUINT32_SWAP_LE_BE(bh.block_type);
-        bh.block_total_length = GUINT32_SWAP_LE_BE(bh.block_total_length);
+    /* add padding bytes to "block total length" */
+    /* (the "block total length" of some example files don't contain any padding bytes!) */
+    if (bh->block_total_length % 4) {
+        block_total_length = bh->block_total_length + 4 - (bh->block_total_length % 4);
+    } else {
+        block_total_length = bh->block_total_length;
     }
 
-    wblock->type = bh.block_type;
+    block_read = block_total_length - MIN_BLOCK_SIZE;
 
-    pcapng_debug1("pcapng_read_block: block_type 0x%x", bh.block_type);
+#ifdef HAVE_PLUGINS
+    /*
+     * Do we have a handler for this block type?
+     */
+    if (block_handlers != NULL &&
+        (handler = (block_handler *)g_hash_table_lookup(block_handlers,
+                                                        GUINT_TO_POINTER(bh->block_type))) != NULL) {
+        /* Yes - call it to read this block type. */
+        if (!handler->reader(fh, block_read, pn->byte_swapped, wblock,
+                             err, err_info))
+            return FALSE;
+    } else
+#endif
+    {
+        /* No.  Skip over this unknown block. */
+        if (!wtap_read_bytes(fh, NULL, block_read, err, err_info)) {
+            return FALSE;
+        }
 
-    if (first_block) {
         /*
-         * This is being read in by pcapng_open(), so this block
-         * must be an SHB.  If it's not, this is not a pcap-ng
-         * file.
-         *
-         * XXX - check for various forms of Windows <-> UN*X
-         * mangling, and suggest that the file might be a
-         * pcap-ng file that was damaged in transit?
+         * We're skipping this, so we won't return these to the caller
+         * in pcapng_read().
          */
-        if (bh.block_type != BLOCK_TYPE_SHB)
-            return -2;       /* not a pcap-ng file */
+        wblock->internal = TRUE;
     }
 
-    switch (bh.block_type) {
-        case(BLOCK_TYPE_SHB):
-            bytes_read = pcapng_read_section_header_block(fh, first_block, &bh, pn, wblock, err, err_info);
-            break;
-        case(BLOCK_TYPE_IDB):
-            bytes_read = pcapng_read_if_descr_block(wth, fh, &bh, pn, wblock, err, err_info);
-            break;
-        case(BLOCK_TYPE_PB):
-            bytes_read = pcapng_read_packet_block(fh, &bh, pn, wblock, err, err_info, FALSE);
-            break;
-        case(BLOCK_TYPE_SPB):
-            bytes_read = pcapng_read_simple_packet_block(fh, &bh, pn, wblock, err, err_info);
-            break;
-        case(BLOCK_TYPE_EPB):
-            bytes_read = pcapng_read_packet_block(fh, &bh, pn, wblock, err, err_info, TRUE);
-            break;
-        case(BLOCK_TYPE_NRB):
-            bytes_read = pcapng_read_name_resolution_block(fh, &bh, pn, wblock, err, err_info);
-            break;
-        case(BLOCK_TYPE_ISB):
-            bytes_read = pcapng_read_interface_statistics_block(fh, &bh, pn, wblock, err, err_info);
-            break;
-        default:
-            pcapng_debug2("pcapng_read_block: Unknown block_type: 0x%x (block ignored), block total length %d", bh.block_type, bh.block_total_length);
-            bytes_read = pcapng_read_unknown_block(fh, &bh, pn, wblock, err, err_info);
-            break;
+    return TRUE;
+}
+
+
+static block_return_val
+pcapng_read_block(wtap *wth, FILE_T fh, pcapng_t *pn, wtapng_block_t *wblock, int *err, gchar **err_info)
+{
+    block_return_val ret;
+    pcapng_block_header_t bh;
+    guint32 block_total_length;
+
+    wblock->block = NULL;
+
+    /* Try to read the (next) block header */
+    if (!wtap_read_bytes_or_eof(fh, &bh, sizeof bh, err, err_info)) {
+        pcapng_debug("pcapng_read_block: wtap_read_bytes_or_eof() failed, err = %d.", *err);
+        if (*err == 0 || *err == WTAP_ERR_SHORT_READ) {
+            /*
+             * Short read or EOF.
+             *
+             * If we're reading this as part of an open,
+             * the file is too short to be a pcapng file.
+             *
+             * If we're not, we treat PCAPNG_BLOCK_NOT_SHB and
+             * PCAPNG_BLOCK_ERROR the same, so we can just return
+             * PCAPNG_BLOCK_NOT_SHB in both cases.
+             */
+            return PCAPNG_BLOCK_NOT_SHB;
+        }
+        return PCAPNG_BLOCK_ERROR;
     }
 
-    if (bytes_read <= 0) {
-        return bytes_read;
+    /*
+     * SHBs have to be treated differently from other blocks, because
+     * the byte order of the fields in the block can only be determined
+     * by looking at the byte-order magic number inside the block, not
+     * by using the byte order of the section to which it belongs, as
+     * it is the block that *defines* the byte order of the section to
+     * which it belongs.
+     */
+    if (bh.block_type == BLOCK_TYPE_SHB) {
+        /*
+         * BLOCK_TYPE_SHB has the same value regardless of byte order,
+         * so we don't need to byte-swap it.
+         *
+         * We *might* need to byte-swap the total length, but we
+         * can't determine whether we do until we look inside the
+         * block and find the byte-order magic number, so we rely
+         * on pcapng_read_section_header_block() to do that and
+         * to swap the total length (as it needs to get the total
+         * length in the right byte order in order to read the
+         * entire block).
+         */
+        wblock->type = bh.block_type;
+
+        pcapng_debug("pcapng_read_block: block_type 0x%x", bh.block_type);
+
+        ret = pcapng_read_section_header_block(fh, &bh, pn, wblock, err, err_info);
+        if (ret != PCAPNG_BLOCK_OK) {
+            return ret;
+        }
+    } else {
+        if (pn->byte_swapped) {
+            bh.block_type         = GUINT32_SWAP_LE_BE(bh.block_type);
+            bh.block_total_length = GUINT32_SWAP_LE_BE(bh.block_total_length);
+        }
+
+        wblock->type = bh.block_type;
+
+        pcapng_debug("pcapng_read_block: block_type 0x%x", bh.block_type);
+
+        if (!pn->shb_read) {
+            /*
+             * No SHB seen yet, so we're trying to read the first block
+             * during an open, to see whether it's an SHB; if what we
+             * read doesn't look like an SHB, this isn't a pcapng file.
+             */
+            *err = 0;
+            *err_info = NULL;
+            return PCAPNG_BLOCK_NOT_SHB;
+        }
+
+        /* Don't try to allocate memory for a huge number of options, as
+           that might fail and, even if it succeeds, it might not leave
+           any address space or memory+backing store for anything else.
+
+           We do that by imposing a maximum block size of MAX_BLOCK_SIZE. */
+        if (bh.block_total_length > MAX_BLOCK_SIZE) {
+            *err = WTAP_ERR_BAD_FILE;
+            *err_info = g_strdup_printf("pcapng_read_block: total block length %u is too large (> %u)",
+                                        bh.block_total_length, MAX_BLOCK_SIZE);
+            return PCAPNG_BLOCK_ERROR;
+        }
+
+        switch (bh.block_type) {
+            case(BLOCK_TYPE_IDB):
+                if (!pcapng_read_if_descr_block(wth, fh, &bh, pn, wblock, err, err_info))
+                    return PCAPNG_BLOCK_ERROR;
+                break;
+            case(BLOCK_TYPE_PB):
+                if (!pcapng_read_packet_block(fh, &bh, pn, wblock, err, err_info, FALSE))
+                    return PCAPNG_BLOCK_ERROR;
+                break;
+            case(BLOCK_TYPE_SPB):
+                if (!pcapng_read_simple_packet_block(fh, &bh, pn, wblock, err, err_info))
+                    return PCAPNG_BLOCK_ERROR;
+                break;
+            case(BLOCK_TYPE_EPB):
+                if (!pcapng_read_packet_block(fh, &bh, pn, wblock, err, err_info, TRUE))
+                    return PCAPNG_BLOCK_ERROR;
+                break;
+            case(BLOCK_TYPE_NRB):
+                if (!pcapng_read_name_resolution_block(fh, &bh, pn, wblock, err, err_info))
+                    return PCAPNG_BLOCK_ERROR;
+                break;
+            case(BLOCK_TYPE_ISB):
+                if (!pcapng_read_interface_statistics_block(fh, &bh, pn, wblock, err, err_info))
+                    return PCAPNG_BLOCK_ERROR;
+                break;
+            case(BLOCK_TYPE_SYSDIG_EVENT):
+            /* case(BLOCK_TYPE_SYSDIG_EVF): */
+                if (!pcapng_read_sysdig_event_block(fh, &bh, pn, wblock, err, err_info))
+                    return PCAPNG_BLOCK_ERROR;
+                break;
+            default:
+                pcapng_debug("pcapng_read_block: Unknown block_type: 0x%x (block ignored), block total length %d", bh.block_type, bh.block_total_length);
+                if (!pcapng_read_unknown_block(fh, &bh, pn, wblock, err, err_info))
+                    return PCAPNG_BLOCK_ERROR;
+                break;
+        }
     }
-    block_read += bytes_read;
 
     /* sanity check: first and second block lengths must match */
     if (!wtap_read_bytes(fh, &block_total_length, sizeof block_total_length,
                          err, err_info)) {
-        pcapng_debug0("pcapng_read_block: couldn't read second block length");
-        return -1;
+        pcapng_debug("pcapng_check_block_trailer: couldn't read second block length");
+        return PCAPNG_BLOCK_ERROR;
     }
-    block_read += bytes_read;
 
     if (pn->byte_swapped)
         block_total_length = GUINT32_SWAP_LE_BE(block_total_length);
 
-    if (!(block_total_length == bh.block_total_length)) {
+    if (block_total_length != bh.block_total_length) {
         *err = WTAP_ERR_BAD_FILE;
-        *err_info = g_strdup_printf("pcapng_read_block: total block lengths (first %u and second %u) don't match",
+        *err_info = g_strdup_printf("pcapng_check_block_trailer: total block lengths (first %u and second %u) don't match",
                                     bh.block_total_length, block_total_length);
-        return -1;
+        return PCAPNG_BLOCK_ERROR;
     }
-
-    return block_read;
+    return PCAPNG_BLOCK_OK;
 }
 
-/* Process an IDB that we've just read. */
+/* Process an IDB that we've just read. The contents of wblock are copied as needed. */
 static void
 pcapng_process_idb(wtap *wth, pcapng_t *pcapng, wtapng_block_t *wblock)
 {
-    wtapng_if_descr_t int_data;
+    wtap_block_t int_data = wtap_block_create(WTAP_BLOCK_IF_DESCR);
     interface_info_t iface_info;
+    wtapng_if_descr_mandatory_t *if_descr_mand = (wtapng_if_descr_mandatory_t*)wtap_block_get_mandatory_data(int_data),
+                                *wblock_if_descr_mand = (wtapng_if_descr_mandatory_t*)wtap_block_get_mandatory_data(wblock->block);
+
+    wtap_block_copy(int_data, wblock->block);
 
-    int_data.wtap_encap = wblock->data.if_descr.wtap_encap;
-    int_data.time_units_per_second = wblock->data.if_descr.time_units_per_second;
-    int_data.link_type = wblock->data.if_descr.link_type;
-    int_data.snap_len = wblock->data.if_descr.snap_len;
-    /* Options */
-    int_data.opt_comment = wblock->data.if_descr.opt_comment;
-    int_data.if_name = wblock->data.if_descr.if_name;
-    int_data.if_description = wblock->data.if_descr.if_description;
-    /* XXX: if_IPv4addr opt 4  Interface network address and netmask.*/
-    /* XXX: if_IPv6addr opt 5  Interface network address and prefix length (stored in the last byte).*/
-    /* XXX: if_MACaddr  opt 6  Interface Hardware MAC address (48 bits).*/
-    /* XXX: if_EUIaddr  opt 7  Interface Hardware EUI address (64 bits)*/
-    int_data.if_speed = wblock->data.if_descr.if_speed;
-    int_data.if_tsresol = wblock->data.if_descr.if_tsresol;
-    /* XXX: if_tzone      10  Time zone for GMT support (TODO: specify better). */
-    int_data.if_filter_str = wblock->data.if_descr.if_filter_str;
-    int_data.bpf_filter_len = wblock->data.if_descr.bpf_filter_len;
-    int_data.if_filter_bpf_bytes = wblock->data.if_descr.if_filter_bpf_bytes;
-    int_data.if_os = wblock->data.if_descr.if_os;
-    int_data.if_fcslen = wblock->data.if_descr.if_fcslen;
     /* XXX if_tsoffset; opt 14  A 64 bits integer value that specifies an offset (in seconds)...*/
     /* Interface statistics */
-    int_data.num_stat_entries = 0;
-    int_data.interface_statistics = NULL;
+    if_descr_mand->num_stat_entries = 0;
+    if_descr_mand->interface_statistics = NULL;
 
     g_array_append_val(wth->interface_data, int_data);
 
-    iface_info.wtap_encap = wblock->data.if_descr.wtap_encap;
-    iface_info.snap_len = wblock->data.if_descr.snap_len;
-    iface_info.time_units_per_second = wblock->data.if_descr.time_units_per_second;
-    iface_info.tsprecision = wblock->data.if_descr.tsprecision;
+    iface_info.wtap_encap = wblock_if_descr_mand->wtap_encap;
+    iface_info.snap_len = wblock_if_descr_mand->snap_len;
+    iface_info.time_units_per_second = wblock_if_descr_mand->time_units_per_second;
+    iface_info.tsprecision = wblock_if_descr_mand->tsprecision;
 
     g_array_append_val(pcapng->interfaces, iface_info);
 }
@@ -2179,7 +2469,6 @@ pcapng_process_idb(wtap *wth, pcapng_t *pcapng, wtapng_block_t *wblock)
 wtap_open_return_val
 pcapng_open(wtap *wth, int *err, gchar **err_info)
 {
-    int bytes_read;
     pcapng_t pn;
     wtapng_block_t wblock;
     pcapng_t *pcapng;
@@ -2192,26 +2481,32 @@ pcapng_open(wtap *wth, int *err, gchar **err_info)
     pn.if_fcslen = -1;
     pn.version_major = -1;
     pn.version_minor = -1;
-    pn.interfaces = g_array_new(FALSE, FALSE, sizeof(interface_info_t));
-
+    pn.interfaces = NULL;
 
     /* we don't expect any packet blocks yet */
     wblock.frame_buffer = NULL;
-    wblock.packet_header = NULL;
+    wblock.rec = NULL;
 
-    pcapng_debug0("pcapng_open: opening file");
+    pcapng_debug("pcapng_open: opening file");
     /* read first block */
-    bytes_read = pcapng_read_block(wth, wth->fh, TRUE, &pn, &wblock, err, err_info);
-    if (bytes_read <= 0) {
-        pcapng_free_wtapng_block_data(&wblock);
-        if (bytes_read == -2) {
-            pcapng_debug0("pcapng_open: doesn't begin with SHB, probably not a pcap-ng file");
-            return WTAP_OPEN_NOT_MINE;
-        }
-        pcapng_debug0("pcapng_open: couldn't read first SHB");
-        if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
-            return WTAP_OPEN_ERROR;
+    switch (pcapng_read_block(wth, wth->fh, &pn, &wblock, err, err_info)) {
+
+    case PCAPNG_BLOCK_OK:
+        /* No problem */
+        break;
+
+    case PCAPNG_BLOCK_NOT_SHB:
+        /* This doesn't look like an SHB, so this isn't a pcapng file. */
+        wtap_block_free(wblock.block);
+        *err = 0;
+        g_free(*err_info);
+        *err_info = NULL;
         return WTAP_OPEN_NOT_MINE;
+
+    case PCAPNG_BLOCK_ERROR:
+        /* An I/O error, or this probably *is* a pcapng file but not a valid one. */
+        wtap_block_free(wblock.block);
+        return WTAP_OPEN_ERROR;
     }
 
     /* first block must be a "Section Header Block" */
@@ -2221,22 +2516,20 @@ pcapng_open(wtap *wth, int *err, gchar **err_info)
          * between Windows and UN*X as text rather than
          * binary data?
          */
-        pcapng_debug1("pcapng_open: first block type %u not SHB", wblock.type);
-        pcapng_free_wtapng_block_data(&wblock);
+        pcapng_debug("pcapng_open: first block type %u not SHB", wblock.type);
+        wtap_block_free(wblock.block);
         return WTAP_OPEN_NOT_MINE;
     }
     pn.shb_read = TRUE;
 
     /*
-     * At this point, we've decided this is a pcap-NG file, not
-     * some other type of file, so we can't return 0, as that
-     * means "this isn't a pcap-NG file, try some other file
-     * type".
+     * At this point, we've decided this is a pcapng file, not
+     * some other type of file, so we can't return WTAP_OPEN_NOT_MINE
+     * past this point.
      */
-    wth->shb_hdr.opt_comment = wblock.data.section.opt_comment;
-    wth->shb_hdr.shb_hardware = wblock.data.section.shb_hardware;
-    wth->shb_hdr.shb_os = wblock.data.section.shb_os;
-    wth->shb_hdr.shb_user_appl = wblock.data.section.shb_user_appl;
+    wtap_block_copy(g_array_index(wth->shb_hdrs, wtap_block_t, 0), wblock.block);
+    wtap_block_free(wblock.block);
+    wblock.block = NULL;
 
     wth->file_encap = WTAP_ENCAP_UNKNOWN;
     wth->snapshot_length = 0;
@@ -2244,6 +2537,7 @@ pcapng_open(wtap *wth, int *err, gchar **err_info)
     pcapng = (pcapng_t *)g_malloc(sizeof(pcapng_t));
     wth->priv = (void *)pcapng;
     *pcapng = pn;
+    pcapng->interfaces = g_array_new(FALSE, FALSE, sizeof(interface_info_t));
 
     wth->subtype_read = pcapng_read;
     wth->subtype_seek_read = pcapng_seek_read;
@@ -2258,10 +2552,10 @@ pcapng_open(wtap *wth, int *err, gchar **err_info)
         if (!wtap_read_bytes_or_eof(wth->fh, &bh, sizeof bh, err, err_info)) {
             if (*err == 0) {
                 /* EOF */
-                pcapng_debug0("No more IDBs available...");
+                pcapng_debug("No more IDBs available...");
                 break;
             }
-            pcapng_debug1("pcapng_open:  Check for more IDB:s, wtap_read_bytes_or_eof() failed, err = %d.", *err);
+            pcapng_debug("pcapng_open:  Check for more IDB:s, wtap_read_bytes_or_eof() failed, err = %d.", *err);
             return WTAP_OPEN_ERROR;
         }
 
@@ -2272,26 +2566,24 @@ pcapng_open(wtap *wth, int *err, gchar **err_info)
             bh.block_type         = GUINT32_SWAP_LE_BE(bh.block_type);
         }
 
-        pcapng_debug1("pcapng_open: Check for more IDB:s block_type 0x%x", bh.block_type);
+        pcapng_debug("pcapng_open: Check for more IDB:s block_type 0x%x", bh.block_type);
 
         if (bh.block_type != BLOCK_TYPE_IDB) {
             break;  /* No more IDB:s */
         }
-        bytes_read = pcapng_read_block(wth, wth->fh, FALSE, &pn, &wblock, err, err_info);
-        if (bytes_read == 0) {
-            pcapng_debug0("No more IDBs available...");
-            pcapng_free_wtapng_block_data(&wblock);
-            break;
-        }
-        if (bytes_read <= 0) {
-            pcapng_debug0("pcapng_open: couldn't read IDB");
-            pcapng_free_wtapng_block_data(&wblock);
-            if (*err == 0)
-                *err = WTAP_ERR_SHORT_READ;
-            return WTAP_OPEN_ERROR;
+        if (pcapng_read_block(wth, wth->fh, &pn, &wblock, err, err_info) != PCAPNG_BLOCK_OK) {
+            wtap_block_free(wblock.block);
+            if (*err == 0) {
+                pcapng_debug("No more IDBs available...");
+                break;
+            } else {
+                pcapng_debug("pcapng_open: couldn't read IDB");
+                return WTAP_OPEN_ERROR;
+            }
         }
         pcapng_process_idb(wth, pcapng, &wblock);
-        pcapng_debug2("pcapng_open: Read IDB number_of_interfaces %u, wtap_encap %i",
+        wtap_block_free(wblock.block);
+        pcapng_debug("pcapng_open: Read IDB number_of_interfaces %u, wtap_encap %i",
                       wth->interface_data->len, wth->file_encap);
     }
     return WTAP_OPEN_MINE;
@@ -2303,105 +2595,120 @@ static gboolean
 pcapng_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
 {
     pcapng_t *pcapng = (pcapng_t *)wth->priv;
-    int bytes_read;
     wtapng_block_t wblock;
-    wtapng_if_descr_t *wtapng_if_descr;
-    wtapng_if_stats_t if_stats;
+    wtap_block_t wtapng_if_descr;
+    wtap_block_t if_stats;
+    wtapng_if_stats_mandatory_t *if_stats_mand_block, *if_stats_mand;
+    wtapng_if_descr_mandatory_t *wtapng_if_descr_mand;
 
-    *data_offset = file_tell(wth->fh);
-    pcapng_debug1("pcapng_read: data_offset is initially %" G_GINT64_MODIFIER "d", *data_offset);
-
-    wblock.frame_buffer  = wth->frame_buffer;
-    wblock.packet_header = &wth->phdr;
+    wblock.frame_buffer  = wth->rec_data;
+    wblock.rec = &wth->rec;
 
     pcapng->add_new_ipv4 = wth->add_new_ipv4;
     pcapng->add_new_ipv6 = wth->add_new_ipv6;
 
     /* read next block */
     while (1) {
-        bytes_read = pcapng_read_block(wth, wth->fh, FALSE, pcapng, &wblock, err, err_info);
-        if (bytes_read <= 0) {
-            pcapng_debug1("pcapng_read: data_offset is finally %" G_GINT64_MODIFIER "d", *data_offset);
-            pcapng_debug0("pcapng_read: couldn't read packet block");
+        *data_offset = file_tell(wth->fh);
+        pcapng_debug("pcapng_read: data_offset is %" G_GINT64_MODIFIER "d", *data_offset);
+        if (pcapng_read_block(wth, wth->fh, pcapng, &wblock, err, err_info) != PCAPNG_BLOCK_OK) {
+            pcapng_debug("pcapng_read: data_offset is finally %" G_GINT64_MODIFIER "d", *data_offset);
+            pcapng_debug("pcapng_read: couldn't read packet block");
+            wtap_block_free(wblock.block);
             return FALSE;
         }
 
+        if (!wblock.internal) {
+            /*
+             * This is a block type we return to the caller to process.
+             */
+            break;
+        }
+
+        /*
+         * This is a block type we process internally, rather than
+         * returning it for the caller to process.
+         */
         switch (wblock.type) {
 
             case(BLOCK_TYPE_SHB):
-                /* We don't currently support multi-section files. */
-                wth->phdr.pkt_encap = WTAP_ENCAP_UNKNOWN;
-                wth->phdr.pkt_tsprec = WTAP_TSPREC_UNKNOWN;
-                *err = WTAP_ERR_UNSUPPORTED;
-                *err_info = g_strdup_printf("pcapng: multi-section files not currently supported");
-                return FALSE;
-
-            case(BLOCK_TYPE_PB):
-            case(BLOCK_TYPE_SPB):
-            case(BLOCK_TYPE_EPB):
-                /* packet block - we've found a packet */
-                goto got_packet;
+                pcapng_debug("pcapng_read: another section header block");
+                g_array_append_val(wth->shb_hdrs, wblock.block);
+                break;
 
             case(BLOCK_TYPE_IDB):
                 /* A new interface */
-                pcapng_debug0("pcapng_read: block type BLOCK_TYPE_IDB");
-                *data_offset += bytes_read;
+                pcapng_debug("pcapng_read: block type BLOCK_TYPE_IDB");
                 pcapng_process_idb(wth, pcapng, &wblock);
+                wtap_block_free(wblock.block);
                 break;
 
             case(BLOCK_TYPE_NRB):
                 /* More name resolution entries */
-                pcapng_debug0("pcapng_read: block type BLOCK_TYPE_NRB");
-                *data_offset += bytes_read;
+                pcapng_debug("pcapng_read: block type BLOCK_TYPE_NRB");
+                if (wth->nrb_hdrs == NULL) {
+                    wth->nrb_hdrs = g_array_new(FALSE, FALSE, sizeof(wtap_block_t));
+                }
+                g_array_append_val(wth->nrb_hdrs, wblock.block);
                 break;
 
             case(BLOCK_TYPE_ISB):
-                /* Another interface statistics report */
-                pcapng_debug0("pcapng_read: block type BLOCK_TYPE_ISB");
-                *data_offset += bytes_read;
-                pcapng_debug1("pcapng_read: *data_offset is updated to %" G_GINT64_MODIFIER "d", *data_offset);
-                if (wth->interface_data->len < wblock.data.if_stats.interface_id) {
-                    pcapng_debug1("pcapng_read: BLOCK_TYPE_ISB wblock.if_stats.interface_id %u > number_of_interfaces", wblock.data.if_stats.interface_id);
+                /*
+                 * Another interface statistics report
+                 *
+                 * XXX - given that they're reports, we should be
+                 * supplying them in read calls, and displaying them
+                 * in the "packet" list, so you can see what the
+                 * statistics were *at the time when the report was
+                 * made*.
+                 *
+                 * The statistics from the *last* ISB could be displayed
+                 * in the summary, but if there are packets after the
+                 * last ISB, that could be misleading.
+                 *
+                 * If we only display them if that ISB has an isb_endtime
+                 * option, which *should* only appear when capturing ended
+                 * on that interface (so there should be no more packet
+                 * blocks or ISBs for that interface after that point,
+                 * that would be the best way of showing "summary"
+                 * statistics.
+                 */
+                pcapng_debug("pcapng_read: block type BLOCK_TYPE_ISB");
+                if_stats_mand_block = (wtapng_if_stats_mandatory_t*)wtap_block_get_mandatory_data(wblock.block);
+                if (wth->interface_data->len <= if_stats_mand_block->interface_id) {
+                    pcapng_debug("pcapng_read: BLOCK_TYPE_ISB wblock.if_stats.interface_id %u >= number_of_interfaces", if_stats_mand_block->interface_id);
                 } else {
                     /* Get the interface description */
-                    wtapng_if_descr = &g_array_index(wth->interface_data, wtapng_if_descr_t, wblock.data.if_stats.interface_id);
-                    if (wtapng_if_descr->num_stat_entries == 0) {
+                    wtapng_if_descr = g_array_index(wth->interface_data, wtap_block_t, if_stats_mand_block->interface_id);
+                    wtapng_if_descr_mand = (wtapng_if_descr_mandatory_t*)wtap_block_get_mandatory_data(wtapng_if_descr);
+                    if (wtapng_if_descr_mand->num_stat_entries == 0) {
                         /* First ISB found, no previous entry */
-                        pcapng_debug0("pcapng_read: block type BLOCK_TYPE_ISB. First ISB found, no previous entry");
-                        wtapng_if_descr->interface_statistics = g_array_new(FALSE, FALSE, sizeof(wtapng_if_stats_t));
+                        pcapng_debug("pcapng_read: block type BLOCK_TYPE_ISB. First ISB found, no previous entry");
+                        wtapng_if_descr_mand->interface_statistics = g_array_new(FALSE, FALSE, sizeof(wtap_block_t));
                     }
 
-                    if_stats.interface_id       = wblock.data.if_stats.interface_id;
-                    if_stats.ts_high            = wblock.data.if_stats.ts_high;
-                    if_stats.ts_low             = wblock.data.if_stats.ts_low;
-                    /* options */
-                    if_stats.opt_comment        = wblock.data.if_stats.opt_comment;     /* NULL if not available */
-                    if_stats.isb_starttime      = wblock.data.if_stats.isb_starttime;
-                    if_stats.isb_endtime        = wblock.data.if_stats.isb_endtime;
-                    if_stats.isb_ifrecv         = wblock.data.if_stats.isb_ifrecv;
-                    if_stats.isb_ifdrop         = wblock.data.if_stats.isb_ifdrop;
-                    if_stats.isb_filteraccept   = wblock.data.if_stats.isb_filteraccept;
-                    if_stats.isb_osdrop         = wblock.data.if_stats.isb_osdrop;
-                    if_stats.isb_usrdeliv       = wblock.data.if_stats.isb_usrdeliv;
-
-                    g_array_append_val(wtapng_if_descr->interface_statistics, if_stats);
-                    wtapng_if_descr->num_stat_entries++;
+                    if_stats = wtap_block_create(WTAP_BLOCK_IF_STATS);
+                    if_stats_mand = (wtapng_if_stats_mandatory_t*)wtap_block_get_mandatory_data(if_stats);
+                    if_stats_mand->interface_id  = if_stats_mand_block->interface_id;
+                    if_stats_mand->ts_high       = if_stats_mand_block->ts_high;
+                    if_stats_mand->ts_low        = if_stats_mand_block->ts_low;
+
+                    wtap_block_copy(if_stats, wblock.block);
+                    g_array_append_val(wtapng_if_descr_mand->interface_statistics, if_stats);
+                    wtapng_if_descr_mand->num_stat_entries++;
                 }
+                wtap_block_free(wblock.block);
                 break;
 
             default:
                 /* XXX - improve handling of "unknown" blocks */
-                pcapng_debug1("pcapng_read: Unknown block type 0x%08x", wblock.type);
-                *data_offset += bytes_read;
-                pcapng_debug1("pcapng_read: *data_offset is updated to %" G_GINT64_MODIFIER "d", *data_offset);
+                pcapng_debug("pcapng_read: Unknown block type 0x%08x", wblock.type);
                 break;
         }
     }
 
-got_packet:
-
-    /*pcapng_debug2("Read length: %u Packet length: %u", bytes_read, wth->phdr.caplen);*/
-    pcapng_debug1("pcapng_read: data_offset is finally %" G_GINT64_MODIFIER "d", *data_offset + bytes_read);
+    /*pcapng_debug("Read length: %u Packet length: %u", bytes_read, wth->rec.rec_header.packet_header.caplen);*/
+    pcapng_debug("pcapng_read: data_offset is finally %" G_GINT64_MODIFIER "d", *data_offset);
 
     return TRUE;
 }
@@ -2410,11 +2717,10 @@ got_packet:
 /* classic wtap: seek to file position and read packet */
 static gboolean
 pcapng_seek_read(wtap *wth, gint64 seek_off,
-                 struct wtap_pkthdr *phdr, Buffer *buf,
+                 wtap_rec *rec, Buffer *buf,
                  int *err, gchar **err_info)
 {
     pcapng_t *pcapng = (pcapng_t *)wth->priv;
-    int bytes_read;
     wtapng_block_t wblock;
 
 
@@ -2422,28 +2728,28 @@ pcapng_seek_read(wtap *wth, gint64 seek_off,
     if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) < 0) {
         return FALSE;   /* Seek error */
     }
-    pcapng_debug1("pcapng_seek_read: reading at offset %" G_GINT64_MODIFIER "u", seek_off);
+    pcapng_debug("pcapng_seek_read: reading at offset %" G_GINT64_MODIFIER "u", seek_off);
 
     wblock.frame_buffer = buf;
-    wblock.packet_header = phdr;
+    wblock.rec = rec;
 
     /* read the block */
-    bytes_read = pcapng_read_block(wth, wth->random_fh, FALSE, pcapng, &wblock, err, err_info);
-    pcapng_free_wtapng_block_data(&wblock);
-    if (bytes_read <= 0) {
-        pcapng_debug3("pcapng_seek_read: couldn't read packet block (err=%d, errno=%d, bytes_read=%d).",
-                      *err, errno, bytes_read);
+    if (pcapng_read_block(wth, wth->random_fh, pcapng, &wblock, err, err_info) != PCAPNG_BLOCK_OK) {
+        pcapng_debug("pcapng_seek_read: couldn't read packet block (err=%d).",
+                      *err);
+        wtap_block_free(wblock.block);
         return FALSE;
     }
 
-    /* block must be a "Packet Block", an "Enhanced Packet Block",
-       or a "Simple Packet Block" */
-    if (wblock.type != BLOCK_TYPE_PB && wblock.type != BLOCK_TYPE_EPB &&
-        wblock.type != BLOCK_TYPE_SPB) {
-        pcapng_debug1("pcapng_seek_read: block type %u not PB/EPB/SPB", wblock.type);
+    /* block must not be one we process internally rather than supplying */
+    if (wblock.internal) {
+        pcapng_debug("pcapng_seek_read: block type %u is not one we return",
+                     wblock.type);
+        wtap_block_free(wblock.block);
         return FALSE;
     }
 
+    wtap_block_free(wblock.block);
     return TRUE;
 }
 
@@ -2454,806 +2760,225 @@ pcapng_close(wtap *wth)
 {
     pcapng_t *pcapng = (pcapng_t *)wth->priv;
 
-    pcapng_debug0("pcapng_close: closing file");
+    pcapng_debug("pcapng_close: closing file");
     g_array_free(pcapng->interfaces, TRUE);
 }
 
+typedef struct pcapng_block_size_t
+{
+    guint32 size;
+} pcapng_block_size_t;
+
+static guint32 pcapng_compute_option_string_size(char *str)
+{
+    guint32 size = 0, pad;
+
+    size = (guint32)strlen(str) & 0xffff;
+    if ((size % 4)) {
+        pad = 4 - (size % 4);
+    } else {
+        pad = 0;
+    }
+
+    size += pad;
+
+    return size;
+}
+
+static void compute_shb_option_size(wtap_block_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_optval_t* optval, void* user_data)
+{
+    pcapng_block_size_t* block_size = (pcapng_block_size_t*)user_data;
+    guint32 size = 0;
+
+    switch(option_id)
+    {
+    case OPT_COMMENT:
+    case OPT_SHB_HARDWARE:
+    case OPT_SHB_OS:
+    case OPT_SHB_USERAPPL:
+        size = pcapng_compute_option_string_size(optval->stringval);
+        break;
+    default:
+        /* Unknown options - size by datatype? */
+        break;
+    }
+
+    block_size->size += size;
+    /* Add bytes for option header if option should be written */
+    if (size > 0) {
+        /* Add optional padding to 32 bits */
+        if ((block_size->size & 0x03) != 0)
+        {
+            block_size->size += 4 - (block_size->size & 0x03);
+        }
+        block_size->size += 4;
+    }
+}
+
+typedef struct pcapng_write_block_t
+{
+    wtap_dumper *wdh;
+    int *err;
+    gboolean success;
+}
+pcapng_write_block_t;
+
+static gboolean pcapng_write_option_string(wtap_dumper *wdh, guint option_id, char *str, int *err)
+{
+    struct pcapng_option_header option_hdr;
+    guint32 size = (guint32)strlen(str) & 0xffff;
+    const guint32 zero_pad = 0;
+    guint32 pad;
+
+    if (size == 0)
+        return TRUE;
+
+    /* String options don't consider pad bytes part of the length */
+    option_hdr.type         = (guint16)option_id;
+    option_hdr.value_length = (guint16)size;
+    if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
+        return FALSE;
+    wdh->bytes_dumped += 4;
+
+    if (!wtap_dump_file_write(wdh, str, size, err))
+        return FALSE;
+    wdh->bytes_dumped += size;
+
+    if ((size % 4)) {
+        pad = 4 - (size % 4);
+    } else {
+        pad = 0;
+    }
+
+    /* write padding (if any) */
+    if (pad != 0) {
+        if (!wtap_dump_file_write(wdh, &zero_pad, pad, err))
+            return FALSE;
+
+        wdh->bytes_dumped += pad;
+    }
+
+    return TRUE;
+}
+
+static void write_wtap_shb_option(wtap_block_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_optval_t *optval, void* user_data)
+{
+    pcapng_write_block_t* write_block = (pcapng_write_block_t*)user_data;
+
+    /* Don't continue if there has been an error */
+    if (!write_block->success)
+        return;
+
+    switch(option_id)
+    {
+    case OPT_COMMENT:
+    case OPT_SHB_HARDWARE:
+    case OPT_SHB_OS:
+    case OPT_SHB_USERAPPL:
+        if (!pcapng_write_option_string(write_block->wdh, option_id, optval->stringval, write_block->err)) {
+            write_block->success = FALSE;
+            return;
+        }
+        break;
+    default:
+        /* Unknown options - write by datatype? */
+        break;
+    }
+}
 
+/* Write a section header block.
+ * If we don't have a section block header already, create a default
+ * one with no options.
+ */
 static gboolean
 pcapng_write_section_header_block(wtap_dumper *wdh, int *err)
 {
     pcapng_block_header_t bh;
     pcapng_section_header_block_t shb;
-    const guint32 zero_pad = 0;
-    gboolean have_options = FALSE;
-    struct option option_hdr;                   /* guint16 type, guint16 value_length; */
-    guint32 options_total_length = 0;
-    guint32 comment_len = 0, shb_hardware_len = 0, shb_os_len = 0, shb_user_appl_len = 0;
-    guint32 comment_pad_len = 0, shb_hardware_pad_len = 0, shb_os_pad_len = 0, shb_user_appl_pad_len = 0;
-
-    if (wdh->shb_hdr) {
-        pcapng_debug0("pcapng_write_section_header_block: Have shb_hdr");
-        /* Check if we should write comment option */
-        if (wdh->shb_hdr->opt_comment) {
-            have_options = TRUE;
-            comment_len = (guint32)strlen(wdh->shb_hdr->opt_comment) & 0xffff;
-            if ((comment_len % 4)) {
-                comment_pad_len = 4 - (comment_len % 4);
-            } else {
-                comment_pad_len = 0;
-            }
-            options_total_length = options_total_length + comment_len + comment_pad_len + 4 /* comment options tag */ ;
-        }
+    pcapng_block_size_t block_size;
+    struct pcapng_option_header option_hdr;
+    wtap_block_t wdh_shb = NULL;
 
-        /* Check if we should write shb_hardware option */
-        if (wdh->shb_hdr->shb_hardware) {
-            have_options = TRUE;
-            shb_hardware_len = (guint32)strlen(wdh->shb_hdr->shb_hardware) & 0xffff;
-            if ((shb_hardware_len % 4)) {
-                shb_hardware_pad_len = 4 - (shb_hardware_len % 4);
-            } else {
-                shb_hardware_pad_len = 0;
-            }
-            options_total_length = options_total_length + shb_hardware_len + shb_hardware_pad_len + 4 /* options tag */ ;
-        }
+    if (wdh->shb_hdrs && (wdh->shb_hdrs->len > 0)) {
+        wdh_shb = g_array_index(wdh->shb_hdrs, wtap_block_t, 0);
+    }
 
-        /* Check if we should write shb_os option */
-        if (wdh->shb_hdr->shb_os) {
-            have_options = TRUE;
-            shb_os_len = (guint32)strlen(wdh->shb_hdr->shb_os) & 0xffff;
-            if ((shb_os_len % 4)) {
-                shb_os_pad_len = 4 - (shb_os_len % 4);
-            } else {
-                shb_os_pad_len = 0;
-            }
-            options_total_length = options_total_length + shb_os_len + shb_os_pad_len + 4 /* options tag */ ;
-        }
+    block_size.size = 0;
+    bh.block_total_length = (guint32)(sizeof(bh) + sizeof(shb) + 4);
+    if (wdh_shb) {
+        pcapng_debug("pcapng_write_section_header_block: Have shb_hdr");
 
-        /* Check if we should write shb_user_appl option */
-        if (wdh->shb_hdr->shb_user_appl) {
-            have_options = TRUE;
-            shb_user_appl_len = (guint32)strlen(wdh->shb_hdr->shb_user_appl) & 0xffff;
-            if ((shb_user_appl_len % 4)) {
-                shb_user_appl_pad_len = 4 - (shb_user_appl_len % 4);
-            } else {
-                shb_user_appl_pad_len = 0;
-            }
-            options_total_length = options_total_length + shb_user_appl_len + shb_user_appl_pad_len + 4 /* options tag */ ;
-        }
-        if (have_options) {
+        /* Compute block size */
+        wtap_block_foreach_option(wdh_shb, compute_shb_option_size, &block_size);
+
+        if (block_size.size > 0) {
             /* End-of-options tag */
-            options_total_length += 4;
+            block_size.size += 4;
         }
+
+        bh.block_total_length += block_size.size;
     }
 
+    pcapng_debug("pcapng_write_section_header_block: Total len %u", bh.block_total_length);
+
     /* write block header */
     bh.block_type = BLOCK_TYPE_SHB;
-    bh.block_total_length = (guint32)(sizeof(bh) + sizeof(shb) + options_total_length + 4);
-    pcapng_debug2("pcapng_write_section_header_block: Total len %u, Options total len %u",bh.block_total_length, options_total_length);
 
     if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err))
         return FALSE;
     wdh->bytes_dumped += sizeof bh;
 
     /* write block fixed content */
-    /* XXX - get these values from wblock? */
     shb.magic = 0x1A2B3C4D;
     shb.version_major = 1;
     shb.version_minor = 0;
-    shb.section_length = -1;
+    if (wdh_shb) {
+        wtapng_mandatory_section_t* section_data = (wtapng_mandatory_section_t*)wtap_block_get_mandatory_data(wdh_shb);
+        shb.section_length = section_data->section_length;
+    } else {
+        shb.section_length = -1;
+    }
 
     if (!wtap_dump_file_write(wdh, &shb, sizeof shb, err))
         return FALSE;
     wdh->bytes_dumped += sizeof shb;
 
-    /* XXX - write (optional) block options
-     * opt_comment  1
-     * shb_hardware 2
-     * shb_os       3
-     * shb_user_appl 4
-     */
-
-    if (comment_len) {
-        option_hdr.type          = OPT_COMMENT;
-        option_hdr.value_length = comment_len;
-        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
+    if (wdh_shb) {
+        pcapng_write_block_t block_data;
 
-        /* Write the comments string */
-        pcapng_debug3("pcapng_write_section_header_block, comment:'%s' comment_len %u comment_pad_len %u" , wdh->shb_hdr->opt_comment, comment_len, comment_pad_len);
-        if (!wtap_dump_file_write(wdh, wdh->shb_hdr->opt_comment, comment_len, err))
-            return FALSE;
-        wdh->bytes_dumped += comment_len;
+        if (block_size.size > 0) {
+            /* Write options */
+            block_data.wdh = wdh;
+            block_data.err = err;
+            block_data.success = TRUE;
+            wtap_block_foreach_option(wdh_shb, write_wtap_shb_option, &block_data);
 
-        /* write padding (if any) */
-        if (comment_pad_len != 0) {
-            if (!wtap_dump_file_write(wdh, &zero_pad, comment_pad_len, err))
+            if (!block_data.success)
                 return FALSE;
-            wdh->bytes_dumped += comment_pad_len;
-        }
-    }
-
-    if (shb_hardware_len) {
-        option_hdr.type          = OPT_SHB_HARDWARE;
-        option_hdr.value_length = shb_hardware_len;
-        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
 
-        /* Write the string */
-        pcapng_debug3("pcapng_write_section_header_block, shb_hardware:'%s' shb_hardware_len %u shb_hardware_pad_len %u" , wdh->shb_hdr->shb_hardware, shb_hardware_len, shb_hardware_pad_len);
-        if (!wtap_dump_file_write(wdh, wdh->shb_hdr->shb_hardware, shb_hardware_len, err))
-            return FALSE;
-        wdh->bytes_dumped += shb_hardware_len;
-
-        /* write padding (if any) */
-        if (shb_hardware_pad_len != 0) {
-            if (!wtap_dump_file_write(wdh, &zero_pad, shb_hardware_pad_len, err))
+            /* Write end of options */
+            option_hdr.type = OPT_EOFOPT;
+            option_hdr.value_length = 0;
+            if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
                 return FALSE;
-            wdh->bytes_dumped += shb_hardware_pad_len;
+            wdh->bytes_dumped += 4;
         }
     }
 
-    if (shb_os_len) {
-        option_hdr.type          = OPT_SHB_OS;
-        option_hdr.value_length = shb_os_len;
-        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-
-        /* Write the string */
-        pcapng_debug3("pcapng_write_section_header_block, shb_os:'%s' shb_os_len %u shb_os_pad_len %u" , wdh->shb_hdr->shb_os, shb_os_len, shb_os_pad_len);
-        if (!wtap_dump_file_write(wdh, wdh->shb_hdr->shb_os, shb_os_len, err))
-            return FALSE;
-        wdh->bytes_dumped += shb_os_len;
-
-        /* write padding (if any) */
-        if (shb_os_pad_len != 0) {
-            if (!wtap_dump_file_write(wdh, &zero_pad, shb_os_pad_len, err))
-                return FALSE;
-            wdh->bytes_dumped += shb_os_pad_len;
-        }
-    }
-
-    if (shb_user_appl_len) {
-        option_hdr.type          = OPT_SHB_USERAPPL;
-        option_hdr.value_length = shb_user_appl_len;
-        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-
-        /* Write the comments string */
-        pcapng_debug3("pcapng_write_section_header_block, shb_user_appl:'%s' shb_user_appl_len %u shb_user_appl_pad_len %u" , wdh->shb_hdr->shb_user_appl, shb_user_appl_len, shb_user_appl_pad_len);
-        if (!wtap_dump_file_write(wdh, wdh->shb_hdr->shb_user_appl, shb_user_appl_len, err))
-            return FALSE;
-        wdh->bytes_dumped += shb_user_appl_len;
-
-        /* write padding (if any) */
-        if (shb_user_appl_pad_len != 0) {
-            if (!wtap_dump_file_write(wdh, &zero_pad, shb_user_appl_pad_len, err))
-                return FALSE;
-            wdh->bytes_dumped += shb_user_appl_pad_len;
-        }
-    }
-
-    /* Write end of options if we have otions */
-    if (have_options) {
-        option_hdr.type = OPT_EOFOPT;
-        option_hdr.value_length = 0;
-        if (!wtap_dump_file_write(wdh, &zero_pad, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-    }
-
-    /* write block footer */
-    if (!wtap_dump_file_write(wdh, &bh.block_total_length,
-                              sizeof bh.block_total_length, err))
-        return FALSE;
-    wdh->bytes_dumped += sizeof bh.block_total_length;
-
-    return TRUE;
-}
-
-#define IDB_OPT_IF_NAME         2
-#define IDB_OPT_IF_DESCR        3
-#define IDB_OPT_IF_SPEED        8
-#define IDB_OPT_IF_TSRESOL      9
-#define IDB_OPT_IF_FILTER       11
-#define IDB_OPT_IF_OS           12
-
-static gboolean
-pcapng_write_if_descr_block(wtap_dumper *wdh, wtapng_if_descr_t *int_data, int *err)
-{
-    pcapng_block_header_t bh;
-    pcapng_interface_description_block_t idb;
-    const guint32 zero_pad = 0;
-    gboolean have_options = FALSE;
-    struct option option_hdr;                   /* guint16 type, guint16 value_length; */
-    guint32 options_total_length = 0;
-    guint32 comment_len = 0, if_name_len = 0, if_description_len = 0 , if_os_len = 0, if_filter_str_len = 0;
-    guint32 comment_pad_len = 0, if_name_pad_len = 0, if_description_pad_len = 0, if_os_pad_len = 0, if_filter_str_pad_len = 0;
-
-
-    pcapng_debug3("pcapng_write_if_descr_block: encap = %d (%s), snaplen = %d",
-                  int_data->link_type,
-                  wtap_encap_string(wtap_pcap_encap_to_wtap_encap(int_data->link_type)),
-                  int_data->snap_len);
-
-    if (int_data->link_type == (guint16)-1) {
-        *err = WTAP_ERR_UNSUPPORTED_ENCAP;
-        return FALSE;
-    }
-
-    /* Calculate options length */
-    if (int_data->opt_comment) {
-        have_options = TRUE;
-        comment_len = (guint32)strlen(int_data->opt_comment) & 0xffff;
-        if ((comment_len % 4)) {
-            comment_pad_len = 4 - (comment_len % 4);
-        } else {
-            comment_pad_len = 0;
-        }
-        options_total_length = options_total_length + comment_len + comment_pad_len + 4 /* comment options tag */ ;
-    }
-
-    /*
-     * if_name        2  A UTF-8 string containing the name of the device used to capture data.
-     */
-    if (int_data->if_name) {
-        have_options = TRUE;
-        if_name_len = (guint32)strlen(int_data->if_name) & 0xffff;
-        if ((if_name_len % 4)) {
-            if_name_pad_len = 4 - (if_name_len % 4);
-        } else {
-            if_name_pad_len = 0;
-        }
-        options_total_length = options_total_length + if_name_len + if_name_pad_len + 4 /* comment options tag */ ;
-    }
-
-    /*
-     * if_description 3  A UTF-8 string containing the description of the device used to capture data.
-     */
-    if (int_data->if_description) {
-        have_options = TRUE;
-        if_description_len = (guint32)strlen(int_data->if_description) & 0xffff;
-        if ((if_description_len % 4)) {
-            if_description_pad_len = 4 - (if_description_len % 4);
-        } else {
-            if_description_pad_len = 0;
-        }
-        options_total_length = options_total_length + if_description_len + if_description_pad_len + 4 /* comment options tag */ ;
-    }
-    /* Currently not handled
-     * if_IPv4addr    4  Interface network address and netmask.
-     * if_IPv6addr    5  Interface network address and prefix length (stored in the last byte).
-     * if_MACaddr     6  Interface Hardware MAC address (48 bits). 00 01 02 03 04 05
-     * if_EUIaddr     7  Interface Hardware EUI address (64 bits), if available. TODO: give a good example
-     */
-    /*
-     * if_speed       8  Interface speed (in bps). 100000000 for 100Mbps
-     */
-    if (int_data->if_speed != 0) {
-        have_options = TRUE;
-        options_total_length = options_total_length + 8 + 4;
-    }
-    /*
-     * if_tsresol     9  Resolution of timestamps.
-     */
-    if (int_data->if_tsresol != 0) {
-        have_options = TRUE;
-        options_total_length = options_total_length + 4 + 4;
-    }
-    /* Not used
-     * if_tzone      10  Time zone for GMT support (TODO: specify better). TODO: give a good example
-     */
-    /*
-     * if_filter     11  The filter (e.g. "capture only TCP traffic") used to capture traffic.
-     * The first byte of the Option Data keeps a code of the filter used (e.g. if this is a libpcap string, or BPF bytecode, and more).
-     */
-    if (int_data->if_filter_str) {
-        have_options = TRUE;
-        if_filter_str_len = (guint32)(strlen(int_data->if_filter_str) + 1) & 0xffff;
-        if ((if_filter_str_len % 4)) {
-            if_filter_str_pad_len = 4 - (if_filter_str_len % 4);
-        } else {
-            if_filter_str_pad_len = 0;
-        }
-        options_total_length = options_total_length + if_filter_str_len + if_filter_str_pad_len + 4 /* comment options tag */ ;
-    }
-    /*
-     * if_os         12  A UTF-8 string containing the name of the operating system of the machine in which this interface is installed.
-     */
-    if (int_data->if_os) {
-        have_options = TRUE;
-        if_os_len = (guint32)strlen(int_data->if_os) & 0xffff;
-        if ((if_os_len % 4)) {
-            if_os_pad_len = 4 - (if_os_len % 4);
-        } else {
-            if_os_pad_len = 0;
-        }
-        options_total_length = options_total_length + if_os_len + if_os_pad_len + 4 /* comment options tag */ ;
-    }
-    /*
-     * if_fcslen     13  An integer value that specified the length of the Frame Check Sequence (in bits) for this interface.
-     * -1 if unknown or changes between packets, opt 13  An integer value that specified the length of the Frame Check Sequence (in bits) for this interface.
-     */
-    if (int_data->if_fcslen != 0) {
-    }
-    /* Not used
-     * if_tsoffset   14  A 64 bits integer value that specifies an offset (in seconds) that must be added to the timestamp of each packet
-     * to obtain the absolute timestamp of a packet. If the option is missing, the timestamps stored in the packet must be considered absolute timestamps.
-     */
-
-    if (have_options) {
-        /* End-of-options tag */
-        options_total_length += 4;
-    }
-
-    /* write block header */
-    bh.block_type = BLOCK_TYPE_IDB;
-    bh.block_total_length = (guint32)(sizeof(bh) + sizeof(idb) + options_total_length + 4);
-
-    if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err))
-        return FALSE;
-    wdh->bytes_dumped += sizeof bh;
-
-    /* write block fixed content */
-    idb.linktype    = int_data->link_type;
-    idb.reserved    = 0;
-    idb.snaplen     = int_data->snap_len;
-
-    if (!wtap_dump_file_write(wdh, &idb, sizeof idb, err))
-        return FALSE;
-    wdh->bytes_dumped += sizeof idb;
-
-    /* XXX - write (optional) block options */
-    if (comment_len != 0) {
-        option_hdr.type         = OPT_COMMENT;
-        option_hdr.value_length = comment_len;
-        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-
-        /* Write the comments string */
-        pcapng_debug3("pcapng_write_if_descr_block, comment:'%s' comment_len %u comment_pad_len %u" , int_data->opt_comment, comment_len, comment_pad_len);
-        if (!wtap_dump_file_write(wdh, int_data->opt_comment, comment_len, err))
-            return FALSE;
-        wdh->bytes_dumped += comment_len;
-
-        /* write padding (if any) */
-        if (comment_pad_len != 0) {
-            if (!wtap_dump_file_write(wdh, &zero_pad, comment_pad_len, err))
-                return FALSE;
-            wdh->bytes_dumped += comment_pad_len;
-        }
-    }
-    /*
-     * if_name        2  A UTF-8 string containing the name of the device used to capture data.
-     */
-    if (if_name_len !=0) {
-        option_hdr.type = IDB_OPT_IF_NAME;
-        option_hdr.value_length = if_name_len;
-        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-
-        /* Write the comments string */
-        pcapng_debug3("pcapng_write_if_descr_block, if_name:'%s' if_name_len %u if_name_pad_len %u" , int_data->if_name, if_name_len, if_name_pad_len);
-        if (!wtap_dump_file_write(wdh, int_data->if_name, if_name_len, err))
-            return FALSE;
-        wdh->bytes_dumped += if_name_len;
-
-        /* write padding (if any) */
-        if (if_name_pad_len != 0) {
-            if (!wtap_dump_file_write(wdh, &zero_pad, if_name_pad_len, err))
-                return FALSE;
-            wdh->bytes_dumped += if_name_pad_len;
-        }
-    }
-    /*
-     * if_description 3  A UTF-8 string containing the description of the device used to capture data.
-     */
-    if (if_description_len != 0) {
-        option_hdr.type          = IDB_OPT_IF_NAME;
-        option_hdr.value_length = if_description_len;
-        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-
-        /* Write the comments string */
-        pcapng_debug3("pcapng_write_if_descr_block, if_description:'%s' if_description_len %u if_description_pad_len %u" , int_data->if_description, if_description_len, if_description_pad_len);
-        if (!wtap_dump_file_write(wdh, int_data->if_description, if_description_len, err))
-            return FALSE;
-        wdh->bytes_dumped += if_description_len;
-
-        /* write padding (if any) */
-        if (if_description_pad_len != 0) {
-            if (!wtap_dump_file_write(wdh, &zero_pad, if_description_pad_len, err))
-                return FALSE;
-            wdh->bytes_dumped += if_description_pad_len;
-        }
-    }
-    /* Currently not handled
-     * if_IPv4addr    4  Interface network address and netmask.
-     * if_IPv6addr    5  Interface network address and prefix length (stored in the last byte).
-     * if_MACaddr     6  Interface Hardware MAC address (48 bits). 00 01 02 03 04 05
-     * if_EUIaddr     7  Interface Hardware EUI address (64 bits), if available. TODO: give a good example
-     */
-    /*
-     * if_speed       8  Interface speed (in bps). 100000000 for 100Mbps
-     */
-    if (int_data->if_speed != 0) {
-        option_hdr.type          = IDB_OPT_IF_SPEED;
-        option_hdr.value_length = 8;
-        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-
-        /* Write the comments string */
-        pcapng_debug1("pcapng_write_if_descr_block: if_speed %" G_GINT64_MODIFIER "u (bps)", int_data->if_speed);
-        if (!wtap_dump_file_write(wdh, &int_data->if_speed, sizeof(guint64), err))
-            return FALSE;
-        wdh->bytes_dumped += 8;
-    }
-    /*
-     * if_tsresol     9  Resolution of timestamps.
-     * default is 6 for microsecond resolution, opt 9  Resolution of timestamps.
-     * If the Most Significant Bit is equal to zero, the remaining bits indicates
-     * the resolution of the timestamp as as a negative power of 10
-     */
-    if (int_data->if_tsresol != 0) {
-        option_hdr.type          = IDB_OPT_IF_TSRESOL;
-        option_hdr.value_length = 1;
-        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-
-        /* Write the time stamp resolution */
-        pcapng_debug1("pcapng_write_if_descr_block: if_tsresol %u", int_data->if_tsresol);
-        if (!wtap_dump_file_write(wdh, &int_data->if_tsresol, 1, err))
-            return FALSE;
-        wdh->bytes_dumped += 1;
-        if (!wtap_dump_file_write(wdh, &zero_pad, 3, err))
-            return FALSE;
-        wdh->bytes_dumped += 3;
-    }
-    /* not used
-     * if_tzone      10  Time zone for GMT support (TODO: specify better). TODO: give a good example
-     */
-    /*
-     * if_filter     11  The filter (e.g. "capture only TCP traffic") used to capture traffic.
-     */
-    /* Libpcap string variant */
-    if (if_filter_str_len !=0) {
-        option_hdr.type          = IDB_OPT_IF_FILTER;
-        option_hdr.value_length = if_filter_str_len;
-        /* if_filter_str_len includes the leading byte indicating filter type (libpcap str or BPF code) */
-        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-
-        /* Write the zero indicating libpcap filter variant */
-        if (!wtap_dump_file_write(wdh, &zero_pad, 1, err))
-            return FALSE;
-        wdh->bytes_dumped += 1;
-
-        /* Write the comments string */
-        pcapng_debug3("pcapng_write_if_descr_block, if_filter_str:'%s' if_filter_str_len %u if_filter_str_pad_len %u" , int_data->if_filter_str, if_filter_str_len, if_filter_str_pad_len);
-        /* if_filter_str_len includes the leading byte indicating filter type (libpcap str or BPF code) */
-        if (!wtap_dump_file_write(wdh, int_data->if_filter_str, if_filter_str_len-1, err))
-            return FALSE;
-        wdh->bytes_dumped += if_filter_str_len - 1;
-
-        /* write padding (if any) */
-        if (if_filter_str_pad_len != 0) {
-            if (!wtap_dump_file_write(wdh, &zero_pad, if_filter_str_pad_len, err))
-                return FALSE;
-            wdh->bytes_dumped += if_filter_str_pad_len;
-        }
-    }
-    /*
-     * if_os         12  A UTF-8 string containing the name of the operating system of the machine in which this interface is installed.
-     */
-    if (if_os_len != 0) {
-        option_hdr.type          = IDB_OPT_IF_OS;
-        option_hdr.value_length = if_os_len;
-        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-
-        /* Write the comments string */
-        pcapng_debug3("pcapng_write_if_descr_block, if_os:'%s' if_os_len %u if_os_pad_len %u" , int_data->if_os, if_os_len, if_os_pad_len);
-        if (!wtap_dump_file_write(wdh, int_data->if_os, if_os_len, err))
-            return FALSE;
-        wdh->bytes_dumped += if_os_len;
-
-        /* write padding (if any) */
-        if (if_os_pad_len != 0) {
-            if (!wtap_dump_file_write(wdh, &zero_pad, if_os_pad_len, err))
-                return FALSE;
-            wdh->bytes_dumped += if_os_pad_len;
-        }
-    }
-
-    if (have_options) {
-        option_hdr.type = OPT_EOFOPT;
-        option_hdr.value_length = 0;
-        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-    }
-
-    /*
-     * if_fcslen     13  An integer value that specified the length of the Frame Check Sequence (in bits) for this interface.
-     */
-    /*
-     * if_tsoffset   14  A 64 bits integer value that specifies an offset (in seconds) that must be added to the timestamp of each packet
-     * to obtain the absolute timestamp of a packet. If the option is missing, the timestamps stored in the packet must be considered absolute timestamps.
-     */
-
-    /* write block footer */
-    if (!wtap_dump_file_write(wdh, &bh.block_total_length,
-                              sizeof bh.block_total_length, err))
-        return FALSE;
-    wdh->bytes_dumped += sizeof bh.block_total_length;
-
-    return TRUE;
-}
-
-#define ISB_STARTTIME     2
-#define ISB_ENDTIME       3
-#define ISB_IFRECV        4
-#define ISB_IFDROP        5
-#define ISB_FILTERACCEPT  6
-#define ISB_OSDROP        7
-#define ISB_USRDELIV      8
-
-static gboolean
-pcapng_write_interface_statistics_block(wtap_dumper *wdh, wtapng_if_stats_t *if_stats, int *err)
-{
-
-    pcapng_block_header_t bh;
-    pcapng_interface_statistics_block_t isb;
-    const guint32 zero_pad = 0;
-    gboolean have_options = FALSE;
-    struct option option_hdr;                   /* guint16 type, guint16 value_length; */
-    guint32 options_total_length = 0;
-    guint32 comment_len = 0;
-    guint32 comment_pad_len = 0;
-
-    pcapng_debug0("pcapng_write_interface_statistics_block");
-
-
-    /* Calculate options length */
-    if (if_stats->opt_comment) {
-        have_options = TRUE;
-        comment_len = (guint32)strlen(if_stats->opt_comment) & 0xffff;
-        if ((comment_len % 4)) {
-            comment_pad_len = 4 - (comment_len % 4);
-        } else {
-            comment_pad_len = 0;
-        }
-        options_total_length = options_total_length + comment_len + comment_pad_len + 4 /* comment options tag */ ;
-    }
-    /*guint64                           isb_starttime */
-    if (if_stats->isb_starttime != 0) {
-        have_options = TRUE;
-        options_total_length = options_total_length + 8 + 4 /* options tag */ ;
-    }
-    /*guint64                           isb_endtime */
-    if (if_stats->isb_endtime != 0) {
-        have_options = TRUE;
-        options_total_length = options_total_length + 8 + 4 /* options tag */ ;
-    }
-    /*guint64                           isb_ifrecv */
-    if (if_stats->isb_ifrecv != G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)) {
-        have_options = TRUE;
-        options_total_length = options_total_length + 8 + 4 /* options tag */ ;
-    }
-    /*guint64                           isb_ifdrop */
-    if (if_stats->isb_ifdrop != G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)) {
-        have_options = TRUE;
-        options_total_length = options_total_length + 8 + 4 /* options tag */ ;
-    }
-    /*guint64                           isb_filteraccept */
-    if (if_stats->isb_filteraccept != G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)) {
-        have_options = TRUE;
-        options_total_length = options_total_length + 8 + 4 /* options tag */ ;
-    }
-    /*guint64                           isb_osdrop */
-    if (if_stats->isb_osdrop != G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)) {
-        have_options = TRUE;
-        options_total_length = options_total_length + 8 + 4 /* options tag */ ;
-    }
-    /*guint64                           isb_usrdeliv */
-    if (if_stats->isb_usrdeliv != G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)) {
-        have_options = TRUE;
-        options_total_length = options_total_length + 8 + 4 /* options tag */ ;
-    }
-
-    /* write block header */
-    if (have_options) {
-        /* End-of-optios tag */
-        options_total_length += 4;
-    }
-
-    /* write block header */
-    bh.block_type = BLOCK_TYPE_ISB;
-    bh.block_total_length = (guint32)(sizeof(bh) + sizeof(isb) + options_total_length + 4);
-
-    if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err))
-        return FALSE;
-    wdh->bytes_dumped += sizeof bh;
-
-    /* write block fixed content */
-    isb.interface_id                = if_stats->interface_id;
-    isb.timestamp_high              = if_stats->ts_high;
-    isb.timestamp_low               = if_stats->ts_low;
-
-
-    if (!wtap_dump_file_write(wdh, &isb, sizeof isb, err))
-        return FALSE;
-    wdh->bytes_dumped += sizeof isb;
-
-    /* write (optional) block options */
-    if (comment_len) {
-        option_hdr.type          = OPT_COMMENT;
-        option_hdr.value_length  = comment_len;
-        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-
-        /* Write the comments string */
-        pcapng_debug3("pcapng_write_interface_statistics_block, comment:'%s' comment_len %u comment_pad_len %u" , if_stats->opt_comment, comment_len, comment_pad_len);
-        if (!wtap_dump_file_write(wdh, if_stats->opt_comment, comment_len, err))
-            return FALSE;
-        wdh->bytes_dumped += comment_len;
-
-        /* write padding (if any) */
-        if (comment_pad_len != 0) {
-            if (!wtap_dump_file_write(wdh, &zero_pad, comment_pad_len, err))
-                return FALSE;
-            wdh->bytes_dumped += comment_pad_len;
-        }
-    }
-    /*guint64               isb_starttime */
-    if (if_stats->isb_starttime != 0) {
-        guint32 high, low;
-
-        option_hdr.type = ISB_STARTTIME;
-        option_hdr.value_length = 8;
-        high = (guint32)((if_stats->isb_starttime>>32) & 0xffffffff);
-        low = (guint32)(if_stats->isb_starttime & 0xffffffff);
-        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-
-        /* Write isb_starttime */
-        pcapng_debug1("pcapng_write_interface_statistics_block, isb_starttime: %" G_GINT64_MODIFIER "u" , if_stats->isb_starttime);
-        if (!wtap_dump_file_write(wdh, &high, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-        if (!wtap_dump_file_write(wdh, &low, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-    }
-    /*guint64               isb_endtime */
-    if (if_stats->isb_endtime != 0) {
-        guint32 high, low;
-
-        option_hdr.type = ISB_ENDTIME;
-        option_hdr.value_length = 8;
-        high = (guint32)((if_stats->isb_endtime>>32) & 0xffffffff);
-        low = (guint32)(if_stats->isb_endtime & 0xffffffff);
-        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-
-        /* Write isb_endtime */
-        pcapng_debug1("pcapng_write_interface_statistics_block, isb_starttime: %" G_GINT64_MODIFIER "u" , if_stats->isb_endtime);
-        if (!wtap_dump_file_write(wdh, &high, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-        if (!wtap_dump_file_write(wdh, &low, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-    }
-    /*guint64               isb_ifrecv;*/
-    if (if_stats->isb_ifrecv != G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)) {
-        option_hdr.type          = ISB_IFRECV;
-        option_hdr.value_length  = 8;
-        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-
-        /* Write isb_ifrecv */
-        pcapng_debug1("pcapng_write_interface_statistics_block, isb_ifrecv: %" G_GINT64_MODIFIER "u" , if_stats->isb_ifrecv);
-        if (!wtap_dump_file_write(wdh, &if_stats->isb_ifrecv, 8, err))
-            return FALSE;
-        wdh->bytes_dumped += 8;
-    }
-    /*guint64               isb_ifdrop;*/
-    if (if_stats->isb_ifdrop != G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)) {
-        option_hdr.type          = ISB_IFDROP;
-        option_hdr.value_length  = 8;
-        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-
-        /* Write isb_ifdrop */
-        pcapng_debug1("pcapng_write_interface_statistics_block, isb_ifdrop: %" G_GINT64_MODIFIER "u" , if_stats->isb_ifdrop);
-        if (!wtap_dump_file_write(wdh, &if_stats->isb_ifdrop, 8, err))
-            return FALSE;
-        wdh->bytes_dumped += 8;
-    }
-    /*guint64               isb_filteraccept;*/
-    if (if_stats->isb_filteraccept != G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)) {
-        option_hdr.type          = ISB_FILTERACCEPT;
-        option_hdr.value_length  = 8;
-        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-
-        /* Write isb_filteraccept */
-        pcapng_debug1("pcapng_write_interface_statistics_block, isb_filteraccept: %" G_GINT64_MODIFIER "u" , if_stats->isb_filteraccept);
-        if (!wtap_dump_file_write(wdh, &if_stats->isb_filteraccept, 8, err))
-            return FALSE;
-        wdh->bytes_dumped += 8;
-    }
-    /*guint64               isb_osdrop;*/
-    if (if_stats->isb_osdrop != G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)) {
-        option_hdr.type          = ISB_OSDROP;
-        option_hdr.value_length  = 8;
-        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-
-        /* Write isb_osdrop */
-        pcapng_debug1("pcapng_write_interface_statistics_block, isb_osdrop: %" G_GINT64_MODIFIER "u" , if_stats->isb_osdrop);
-        if (!wtap_dump_file_write(wdh, &if_stats->isb_osdrop, 8, err))
-            return FALSE;
-        wdh->bytes_dumped += 8;
-    }
-    /*guint64               isb_usrdeliv;*/
-    if (if_stats->isb_usrdeliv != G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)) {
-        option_hdr.type          = ISB_USRDELIV;
-        option_hdr.value_length  = 8;
-        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-
-        /* Write isb_usrdeliv */
-        pcapng_debug1("pcapng_write_interface_statistics_block, isb_usrdeliv: %" G_GINT64_MODIFIER "u" , if_stats->isb_usrdeliv);
-        if (!wtap_dump_file_write(wdh, &if_stats->isb_usrdeliv, 8, err))
-            return FALSE;
-        wdh->bytes_dumped += 8;
-    }
-
-    if (have_options) {
-        option_hdr.type = OPT_EOFOPT;
-        option_hdr.value_length = 0;
-        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
-            return FALSE;
-        wdh->bytes_dumped += 4;
-    }
-
-    /* write block footer */
-    if (!wtap_dump_file_write(wdh, &bh.block_total_length,
-                              sizeof bh.block_total_length, err))
-        return FALSE;
-    wdh->bytes_dumped += sizeof bh.block_total_length;
-
-    return TRUE;
-
-}
+    /* write block footer */
+    if (!wtap_dump_file_write(wdh, &bh.block_total_length,
+                              sizeof bh.block_total_length, err))
+        return FALSE;
+    wdh->bytes_dumped += sizeof bh.block_total_length;
 
+    return TRUE;
+}
 
 static gboolean
-pcapng_write_enhanced_packet_block(wtap_dumper *wdh,
-                                   const struct wtap_pkthdr *phdr,
-                                   const union wtap_pseudo_header *pseudo_header, const guint8 *pd, int *err)
+pcapng_write_enhanced_packet_block(wtap_dumper *wdh, const wtap_rec *rec,
+                                   const guint8 *pd, int *err)
 {
+    const union wtap_pseudo_header *pseudo_header = &rec->rec_header.packet_header.pseudo_header;
     pcapng_block_header_t bh;
     pcapng_enhanced_packet_block_t epb;
     guint64 ts;
@@ -3264,25 +2989,26 @@ pcapng_write_enhanced_packet_block(wtap_dumper *wdh,
     guint32 options_total_length = 0;
     struct option option_hdr;
     guint32 comment_len = 0, comment_pad_len = 0;
-    wtapng_if_descr_t int_data;
+    wtap_block_t int_data;
+    wtapng_if_descr_mandatory_t *int_data_mand;
 
     /* Don't write anything we're not willing to read. */
-    if (phdr->caplen > WTAP_MAX_PACKET_SIZE) {
+    if (rec->rec_header.packet_header.caplen > wtap_max_snaplen_for_encap(wdh->encap)) {
         *err = WTAP_ERR_PACKET_TOO_LARGE;
         return FALSE;
     }
 
-    phdr_len = (guint32)pcap_get_phdr_size(phdr->pkt_encap, pseudo_header);
-    if ((phdr_len + phdr->caplen) % 4) {
-        pad_len = 4 - ((phdr_len + phdr->caplen) % 4);
+    phdr_len = (guint32)pcap_get_phdr_size(rec->rec_header.packet_header.pkt_encap, pseudo_header);
+    if ((phdr_len + rec->rec_header.packet_header.caplen) % 4) {
+        pad_len = 4 - ((phdr_len + rec->rec_header.packet_header.caplen) % 4);
     } else {
         pad_len = 0;
     }
 
     /* Check if we should write comment option */
-    if (phdr->opt_comment) {
+    if (rec->opt_comment) {
         have_options = TRUE;
-        comment_len = (guint32)strlen(phdr->opt_comment) & 0xffff;
+        comment_len = (guint32)strlen(rec->opt_comment) & 0xffff;
         if ((comment_len % 4)) {
             comment_pad_len = 4 - (comment_len % 4);
         } else {
@@ -3290,30 +3016,30 @@ pcapng_write_enhanced_packet_block(wtap_dumper *wdh,
         }
         options_total_length = options_total_length + comment_len + comment_pad_len + 4 /* comment options tag */ ;
     }
-    if (phdr->presence_flags & WTAP_HAS_PACK_FLAGS) {
+    if (rec->presence_flags & WTAP_HAS_PACK_FLAGS) {
         have_options = TRUE;
         options_total_length = options_total_length + 8;
     }
     if (have_options) {
-        /* End-of optios tag */
+        /* End-of options tag */
         options_total_length += 4;
     }
 
     /* write (enhanced) packet block header */
     bh.block_type = BLOCK_TYPE_EPB;
-    bh.block_total_length = (guint32)sizeof(bh) + (guint32)sizeof(epb) + phdr_len + phdr->caplen + pad_len + options_total_length + 4;
+    bh.block_total_length = (guint32)sizeof(bh) + (guint32)sizeof(epb) + phdr_len + rec->rec_header.packet_header.caplen + pad_len + options_total_length + 4;
 
     if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err))
         return FALSE;
     wdh->bytes_dumped += sizeof bh;
 
     /* write block fixed content */
-    if (phdr->presence_flags & WTAP_HAS_INTERFACE_ID)
-        epb.interface_id        = phdr->interface_id;
+    if (rec->presence_flags & WTAP_HAS_INTERFACE_ID)
+        epb.interface_id        = rec->rec_header.packet_header.interface_id;
     else {
         /*
          * XXX - we should support writing WTAP_ENCAP_PER_PACKET
-         * data to pcap-NG files even if we *don't* have interface
+         * data to pcapng files even if we *don't* have interface
          * IDs.
          */
         epb.interface_id        = 0;
@@ -3329,29 +3055,30 @@ pcapng_write_enhanced_packet_block(wtap_dumper *wdh,
         *err = WTAP_ERR_INTERNAL;
         return FALSE;
     }
-    int_data = g_array_index(wdh->interface_data, wtapng_if_descr_t,
+    int_data = g_array_index(wdh->interface_data, wtap_block_t,
                              epb.interface_id);
-    ts = ((guint64)phdr->ts.secs) * int_data.time_units_per_second +
-        (((guint64)phdr->ts.nsecs) * int_data.time_units_per_second) / 1000000000;
+    int_data_mand = (wtapng_if_descr_mandatory_t*)wtap_block_get_mandatory_data(int_data);
+    ts = ((guint64)rec->ts.secs) * int_data_mand->time_units_per_second +
+        (((guint64)rec->ts.nsecs) * int_data_mand->time_units_per_second) / 1000000000;
     epb.timestamp_high      = (guint32)(ts >> 32);
     epb.timestamp_low       = (guint32)ts;
-    epb.captured_len        = phdr->caplen + phdr_len;
-    epb.packet_len          = phdr->len + phdr_len;
+    epb.captured_len        = rec->rec_header.packet_header.caplen + phdr_len;
+    epb.packet_len          = rec->rec_header.packet_header.len + phdr_len;
 
     if (!wtap_dump_file_write(wdh, &epb, sizeof epb, err))
         return FALSE;
     wdh->bytes_dumped += sizeof epb;
 
     /* write pseudo header */
-    if (!pcap_write_phdr(wdh, phdr->pkt_encap, pseudo_header, err)) {
+    if (!pcap_write_phdr(wdh, rec->rec_header.packet_header.pkt_encap, pseudo_header, err)) {
         return FALSE;
     }
     wdh->bytes_dumped += phdr_len;
 
     /* write packet data */
-    if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
+    if (!wtap_dump_file_write(wdh, pd, rec->rec_header.packet_header.caplen, err))
         return FALSE;
-    wdh->bytes_dumped += phdr->caplen;
+    wdh->bytes_dumped += rec->rec_header.packet_header.caplen;
 
     /* write padding (if any) */
     if (pad_len != 0) {
@@ -3381,7 +3108,7 @@ pcapng_write_enhanced_packet_block(wtap_dumper *wdh,
      *                                between this packet and the preceding one.
      * opt_endofopt    0   0          It delimits the end of the optional fields. This block cannot be repeated within a given list of options.
      */
-    if (phdr->opt_comment) {
+    if (rec->opt_comment) {
         option_hdr.type         = OPT_COMMENT;
         option_hdr.value_length = comment_len;
         if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
@@ -3389,8 +3116,8 @@ pcapng_write_enhanced_packet_block(wtap_dumper *wdh,
         wdh->bytes_dumped += 4;
 
         /* Write the comments string */
-        pcapng_debug3("pcapng_write_enhanced_packet_block, comment:'%s' comment_len %u comment_pad_len %u" , phdr->opt_comment, comment_len, comment_pad_len);
-        if (!wtap_dump_file_write(wdh, phdr->opt_comment, comment_len, err))
+        pcapng_debug("pcapng_write_enhanced_packet_block, comment:'%s' comment_len %u comment_pad_len %u" , rec->opt_comment, comment_len, comment_pad_len);
+        if (!wtap_dump_file_write(wdh, rec->opt_comment, comment_len, err))
             return FALSE;
         wdh->bytes_dumped += comment_len;
 
@@ -3401,104 +3128,423 @@ pcapng_write_enhanced_packet_block(wtap_dumper *wdh,
             wdh->bytes_dumped += comment_pad_len;
         }
 
-        pcapng_debug2("pcapng_write_enhanced_packet_block: Wrote Options comments: comment_len %u, comment_pad_len %u",
+        pcapng_debug("pcapng_write_enhanced_packet_block: Wrote Options comments: comment_len %u, comment_pad_len %u",
                       comment_len,
                       comment_pad_len);
     }
-    if (phdr->presence_flags & WTAP_HAS_PACK_FLAGS) {
+    if (rec->presence_flags & WTAP_HAS_PACK_FLAGS) {
         option_hdr.type         = OPT_EPB_FLAGS;
         option_hdr.value_length = 4;
         if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
             return FALSE;
         wdh->bytes_dumped += 4;
-        if (!wtap_dump_file_write(wdh, &phdr->pack_flags, 4, err))
+        if (!wtap_dump_file_write(wdh, &rec->rec_header.packet_header.pack_flags, 4, err))
             return FALSE;
         wdh->bytes_dumped += 4;
-        pcapng_debug1("pcapng_write_enhanced_packet_block: Wrote Options packet flags: %x", phdr->pack_flags);
+        pcapng_debug("pcapng_write_enhanced_packet_block: Wrote Options packet flags: %x", rec->rec_header.packet_header.pack_flags);
     }
-    /* Write end of options if we have otions */
+    /* Write end of options if we have options */
     if (have_options) {
         if (!wtap_dump_file_write(wdh, &zero_pad, 4, err))
             return FALSE;
-        wdh->bytes_dumped += 4;
+        wdh->bytes_dumped += 4;
+    }
+
+    /* write block footer */
+    if (!wtap_dump_file_write(wdh, &bh.block_total_length,
+                              sizeof bh.block_total_length, err))
+        return FALSE;
+    wdh->bytes_dumped += sizeof bh.block_total_length;
+
+    return TRUE;
+}
+
+static gboolean
+pcapng_write_sysdig_event_block(wtap_dumper *wdh, const wtap_rec *rec,
+                                const guint8 *pd, int *err)
+{
+    pcapng_block_header_t bh;
+    const guint32 zero_pad = 0;
+    guint32 pad_len;
+#if 0
+    gboolean have_options = FALSE;
+    struct option option_hdr;
+    guint32 comment_len = 0, comment_pad_len = 0;
+#endif
+    guint32 options_total_length = 0;
+    guint16 cpu_id;
+    guint64 hdr_ts;
+    guint64 ts;
+    guint64 thread_id;
+    guint32 event_len;
+    guint16 event_type;
+
+    /* Don't write anything we're not willing to read. */
+    if (rec->rec_header.syscall_header.event_filelen > WTAP_MAX_PACKET_SIZE_STANDARD) {
+        *err = WTAP_ERR_PACKET_TOO_LARGE;
+        return FALSE;
+    }
+
+    if (rec->rec_header.syscall_header.event_filelen % 4) {
+        pad_len = 4 - (rec->rec_header.syscall_header.event_filelen % 4);
+    } else {
+        pad_len = 0;
+    }
+
+#if 0
+    /* Check if we should write comment option */
+    if (rec->opt_comment) {
+        have_options = TRUE;
+        comment_len = (guint32)strlen(rec->opt_comment) & 0xffff;
+        if ((comment_len % 4)) {
+            comment_pad_len = 4 - (comment_len % 4);
+        } else {
+            comment_pad_len = 0;
+        }
+        options_total_length = options_total_length + comment_len + comment_pad_len + 4 /* comment options tag */ ;
+    }
+    if (have_options) {
+        /* End-of options tag */
+        options_total_length += 4;
+    }
+#endif
+
+    /* write sysdig event block header */
+    bh.block_type = BLOCK_TYPE_SYSDIG_EVENT;
+    bh.block_total_length = (guint32)sizeof(bh) + SYSDIG_EVENT_HEADER_SIZE + rec->rec_header.syscall_header.event_filelen + pad_len + options_total_length + 4;
+
+    if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err))
+        return FALSE;
+    wdh->bytes_dumped += sizeof bh;
+
+    /* Sysdig is always LE? */
+    cpu_id = GUINT16_TO_LE(rec->rec_header.syscall_header.cpu_id);
+    hdr_ts = (((guint64)rec->ts.secs) * 1000000000) + rec->ts.nsecs;
+    ts = GUINT64_TO_LE(hdr_ts);
+    thread_id = GUINT64_TO_LE(rec->rec_header.syscall_header.thread_id);
+    event_len = GUINT32_TO_LE(rec->rec_header.syscall_header.event_len);
+    event_type = GUINT16_TO_LE(rec->rec_header.syscall_header.event_type);
+
+    if (!wtap_dump_file_write(wdh, &cpu_id, sizeof cpu_id, err))
+        return FALSE;
+    wdh->bytes_dumped += sizeof cpu_id;
+
+    if (!wtap_dump_file_write(wdh, &ts, sizeof ts, err))
+        return FALSE;
+    wdh->bytes_dumped += sizeof ts;
+
+    if (!wtap_dump_file_write(wdh, &thread_id, sizeof thread_id, err))
+        return FALSE;
+    wdh->bytes_dumped += sizeof thread_id;
+
+    if (!wtap_dump_file_write(wdh, &event_len, sizeof event_len, err))
+        return FALSE;
+    wdh->bytes_dumped += sizeof event_len;
+
+    if (!wtap_dump_file_write(wdh, &event_type, sizeof event_type, err))
+        return FALSE;
+    wdh->bytes_dumped += sizeof event_type;
+
+    /* write event data */
+    if (!wtap_dump_file_write(wdh, pd, rec->rec_header.syscall_header.event_filelen, err))
+        return FALSE;
+    wdh->bytes_dumped += rec->rec_header.syscall_header.event_filelen;
+
+    /* write padding (if any) */
+    if (pad_len != 0) {
+        if (!wtap_dump_file_write(wdh, &zero_pad, pad_len, err))
+            return FALSE;
+        wdh->bytes_dumped += pad_len;
     }
 
+    /* XXX Write comment? */
+
     /* write block footer */
     if (!wtap_dump_file_write(wdh, &bh.block_total_length,
                               sizeof bh.block_total_length, err))
         return FALSE;
-    wdh->bytes_dumped += sizeof bh.block_total_length;
 
     return TRUE;
+
+}
+
+/*
+ * libpcap's maximum pcapng block size is currently 16MB.
+ *
+ * The maximum pcapng block size in macOS's private pcapng reading code
+ * is 1MB.  (Yes, this means that a program using the standard pcap
+ * code to read pcapng files can handle bigger blocks than can programs
+ * using the private code, such as Apple's tcpdump, can handle.)
+ *
+ * The pcapng reading code here can handle NRBs of arbitrary size (less
+ * than 4GB, obviously), as they read each NRB record independently,
+ * rather than reading the entire block into memory.
+ *
+ * So, for now, we set the maximum NRB block size we write as 1 MB.
+ *
+ * (Yes, for the benefit of the fussy, "MB" is really "MiB".)
+ */
+
+#define NRES_BLOCK_MAX_SIZE (1024*1024)
+
+static void
+compute_nrb_option_size(wtap_block_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_optval_t* optval, void* user_data)
+{
+    pcapng_block_size_t* block_size = (pcapng_block_size_t*)user_data;
+    guint32 size = 0;
+
+    switch(option_id)
+    {
+    case OPT_COMMENT:
+    case OPT_NS_DNSNAME:
+        size = pcapng_compute_option_string_size(optval->stringval);
+        break;
+    case OPT_NS_DNSIP4ADDR:
+        size = 4;
+        break;
+    case OPT_NS_DNSIP6ADDR:
+        size = 16;
+        break;
+    default:
+        /* Unknown options - size by datatype? */
+        break;
+    }
+
+    block_size->size += size;
+    /* Add bytes for option header if option should be written */
+    if (size > 0) {
+        /* Add optional padding to 32 bits */
+        if ((block_size->size & 0x03) != 0)
+        {
+            block_size->size += 4 - (block_size->size & 0x03);
+        }
+        block_size->size += 4;
+    }
+}
+
+static void
+put_nrb_option(wtap_block_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_optval_t* optval, void* user_data)
+{
+    guint8 **opt_ptrp = (guint8 **)user_data;
+    guint32 size = 0;
+    struct pcapng_option_header option_hdr;
+    guint32 pad;
+
+    switch(option_id)
+    {
+    case OPT_COMMENT:
+    case OPT_NS_DNSNAME:
+        /* String options don't consider pad bytes part of the length */
+        size = (guint32)strlen(optval->stringval) & 0xffff;
+        option_hdr.type         = (guint16)option_id;
+        option_hdr.value_length = (guint16)size;
+        memcpy(*opt_ptrp, &option_hdr, 4);
+        *opt_ptrp += 4;
+
+        memcpy(*opt_ptrp, optval->stringval, size);
+        *opt_ptrp += size;
+
+        if ((size % 4)) {
+            pad = 4 - (size % 4);
+        } else {
+            pad = 0;
+        }
+
+        /* put padding (if any) */
+        if (pad != 0) {
+            memset(*opt_ptrp, 0, pad);
+            *opt_ptrp += pad;
+        }
+        break;
+    case OPT_NS_DNSIP4ADDR:
+        option_hdr.type         = (guint16)option_id;
+        option_hdr.value_length = 4;
+        memcpy(*opt_ptrp, &option_hdr, 4);
+        *opt_ptrp += 4;
+
+        memcpy(*opt_ptrp, &optval->ipv4val, 4);
+        *opt_ptrp += 4;
+        break;
+    case OPT_NS_DNSIP6ADDR:
+        option_hdr.type         = (guint16)option_id;
+        option_hdr.value_length = 16;
+        memcpy(*opt_ptrp, &option_hdr, 4);
+        *opt_ptrp += 4;
+
+        memcpy(*opt_ptrp, &optval->ipv6val, 16);
+        *opt_ptrp += 16;
+        break;
+    default:
+        /* Unknown options - size by datatype? */
+        break;
+    }
+}
+
+static void
+put_nrb_options(wtap_dumper *wdh, guint8 *opt_ptr)
+{
+    if (wdh->nrb_hdrs && wdh->nrb_hdrs->len > 0) {
+        wtap_block_t nrb_hdr = g_array_index(wdh->nrb_hdrs, wtap_block_t, 0);
+        struct option option_hdr;
+
+        wtap_block_foreach_option(nrb_hdr, put_nrb_option, &opt_ptr);
+
+        /* Put end of options */
+        option_hdr.type = OPT_EOFOPT;
+        option_hdr.value_length = 0;
+        memcpy(opt_ptr, &option_hdr, 4);
+    }
 }
 
-/* Arbitrary. */
-#define NRES_REC_MAX_SIZE ((WTAP_MAX_PACKET_SIZE * 4) + 16)
 static gboolean
 pcapng_write_name_resolution_block(wtap_dumper *wdh, int *err)
 {
     pcapng_block_header_t bh;
     pcapng_name_resolution_block_t nrb;
-    guint8 *rec_data;
-    gint rec_off, namelen, tot_rec_len;
+    pcapng_block_size_t opts_size;
+    size_t max_rec_data_size;
+    guint8 *block_data;
+    guint32 block_off;
+    size_t hostnamelen;
+    guint16 namelen;
+    guint32 tot_rec_len;
     hashipv4_t *ipv4_hash_list_entry;
     hashipv6_t *ipv6_hash_list_entry;
     int i;
 
-    if ((!wdh->addrinfo_lists) || ((!wdh->addrinfo_lists->ipv4_addr_list)&&(!wdh->addrinfo_lists->ipv6_addr_list))) {
+    if (wtap_addrinfo_list_empty(wdh->addrinfo_lists)) {
+        /*
+         * No name/address pairs to write.
+         * XXX - what if we have options?
+         */
+        return TRUE;
+    }
+
+    /* Calculate the space needed for options. */
+    opts_size.size = 0;
+    if (wdh->nrb_hdrs && wdh->nrb_hdrs->len > 0) {
+        wtap_block_t nrb_hdr = g_array_index(wdh->nrb_hdrs, wtap_block_t, 0);
+
+        wtap_block_foreach_option(nrb_hdr, compute_nrb_option_size, &opts_size);
+        if (opts_size.size > 0) {
+            /* End-of options tag */
+            opts_size.size += 4;
+        }
+    }
+
+    /*
+     * Make sure we can fit at least one maximum-sized record, plus
+     * an end-of-records record, plus the options, into a maximum-sized
+     * block.
+     *
+     * That requires that there be enough space for the block header
+     * (8 bytes), a maximum-sized record (2 bytes of record type, 2
+     * bytes of record value length, 65535 bytes of record value,
+     * and 1 byte of padding), an end-of-records record (4 bytes),
+     * the options (opts_size.size bytes), and the block trailer (4
+     * bytes).
+     */
+    if (8 + 2 + 2 + 65535 + 1 + 4 + opts_size.size + 4 > NRES_BLOCK_MAX_SIZE) {
+        /*
+         * XXX - we can't even fit the options in the largest NRB size
+         * we're willing to write and still have room enough for a
+         * maximum-sized record.  Just discard the information for now.
+         */
         return TRUE;
     }
 
-    rec_off = 8; /* block type + block total length */
+    /*
+     * Allocate a buffer for the largest block we'll write.
+     */
+    block_data = (guint8 *)g_malloc(NRES_BLOCK_MAX_SIZE);
+
+    /*
+     * Calculate the maximum amount of record data we'll be able to
+     * fit into such a block, after taking into account the block header
+     * (8 bytes), the end-of-records record (4 bytes), the options
+     * (opts_size.size bytes), and the block trailer (4 bytes).
+     */
+    max_rec_data_size = NRES_BLOCK_MAX_SIZE - (8 + 4 + opts_size.size + 4);
+
+    block_off = 8; /* block type + block total length */
     bh.block_type = BLOCK_TYPE_NRB;
-    bh.block_total_length = rec_off + 8; /* end-of-record + block total length */
-    rec_data = (guint8 *)g_malloc(NRES_REC_MAX_SIZE);
+    bh.block_total_length = 12; /* block header + block trailer */
 
+    /*
+     * Write out the IPv4 resolved addresses, if any.
+     */
     if (wdh->addrinfo_lists->ipv4_addr_list){
         i = 0;
         ipv4_hash_list_entry = (hashipv4_t *)g_list_nth_data(wdh->addrinfo_lists->ipv4_addr_list, i);
         while(ipv4_hash_list_entry != NULL){
 
             nrb.record_type = NRES_IP4RECORD;
-            namelen = (gint)strlen(ipv4_hash_list_entry->name) + 1;
-            nrb.record_len = 4 + namelen;
+            hostnamelen = strlen(ipv4_hash_list_entry->name);
+            if (hostnamelen > (G_MAXUINT16 - 4) - 1) {
+                /*
+                 * This won't fit in the largest possible NRB record;
+                 * discard it.
+                 */
+                i++;
+                ipv4_hash_list_entry = (hashipv4_t *)g_list_nth_data(wdh->addrinfo_lists->ipv4_addr_list, i);
+                continue;
+            }
+            namelen = (guint16)(hostnamelen + 1);
+            nrb.record_len = 4 + namelen;  /* 4 bytes IPv4 address length */
+            /* 2 bytes record type, 2 bytes length field */
             tot_rec_len = 4 + nrb.record_len + PADDING4(nrb.record_len);
 
-            if (rec_off + tot_rec_len > NRES_REC_MAX_SIZE){
-                /* We know the total length now; copy the block header. */
-                memcpy(rec_data, &bh, sizeof(bh));
+            if (block_off + tot_rec_len > max_rec_data_size) {
+                /*
+                 * This record would overflow our maximum size for Name
+                 * Resolution Blocks; write out all the records we created
+                 * before it, and start a new NRB.
+                 */
+
+                /* Append the end-of-records record */
+                memset(block_data + block_off, 0, 4);
+                block_off += 4;
+                bh.block_total_length += 4;
+
+                /*
+                 * Put the options into the block.
+                 *
+                 * XXX - this puts the same options in all NRBs.
+                 */
+                put_nrb_options(wdh, block_data + block_off);
+                block_off += opts_size.size;
+                bh.block_total_length += opts_size.size;
 
-                /* End of record */
-                memset(rec_data + rec_off, 0, 4);
-                rec_off += 4;
+                /* Copy the block header. */
+                memcpy(block_data, &bh, sizeof(bh));
 
-                memcpy(rec_data + rec_off, &bh.block_total_length, sizeof(bh.block_total_length));
+                /* Copy the block trailer. */
+                memcpy(block_data + block_off, &bh.block_total_length, sizeof(bh.block_total_length));
 
-                pcapng_debug2("pcapng_write_name_resolution_block: Write bh.block_total_length bytes %d, rec_off %u", bh.block_total_length, rec_off);
+                pcapng_debug("pcapng_write_name_resolution_block: Write bh.block_total_length bytes %d, block_off %u", bh.block_total_length, block_off);
 
-                if (!wtap_dump_file_write(wdh, rec_data, bh.block_total_length, err)) {
-                    g_free(rec_data);
+                if (!wtap_dump_file_write(wdh, block_data, bh.block_total_length, err)) {
+                    g_free(block_data);
                     return FALSE;
                 }
                 wdh->bytes_dumped += bh.block_total_length;
 
                 /*Start a new NRB */
-                rec_off = 8; /* block type + block total length */
+                block_off = 8; /* block type + block total length */
                 bh.block_type = BLOCK_TYPE_NRB;
-                bh.block_total_length = rec_off + 8; /* end-of-record + block total length */
-
+                bh.block_total_length = 12; /* block header + block trailer */
             }
 
             bh.block_total_length += tot_rec_len;
-            memcpy(rec_data + rec_off, &nrb, sizeof(nrb));
-            rec_off += 4;
-            memcpy(rec_data + rec_off, &(ipv4_hash_list_entry->addr), 4);
-            rec_off += 4;
-            memcpy(rec_data + rec_off, ipv4_hash_list_entry->name, namelen);
-            rec_off += namelen;
-            memset(rec_data + rec_off, 0, PADDING4(namelen));
-            rec_off += PADDING4(namelen);
-            pcapng_debug1("NRB: added IPv4 record for %s", ipv4_hash_list_entry->name);
+            memcpy(block_data + block_off, &nrb, sizeof(nrb));
+            block_off += 4;
+            memcpy(block_data + block_off, &(ipv4_hash_list_entry->addr), 4);
+            block_off += 4;
+            memcpy(block_data + block_off, ipv4_hash_list_entry->name, namelen);
+            block_off += namelen;
+            memset(block_data + block_off, 0, PADDING4(namelen));
+            block_off += PADDING4(namelen);
+            pcapng_debug("NRB: added IPv4 record for %s", ipv4_hash_list_entry->name);
 
             i++;
             ipv4_hash_list_entry = (hashipv4_t *)g_list_nth_data(wdh->addrinfo_lists->ipv4_addr_list, i);
@@ -3513,46 +3559,72 @@ pcapng_write_name_resolution_block(wtap_dumper *wdh, int *err)
         while(ipv6_hash_list_entry != NULL){
 
             nrb.record_type = NRES_IP6RECORD;
-            namelen = (gint)strlen(ipv6_hash_list_entry->name) + 1;
+            hostnamelen = strlen(ipv6_hash_list_entry->name);
+            if (hostnamelen > (G_MAXUINT16 - 16) - 1) {
+                /*
+                 * This won't fit in the largest possible NRB record;
+                 * discard it.
+                 */
+                i++;
+                ipv6_hash_list_entry = (hashipv6_t *)g_list_nth_data(wdh->addrinfo_lists->ipv6_addr_list, i);
+                continue;
+            }
+            namelen = (guint16)(hostnamelen + 1);
             nrb.record_len = 16 + namelen;  /* 16 bytes IPv6 address length */
             /* 2 bytes record type, 2 bytes length field */
             tot_rec_len = 4 + nrb.record_len + PADDING4(nrb.record_len);
 
-            if (rec_off + tot_rec_len > NRES_REC_MAX_SIZE){
-                /* We know the total length now; copy the block header. */
-                memcpy(rec_data, &bh, sizeof(bh));
+            if (block_off + tot_rec_len > max_rec_data_size) {
+                /*
+                 * This record would overflow our maximum size for Name
+                 * Resolution Blocks; write out all the records we created
+                 * before it, and start a new NRB.
+                 */
+
+                /* Append the end-of-records record */
+                memset(block_data + block_off, 0, 4);
+                block_off += 4;
+                bh.block_total_length += 4;
+
+                /*
+                 * Put the options into the block.
+                 *
+                 * XXX - this puts the same options in all NRBs.
+                 */
+                put_nrb_options(wdh, block_data + block_off);
+                block_off += opts_size.size;
+                bh.block_total_length += opts_size.size;
 
-                /* End of record */
-                memset(rec_data + rec_off, 0, 4);
-                rec_off += 4;
+                /* Copy the block header. */
+                memcpy(block_data, &bh, sizeof(bh));
 
-                memcpy(rec_data + rec_off, &bh.block_total_length, sizeof(bh.block_total_length));
+                /* Copy the block trailer. */
+                memcpy(block_data + block_off, &bh.block_total_length, sizeof(bh.block_total_length));
 
-                pcapng_debug2("pcapng_write_name_resolution_block: Write bh.block_total_length bytes %d, rec_off %u", bh.block_total_length, rec_off);
+                pcapng_debug("pcapng_write_name_resolution_block: Write bh.block_total_length bytes %d, block_off %u", bh.block_total_length, block_off);
 
-                if (!wtap_dump_file_write(wdh, rec_data, bh.block_total_length, err)) {
-                    g_free(rec_data);
+                if (!wtap_dump_file_write(wdh, block_data, bh.block_total_length, err)) {
+                    g_free(block_data);
                     return FALSE;
                 }
                 wdh->bytes_dumped += bh.block_total_length;
 
                 /*Start a new NRB */
-                rec_off = 8; /* block type + block total length */
+                block_off = 8; /* block type + block total length */
                 bh.block_type = BLOCK_TYPE_NRB;
-                bh.block_total_length = rec_off + 8; /* end-of-record + block total length */
-
+                bh.block_total_length = 12; /* block header + block trailer */
             }
 
             bh.block_total_length += tot_rec_len;
-            memcpy(rec_data + rec_off, &nrb, sizeof(nrb));
-            rec_off += 4;
-            memcpy(rec_data + rec_off, &(ipv6_hash_list_entry->addr), 16);
-            rec_off += 16;
-            memcpy(rec_data + rec_off, ipv6_hash_list_entry->name, namelen);
-            rec_off += namelen;
-            memset(rec_data + rec_off, 0, PADDING4(namelen));
-            rec_off += PADDING4(namelen);
-            pcapng_debug1("NRB: added IPv6 record for %s", ipv6_hash_list_entry->name);
+            memcpy(block_data + block_off, &nrb, sizeof(nrb));
+            block_off += 4;
+            memcpy(block_data + block_off, &(ipv6_hash_list_entry->addr), 16);
+            block_off += 16;
+            memcpy(block_data + block_off, ipv6_hash_list_entry->name, namelen);
+            block_off += namelen;
+            memset(block_data + block_off, 0, PADDING4(namelen));
+            block_off += PADDING4(namelen);
+            pcapng_debug("NRB: added IPv6 record for %s", ipv6_hash_list_entry->name);
 
             i++;
             ipv6_hash_list_entry = (hashipv6_t *)g_list_nth_data(wdh->addrinfo_lists->ipv6_addr_list, i);
@@ -3561,44 +3633,473 @@ pcapng_write_name_resolution_block(wtap_dumper *wdh, int *err)
         wdh->addrinfo_lists->ipv6_addr_list = NULL;
     }
 
-    /* We know the total length now; copy the block header. */
-    memcpy(rec_data, &bh, sizeof(bh));
+    /* Append the end-of-records record */
+    memset(block_data + block_off, 0, 4);
+    block_off += 4;
+    bh.block_total_length += 4;
+
+    /*
+     * Put the options into the block.
+     */
+    put_nrb_options(wdh, block_data + block_off);
+    block_off += opts_size.size;
+    bh.block_total_length += opts_size.size;
 
-    /* End of record */
-    memset(rec_data + rec_off, 0, 4);
-    rec_off += 4;
+    /* Copy the block header. */
+    memcpy(block_data, &bh, sizeof(bh));
 
-    memcpy(rec_data + rec_off, &bh.block_total_length, sizeof(bh.block_total_length));
+    /* Copy the block trailer. */
+    memcpy(block_data + block_off, &bh.block_total_length, sizeof(bh.block_total_length));
 
-    pcapng_debug2("pcapng_write_name_resolution_block: Write bh.block_total_length bytes %d, rec_off %u", bh.block_total_length, rec_off);
+    pcapng_debug("pcapng_write_name_resolution_block: Write bh.block_total_length bytes %d, block_off %u", bh.block_total_length, block_off);
 
-    if (!wtap_dump_file_write(wdh, rec_data, bh.block_total_length, err)) {
-        g_free(rec_data);
+    if (!wtap_dump_file_write(wdh, block_data, bh.block_total_length, err)) {
+        g_free(block_data);
         return FALSE;
     }
-
-    g_free(rec_data);
     wdh->bytes_dumped += bh.block_total_length;
+
+    g_free(block_data);
+
+    return TRUE;
+}
+
+static void compute_isb_option_size(wtap_block_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_optval_t *optval, void* user_data)
+{
+    pcapng_block_size_t* block_size = (pcapng_block_size_t*)user_data;
+    guint32 size = 0;
+
+    switch(option_id)
+    {
+    case OPT_COMMENT:
+        size = pcapng_compute_option_string_size(optval->stringval);
+        break;
+    case OPT_ISB_STARTTIME:
+    case OPT_ISB_ENDTIME:
+        size = 8;
+        break;
+    case OPT_ISB_IFRECV:
+    case OPT_ISB_IFDROP:
+    case OPT_ISB_FILTERACCEPT:
+    case OPT_ISB_OSDROP:
+    case OPT_ISB_USRDELIV:
+        size = 8;
+        break;
+    default:
+        /* Unknown options - size by datatype? */
+        break;
+    }
+
+    block_size->size += size;
+    /* Add bytes for option header if option should be written */
+    if (size > 0) {
+        /* Add optional padding to 32 bits */
+        if ((block_size->size & 0x03) != 0)
+        {
+            block_size->size += 4 - (block_size->size & 0x03);
+        }
+        block_size->size += 4;
+    }
+}
+
+static void write_wtap_isb_option(wtap_block_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_optval_t *optval, void* user_data)
+{
+    pcapng_write_block_t* write_block = (pcapng_write_block_t*)user_data;
+    struct pcapng_option_header option_hdr;
+
+    /* Don't continue if there has been an error */
+    if (!write_block->success)
+        return;
+
+    switch(option_id)
+    {
+    case OPT_COMMENT:
+        if (!pcapng_write_option_string(write_block->wdh, option_id, optval->stringval, write_block->err)) {
+            write_block->success = FALSE;
+            return;
+        }
+        break;
+    case OPT_ISB_STARTTIME:
+    case OPT_ISB_ENDTIME:
+        {
+            guint32 high, low;
+
+            option_hdr.type         = option_id;
+            option_hdr.value_length = 8;
+            if (!wtap_dump_file_write(write_block->wdh, &option_hdr, 4, write_block->err)) {
+                write_block->success = FALSE;
+                return;
+            }
+            write_block->wdh->bytes_dumped += 4;
+
+            high = (guint32)(optval->uint64val >> 32);
+            low = (guint32)(optval->uint64val >> 0);
+            if (!wtap_dump_file_write(write_block->wdh, &high, sizeof(guint32), write_block->err)) {
+                write_block->success = FALSE;
+                return;
+            }
+            write_block->wdh->bytes_dumped += 4;
+            if (!wtap_dump_file_write(write_block->wdh, &low, sizeof(guint32), write_block->err)) {
+                write_block->success = FALSE;
+                return;
+            }
+            write_block->wdh->bytes_dumped += 4;
+        }
+        break;
+    case OPT_ISB_IFRECV:
+    case OPT_ISB_IFDROP:
+    case OPT_ISB_FILTERACCEPT:
+    case OPT_ISB_OSDROP:
+    case OPT_ISB_USRDELIV:
+        {
+            option_hdr.type         = option_id;
+            option_hdr.value_length = 8;
+            if (!wtap_dump_file_write(write_block->wdh, &option_hdr, 4, write_block->err)) {
+                write_block->success = FALSE;
+                return;
+            }
+            write_block->wdh->bytes_dumped += 4;
+
+            if (!wtap_dump_file_write(write_block->wdh, &optval->uint64val, sizeof(guint64), write_block->err)) {
+                write_block->success = FALSE;
+                return;
+            }
+            write_block->wdh->bytes_dumped += 8;
+        }
+        break;
+    default:
+        /* Unknown options - write by datatype? */
+        break;
+    }
+}
+
+static gboolean
+pcapng_write_interface_statistics_block(wtap_dumper *wdh, wtap_block_t if_stats, int *err)
+{
+    pcapng_block_header_t bh;
+    pcapng_interface_statistics_block_t isb;
+    pcapng_block_size_t block_size;
+    pcapng_write_block_t block_data;
+    struct pcapng_option_header option_hdr;
+    wtapng_if_stats_mandatory_t* mand_data = (wtapng_if_stats_mandatory_t*)wtap_block_get_mandatory_data(if_stats);
+
+    pcapng_debug("pcapng_write_interface_statistics_block");
+
+    /* Compute block size */
+    block_size.size = 0;
+    wtap_block_foreach_option(if_stats, compute_isb_option_size, &block_size);
+
+    if (block_size.size > 0) {
+        /* End-of-options tag */
+        block_size.size += 4;
+    }
+
+    /* write block header */
+    bh.block_type = BLOCK_TYPE_ISB;
+    bh.block_total_length = (guint32)(sizeof(bh) + sizeof(isb) + block_size.size + 4);
+    pcapng_debug("pcapng_write_interface_statistics_block: Total len %u", bh.block_total_length);
+
+    if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err))
+        return FALSE;
+    wdh->bytes_dumped += sizeof bh;
+
+    /* write block fixed content */
+    isb.interface_id                = mand_data->interface_id;
+    isb.timestamp_high              = mand_data->ts_high;
+    isb.timestamp_low               = mand_data->ts_low;
+
+    if (!wtap_dump_file_write(wdh, &isb, sizeof isb, err))
+        return FALSE;
+    wdh->bytes_dumped += sizeof isb;
+
+    /* Write options */
+    if (block_size.size > 0) {
+        block_data.wdh = wdh;
+        block_data.err = err;
+        block_data.success = TRUE;
+        wtap_block_foreach_option(if_stats, write_wtap_isb_option, &block_data);
+
+        if (!block_data.success)
+            return FALSE;
+
+        /* Write end of options */
+        option_hdr.type = OPT_EOFOPT;
+        option_hdr.value_length = 0;
+        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
+            return FALSE;
+        wdh->bytes_dumped += 4;
+    }
+
+    /* write block footer */
+    if (!wtap_dump_file_write(wdh, &bh.block_total_length,
+                              sizeof bh.block_total_length, err))
+        return FALSE;
+    wdh->bytes_dumped += sizeof bh.block_total_length;
+    return TRUE;
+}
+
+static void compute_idb_option_size(wtap_block_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_optval_t *optval, void* user_data)
+{
+    pcapng_block_size_t* block_size = (pcapng_block_size_t*)user_data;
+    guint32 size = 0;
+
+    switch(option_id)
+    {
+    case OPT_COMMENT:
+    case OPT_IDB_NAME:
+    case OPT_IDB_DESCR:
+    case OPT_IDB_OS:
+    case OPT_IDB_HARDWARE:
+        size = pcapng_compute_option_string_size(optval->stringval);
+        break;
+    case OPT_IDB_SPEED:
+        size = 8;
+        break;
+    case OPT_IDB_TSRESOL:
+        size = 1;
+        break;
+    case OPT_IDB_FILTER:
+        {
+            wtapng_if_descr_filter_t* filter = (wtapng_if_descr_filter_t*)optval->customval.data;
+            guint32 pad;
+            if (filter->if_filter_str != NULL) {
+                size = (guint32)(strlen(filter->if_filter_str) + 1) & 0xffff;
+                if ((size % 4)) {
+                    pad = 4 - (size % 4);
+                } else {
+                    pad = 0;
+                }
+
+                size += pad;
+            }
+        }
+        break;
+    case OPT_IDB_FCSLEN:
+        /* XXX - Not currently writing value */
+        break;
+    default:
+        /* Unknown options - size by datatype? */
+        break;
+    }
+
+    block_size->size += size;
+    /* Add bytes for option header if option should be written */
+    if (size > 0) {
+        /* Add optional padding to 32 bits */
+        if ((block_size->size & 0x03) != 0)
+        {
+            block_size->size += 4 - (block_size->size & 0x03);
+        }
+        block_size->size += 4;
+    }
+}
+
+static void write_wtap_idb_option(wtap_block_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_optval_t *optval, void* user_data)
+{
+    pcapng_write_block_t* write_block = (pcapng_write_block_t*)user_data;
+    struct pcapng_option_header option_hdr;
+    const guint32 zero_pad = 0;
+
+    switch(option_id)
+    {
+    case OPT_COMMENT:
+    case OPT_IDB_NAME:
+    case OPT_IDB_DESCR:
+    case OPT_IDB_OS:
+    case OPT_IDB_HARDWARE:
+        if (!pcapng_write_option_string(write_block->wdh, option_id, optval->stringval, write_block->err)) {
+            write_block->success = FALSE;
+            return;
+        }
+        break;
+    case OPT_IDB_SPEED:
+        option_hdr.type         = option_id;
+        option_hdr.value_length = 8;
+        if (!wtap_dump_file_write(write_block->wdh, &option_hdr, 4, write_block->err)) {
+            write_block->success = FALSE;
+            return;
+        }
+        write_block->wdh->bytes_dumped += 4;
+
+        if (!wtap_dump_file_write(write_block->wdh, &optval->uint64val, sizeof(guint64), write_block->err)) {
+            write_block->success = FALSE;
+            return;
+        }
+        write_block->wdh->bytes_dumped += 8;
+        break;
+    case OPT_IDB_TSRESOL:
+        option_hdr.type         = option_id;
+        option_hdr.value_length = 1;
+        if (!wtap_dump_file_write(write_block->wdh, &option_hdr, 4, write_block->err)) {
+            write_block->success = FALSE;
+            return;
+        }
+        write_block->wdh->bytes_dumped += 4;
+
+        if (!wtap_dump_file_write(write_block->wdh, &optval->uint8val, 1, write_block->err)) {
+            write_block->success = FALSE;
+            return;
+        }
+        write_block->wdh->bytes_dumped += 1;
+
+        if (!wtap_dump_file_write(write_block->wdh, &zero_pad, 3, write_block->err)) {
+            write_block->success = FALSE;
+            return;
+        }
+        write_block->wdh->bytes_dumped += 3;
+        break;
+    case OPT_IDB_FILTER:
+        {
+            wtapng_if_descr_filter_t* filter = (wtapng_if_descr_filter_t*)optval->customval.data;
+            guint32 size, pad;
+            if (filter->if_filter_str != NULL) {
+                size = (guint32)(strlen(filter->if_filter_str) + 1) & 0xffff;
+                if ((size % 4)) {
+                    pad = 4 - (size % 4);
+                } else {
+                    pad = 0;
+                }
+
+                option_hdr.type         = option_id;
+                option_hdr.value_length = size;
+                if (!wtap_dump_file_write(write_block->wdh, &option_hdr, 4, write_block->err)) {
+                    write_block->success = FALSE;
+                    return;
+                }
+                write_block->wdh->bytes_dumped += 4;
+
+                /* Write the zero indicating libpcap filter variant */
+                if (!wtap_dump_file_write(write_block->wdh, &zero_pad, 1, write_block->err)) {
+                    write_block->success = FALSE;
+                    return;
+                }
+                write_block->wdh->bytes_dumped += 1;
+
+                /* if_filter_str_len includes the leading byte indicating filter type (libpcap str or BPF code) */
+                if (!wtap_dump_file_write(write_block->wdh, filter->if_filter_str, size-1, write_block->err)) {
+                    write_block->success = FALSE;
+                    return;
+                }
+                write_block->wdh->bytes_dumped += size - 1;
+
+                /* write padding (if any) */
+                if (pad != 0) {
+                    if (!wtap_dump_file_write(write_block->wdh, &zero_pad, pad, write_block->err)) {
+                        write_block->success = FALSE;
+                        return;
+                    }
+                    write_block->wdh->bytes_dumped += pad;
+                }
+
+            }
+        }
+        break;
+    case OPT_IDB_FCSLEN:
+        /* XXX - Not currently writing value */
+        break;
+    default:
+        /* Unknown options - size by datatype? */
+        break;
+    }
+}
+
+static gboolean
+pcapng_write_if_descr_block(wtap_dumper *wdh, wtap_block_t int_data, int *err)
+{
+    pcapng_block_header_t bh;
+    pcapng_interface_description_block_t idb;
+    pcapng_block_size_t block_size;
+    pcapng_write_block_t block_data;
+    struct pcapng_option_header option_hdr;
+    wtapng_if_descr_mandatory_t* mand_data = (wtapng_if_descr_mandatory_t*)wtap_block_get_mandatory_data(int_data);
+    int link_type;
+
+    pcapng_debug("pcapng_write_if_descr_block: encap = %d (%s), snaplen = %d",
+                  mand_data->wtap_encap,
+                  wtap_encap_string(mand_data->wtap_encap),
+                  mand_data->snap_len);
+
+    link_type = wtap_wtap_encap_to_pcap_encap(mand_data->wtap_encap);
+    if (link_type == -1) {
+        *err = WTAP_ERR_UNWRITABLE_ENCAP;
+        return FALSE;
+    }
+
+    /* Compute block size */
+    block_size.size = 0;
+    wtap_block_foreach_option(int_data, compute_idb_option_size, &block_size);
+
+    if (block_size.size > 0) {
+        /* End-of-options tag */
+        block_size.size += 4;
+    }
+
+    /* write block header */
+    bh.block_type = BLOCK_TYPE_IDB;
+    bh.block_total_length = (guint32)(sizeof(bh) + sizeof(idb) + block_size.size + 4);
+    pcapng_debug("pcapng_write_if_descr_block: Total len %u", bh.block_total_length);
+
+    if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err))
+        return FALSE;
+    wdh->bytes_dumped += sizeof bh;
+
+    /* write block fixed content */
+    idb.linktype    = link_type;
+    idb.reserved    = 0;
+    idb.snaplen     = mand_data->snap_len;
+
+    if (!wtap_dump_file_write(wdh, &idb, sizeof idb, err))
+        return FALSE;
+    wdh->bytes_dumped += sizeof idb;
+
+    if (block_size.size > 0) {
+        /* Write options */
+        block_data.wdh = wdh;
+        block_data.err = err;
+        block_data.success = TRUE;
+        wtap_block_foreach_option(int_data, write_wtap_idb_option, &block_data);
+
+        if (!block_data.success)
+            return FALSE;
+
+        /* Write end of options */
+        option_hdr.type = OPT_EOFOPT;
+        option_hdr.value_length = 0;
+        if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
+            return FALSE;
+        wdh->bytes_dumped += 4;
+    }
+
+    /* write block footer */
+    if (!wtap_dump_file_write(wdh, &bh.block_total_length,
+                              sizeof bh.block_total_length, err))
+        return FALSE;
+
+    wdh->bytes_dumped += sizeof bh.block_total_length;
     return TRUE;
 }
 
 static gboolean pcapng_dump(wtap_dumper *wdh,
-                            const struct wtap_pkthdr *phdr,
-                            const guint8 *pd, int *err)
+                            const wtap_rec *rec,
+                            const guint8 *pd, int *err, gchar **err_info _U_)
 {
-    const union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
 #ifdef HAVE_PLUGINS
     block_handler *handler;
 #endif
 
-    pcapng_debug2("pcapng_dump: encap = %d (%s)",
-                  phdr->pkt_encap,
-                  wtap_encap_string(phdr->pkt_encap));
+    pcapng_debug("pcapng_dump: encap = %d (%s)",
+                  rec->rec_header.packet_header.pkt_encap,
+                  wtap_encap_string(rec->rec_header.packet_header.pkt_encap));
 
-    switch (phdr->rec_type) {
+    switch (rec->rec_type) {
 
         case REC_TYPE_PACKET:
-            if (!pcapng_write_enhanced_packet_block(wdh, phdr, pseudo_header, pd, err)) {
+            /*
+             * XXX - write a Simple Packet Block if there's no time
+             * stamp or other information that doesn't appear in an
+             * SPB?
+             */
+            if (!pcapng_write_enhanced_packet_block(wdh, rec, pd, err)) {
                 return FALSE;
             }
             break;
@@ -3609,24 +4110,30 @@ static gboolean pcapng_dump(wtap_dumper *wdh,
             /*
              * Do we have a handler for this block type?
              */
-            handler = (block_handler *)g_hash_table_lookup(block_handlers,
-                                                           GUINT_TO_POINTER(pseudo_header->ftsrec.record_type));
-            if (handler != NULL) {
+            if (block_handlers != NULL &&
+                (handler = (block_handler *)g_hash_table_lookup(block_handlers,
+                                                                GUINT_TO_POINTER(rec->rec_header.ft_specific_header.record_type))) != NULL) {
                 /* Yes. Call it to write out this record. */
-                if (!handler->write(wdh, phdr, pd, err))
+                if (!handler->writer(wdh, rec, pd, err))
                     return FALSE;
             } else
 #endif
             {
                 /* No. */
-                *err = WTAP_ERR_REC_TYPE_UNSUPPORTED;
+                *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
+                return FALSE;
+            }
+            break;
+
+        case REC_TYPE_SYSCALL:
+            if (!pcapng_write_sysdig_event_block(wdh, rec, pd, err)) {
                 return FALSE;
             }
             break;
 
         default:
             /* We don't support writing this record type. */
-            *err = WTAP_ERR_REC_TYPE_UNSUPPORTED;
+            *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
             return FALSE;
     }
 
@@ -3636,7 +4143,7 @@ static gboolean pcapng_dump(wtap_dumper *wdh,
 
 /* Finish writing to a dump file.
    Returns TRUE on success, FALSE on failure. */
-static gboolean pcapng_dump_close(wtap_dumper *wdh, int *err _U_)
+static gboolean pcapng_dump_finish(wtap_dumper *wdh, int *err)
 {
     guint i, j;
 
@@ -3646,21 +4153,24 @@ static gboolean pcapng_dump_close(wtap_dumper *wdh, int *err _U_)
     for (i = 0; i < wdh->interface_data->len; i++) {
 
         /* Get the interface description */
-        wtapng_if_descr_t int_data;
+        wtap_block_t int_data;
+        wtapng_if_descr_mandatory_t *int_data_mand;
+
+        int_data = g_array_index(wdh->interface_data, wtap_block_t, i);
+        int_data_mand = (wtapng_if_descr_mandatory_t*)wtap_block_get_mandatory_data(int_data);
 
-        int_data = g_array_index(wdh->interface_data, wtapng_if_descr_t, i);
-        for (j = 0; j < int_data.num_stat_entries; j++) {
-            wtapng_if_stats_t if_stats;
+        for (j = 0; j < int_data_mand->num_stat_entries; j++) {
+            wtap_block_t if_stats;
 
-            if_stats = g_array_index(int_data.interface_statistics, wtapng_if_stats_t, j);
-            pcapng_debug1("pcapng_dump_close: write ISB for interface %u",if_stats.interface_id);
-            if (!pcapng_write_interface_statistics_block(wdh, &if_stats, err)) {
+            if_stats = g_array_index(int_data_mand->interface_statistics, wtap_block_t, j);
+            pcapng_debug("pcapng_dump_finish: write ISB for interface %u", ((wtapng_if_stats_mandatory_t*)wtap_block_get_mandatory_data(if_stats))->interface_id);
+            if (!pcapng_write_interface_statistics_block(wdh, if_stats, err)) {
                 return FALSE;
             }
         }
     }
 
-    pcapng_debug0("pcapng_dump_close");
+    pcapng_debug("pcapng_dump_finish");
     return TRUE;
 }
 
@@ -3672,13 +4182,13 @@ pcapng_dump_open(wtap_dumper *wdh, int *err)
 {
     guint i;
 
-    pcapng_debug0("pcapng_dump_open");
+    pcapng_debug("pcapng_dump_open");
     /* This is a pcapng file */
     wdh->subtype_write = pcapng_dump;
-    wdh->subtype_close = pcapng_dump_close;
+    wdh->subtype_finish = pcapng_dump_finish;
 
     if (wdh->interface_data->len == 0) {
-        pcapng_debug0("There are no interfaces. Can't handle that...");
+        pcapng_debug("There are no interfaces. Can't handle that...");
         *err = WTAP_ERR_INTERNAL;
         return FALSE;
     }
@@ -3687,20 +4197,20 @@ pcapng_dump_open(wtap_dumper *wdh, int *err)
     if (!pcapng_write_section_header_block(wdh, err)) {
         return FALSE;
     }
-    pcapng_debug0("pcapng_dump_open: wrote section header block.");
+    pcapng_debug("pcapng_dump_open: wrote section header block.");
 
     /* Write the Interface description blocks */
-    pcapng_debug1("pcapng_dump_open: Number of IDB:s to write (number of interfaces) %u",
+    pcapng_debug("pcapng_dump_open: Number of IDB:s to write (number of interfaces) %u",
                   wdh->interface_data->len);
 
     for (i = 0; i < wdh->interface_data->len; i++) {
 
         /* Get the interface description */
-        wtapng_if_descr_t int_data;
+        wtap_block_t idb;
 
-        int_data = g_array_index(wdh->interface_data, wtapng_if_descr_t, i);
+        idb = g_array_index(wdh->interface_data, wtap_block_t, i);
 
-        if (!pcapng_write_if_descr_block(wdh, &int_data, err)) {
+        if (!pcapng_write_if_descr_block(wdh, idb, err)) {
             return FALSE;
         }
 
@@ -3714,7 +4224,7 @@ pcapng_dump_open(wtap_dumper *wdh, int *err)
    an error indication otherwise. */
 int pcapng_dump_can_write_encap(int wtap_encap)
 {
-    pcapng_debug2("pcapng_dump_can_write_encap: encap = %d (%s)",
+    pcapng_debug("pcapng_dump_can_write_encap: encap = %d (%s)",
                   wtap_encap,
                   wtap_encap_string(wtap_encap));
 
@@ -3724,13 +4234,13 @@ int pcapng_dump_can_write_encap(int wtap_encap)
 
     /* Make sure we can figure out this DLT type */
     if (wtap_wtap_encap_to_pcap_encap(wtap_encap) == -1)
-        return WTAP_ERR_UNSUPPORTED_ENCAP;
+        return WTAP_ERR_UNWRITABLE_ENCAP;
 
     return 0;
 }
 
 /*
- * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
+ * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
  *
  * Local variables:
  * c-basic-offset: 4