]> The Tcpdump Group git mirrors - libpcap/blobdiff - sf-pcapng.c
Update config.{guess,sub}, timestamps 2023-01-01,2023-01-21
[libpcap] / sf-pcapng.c
index ae671775f25c974828752bf8f0253de9e824f1fa..058a7244d62a42f119f27bc529888060eca84bae 100644 (file)
@@ -34,6 +34,7 @@
 #include <string.h>
 
 #include "pcap-int.h"
+#include "pcap-util.h"
 
 #include "pcap-common.h"
 
@@ -85,7 +86,7 @@ struct option_header {
  * Section Header Block.
  */
 #define BT_SHB                 0x0A0D0D0A
-
+#define BT_SHB_INSANE_MAX       1024U*1024U*1U  /* 1MB should be enough */
 struct section_header_block {
        bpf_u_int32     byte_order_magic;
        u_short         major_version;
@@ -101,7 +102,8 @@ struct section_header_block {
 
 /*
  * Current version number.  If major_version isn't PCAP_NG_VERSION_MAJOR,
- * that means that this code can't read the file.
+ * or if minor_version isn't PCAP_NG_VERSION_MINOR or 2, that means that
+ * this code can't read the file.
  */
 #define PCAP_NG_VERSION_MAJOR  1
 #define PCAP_NG_VERSION_MINOR  0
@@ -197,9 +199,10 @@ typedef enum {
  * Per-interface information.
  */
 struct pcap_ng_if {
-       u_int tsresol;                  /* time stamp resolution */
+       uint32_t snaplen;               /* snapshot length */
+       uint64_t tsresol;               /* time stamp resolution */
        tstamp_scale_type_t scale_type; /* how to scale */
-       u_int scale_factor;             /* time stamp scale factor for power-of-10 tsresol */
+       uint64_t scale_factor;          /* time stamp scale factor for power-of-10 tsresol */
        uint64_t tsoffset;              /* time stamp offset */
 };
 
@@ -223,7 +226,7 @@ struct pcap_ng_if {
  * so we impose a limit regardless of the size of a pointer.
  */
 struct pcap_ng_sf {
-       u_int user_tsresol;             /* time stamp resolution requested by the user */
+       uint64_t user_tsresol;          /* time stamp resolution requested by the user */
        u_int max_blocksize;            /* don't grow buffer size past this */
        bpf_u_int32 ifcount;            /* number of interfaces seen in this capture */
        bpf_u_int32 ifaces_size;        /* size of array below */
@@ -231,16 +234,21 @@ struct pcap_ng_sf {
 };
 
 /*
- * Maximum block size for a given maximum snapshot length; we calculate
- * this based
- *
- * We define it as the size of an EPB with a max_snaplen-sized
- * packet and 128KB of options.
+ * The maximum block size we start with; we use an arbitrary value of
+ * 16 MiB.
+ */
+#define INITIAL_MAX_BLOCKSIZE  (16*1024*1024)
+
+/*
+ * Maximum block size for a given maximum snapshot length; we define it
+ * as the size of an EPB with a max_snaplen-sized packet and 128KB of
+ * options.
  */
-#define MAX_BLOCKSIZE(max_snaplen)     (sizeof (struct block_header) + \
-                                        sizeof (struct enhanced_packet_block) + \
-                                        (max_snaplen) + 131072 + \
-                                        sizeof (struct block_trailer))
+#define MAX_BLOCKSIZE_FOR_SNAPLEN(max_snaplen) \
+       (sizeof (struct block_header) + \
+        sizeof (struct enhanced_packet_block) + \
+        (max_snaplen) + 131072 + \
+        sizeof (struct block_trailer))
 
 static void pcap_ng_cleanup(pcap_t *p);
 static int pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr,
@@ -260,10 +268,9 @@ read_bytes(FILE *fp, void *buf, size_t bytes_to_read, int fail_on_eof,
                } else {
                        if (amt_read == 0 && !fail_on_eof)
                                return (0);     /* EOF */
-                       pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
-                           "truncated dump file; tried to read %lu bytes, only got %lu",
-                           (unsigned long)bytes_to_read,
-                           (unsigned long)amt_read);
+                       snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                           "truncated pcapng dump file; tried to read %zu bytes, only got %zu",
+                           bytes_to_read, amt_read);
                }
                return (-1);
        }
@@ -276,6 +283,7 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf)
        struct pcap_ng_sf *ps;
        int status;
        struct block_header bhdr;
+       struct block_trailer *btrlr;
        u_char *bdata;
        size_t data_remaining;
 
@@ -290,30 +298,29 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf)
                bhdr.total_length = SWAPLONG(bhdr.total_length);
        }
 
-       /*
-        * Is this block "too big"?
-        *
-        * We choose 16MB as "too big", for now, so that we handle
-        * "reasonably" large buffers but don't chew up all the
-        * memory if we read a malformed file.
-        */
-       if (bhdr.total_length > 16*1024*1024) {
-               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
-                   "pcapng block size %u > maximum %u",
-                   bhdr.total_length, 16*1024*1024);
-                   return (-1);
-       }
-
        /*
         * Is this block "too small" - i.e., is it shorter than a block
         * header plus a block trailer?
         */
        if (bhdr.total_length < sizeof(struct block_header) +
            sizeof(struct block_trailer)) {
-               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
-                   "block in pcapng dump file has a length of %u < %lu",
+               snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                   "block in pcapng dump file has a length of %u < %zu",
                    bhdr.total_length,
-                   (unsigned long)(sizeof(struct block_header) + sizeof(struct block_trailer)));
+                   sizeof(struct block_header) + sizeof(struct block_trailer));
+               return (-1);
+       }
+
+       /*
+        * Is the block total length a multiple of 4?
+        */
+       if ((bhdr.total_length % 4) != 0) {
+               /*
+                * No.  Report that as an error.
+                */
+               snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                   "block in pcapng dump file has a length of %u that is not a multiple of 4",
+                   bhdr.total_length);
                return (-1);
        }
 
@@ -322,18 +329,19 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf)
         */
        if (p->bufsize < bhdr.total_length) {
                /*
-                * No - make it big enough, unless it's too big.
+                * No - make it big enough, unless it's too big, in
+                * which case we fail.
                 */
                void *bigger_buffer;
 
                if (bhdr.total_length > ps->max_blocksize) {
-                       pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "block is larger than maximum block size %u",
+                       snprintf(errbuf, PCAP_ERRBUF_SIZE, "pcapng block size %u > maximum %u", bhdr.total_length,
                            ps->max_blocksize);
                        return (-1);
                }
                bigger_buffer = realloc(p->buffer, bhdr.total_length);
                if (bigger_buffer == NULL) {
-                       pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
+                       snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
                        return (-1);
                }
                p->buffer = bigger_buffer;
@@ -349,6 +357,26 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf)
        if (read_bytes(fp, bdata, data_remaining, 1, errbuf) == -1)
                return (-1);
 
+       /*
+        * Get the block size from the trailer.
+        */
+       btrlr = (struct block_trailer *)(bdata + data_remaining - sizeof (struct block_trailer));
+       if (p->swapped)
+               btrlr->total_length = SWAPLONG(btrlr->total_length);
+
+       /*
+        * Is the total length from the trailer the same as the total
+        * length from the header?
+        */
+       if (bhdr.total_length != btrlr->total_length) {
+               /*
+                * No.
+                */
+               snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                   "block total length in header and trailer don't match");
+               return (-1);
+       }
+
        /*
         * Initialize the cursor.
         */
@@ -369,7 +397,7 @@ get_from_block_data(struct block_cursor *cursor, size_t chunk_size,
         * the block data.
         */
        if (cursor->data_remaining < chunk_size) {
-               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+               snprintf(errbuf, PCAP_ERRBUF_SIZE,
                    "block of type %u in pcapng dump file is too short",
                    cursor->block_type);
                return (NULL);
@@ -431,7 +459,7 @@ get_optvalue_from_block_data(struct block_cursor *cursor,
 }
 
 static int
-process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol,
+process_idb_options(pcap_t *p, struct block_cursor *cursor, uint64_t *tsresol,
     uint64_t *tsoffset, int *is_binary, char *errbuf)
 {
        struct option_header *opthdr;
@@ -470,7 +498,7 @@ process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol,
 
                case OPT_ENDOFOPT:
                        if (opthdr->option_length != 0) {
-                               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                               snprintf(errbuf, PCAP_ERRBUF_SIZE,
                                    "Interface Description Block has opt_endofopt option with length %u != 0",
                                    opthdr->option_length);
                                return (-1);
@@ -479,13 +507,13 @@ process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol,
 
                case IF_TSRESOL:
                        if (opthdr->option_length != 1) {
-                               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                               snprintf(errbuf, PCAP_ERRBUF_SIZE,
                                    "Interface Description Block has if_tsresol option with length %u != 1",
                                    opthdr->option_length);
                                return (-1);
                        }
                        if (saw_tsresol) {
-                               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                               snprintf(errbuf, PCAP_ERRBUF_SIZE,
                                    "Interface Description Block has more than one if_tsresol option");
                                return (-1);
                        }
@@ -497,32 +525,32 @@ process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol,
                                 */
                                uint8_t tsresol_shift = (tsresol_opt & 0x7F);
 
-                               if (tsresol_shift > 31) {
+                               if (tsresol_shift > 63) {
                                        /*
                                         * Resolution is too high; 2^-{res}
-                                        * won't fit in a 32-bit value.
+                                        * won't fit in a 64-bit value.
                                         */
-                                       pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                                       snprintf(errbuf, PCAP_ERRBUF_SIZE,
                                            "Interface Description Block if_tsresol option resolution 2^-%u is too high",
-                                           tsresol_opt & 0x7F);
+                                           tsresol_shift);
                                        return (-1);
                                }
                                *is_binary = 1;
-                               *tsresol = 1 << tsresol_shift;
+                               *tsresol = ((uint64_t)1) << tsresol_shift;
                        } else {
                                /*
                                 * Resolution is negative power of 10.
                                 */
-                               if (tsresol_opt > 9) {
+                               if (tsresol_opt > 19) {
                                        /*
                                         * Resolution is too high; 2^-{res}
-                                        * won't fit in a 32-bit value (the
+                                        * won't fit in a 64-bit value (the
                                         * largest power of 10 that fits
-                                        * in a 32-bit value is 10^9, as
-                                        * the largest 32-bit unsigned
-                                        * value is ~4*10^9).
+                                        * in a 64-bit value is 10^19, as
+                                        * the largest 64-bit unsigned
+                                        * value is ~1.8*10^19).
                                         */
-                                       pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                                       snprintf(errbuf, PCAP_ERRBUF_SIZE,
                                            "Interface Description Block if_tsresol option resolution 10^-%u is too high",
                                            tsresol_opt);
                                        return (-1);
@@ -536,13 +564,13 @@ process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol,
 
                case IF_TSOFFSET:
                        if (opthdr->option_length != 8) {
-                               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                               snprintf(errbuf, PCAP_ERRBUF_SIZE,
                                    "Interface Description Block has if_tsoffset option with length %u != 8",
                                    opthdr->option_length);
                                return (-1);
                        }
                        if (saw_tsoffset) {
-                               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                               snprintf(errbuf, PCAP_ERRBUF_SIZE,
                                    "Interface Description Block has more than one if_tsoffset option");
                                return (-1);
                        }
@@ -562,10 +590,11 @@ done:
 }
 
 static int
-add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf)
+add_interface(pcap_t *p, struct interface_description_block *idbp,
+    struct block_cursor *cursor, char *errbuf)
 {
        struct pcap_ng_sf *ps;
-       u_int tsresol;
+       uint64_t tsresol;
        uint64_t tsoffset;
        int is_binary;
 
@@ -619,7 +648,7 @@ add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf)
                                 * possible 32-bit power of 2, as we do
                                 * size doubling.
                                 */
-                               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                               snprintf(errbuf, PCAP_ERRBUF_SIZE,
                                    "more than %u interfaces in the file",
                                    0x80000000U);
                                return (0);
@@ -650,7 +679,7 @@ add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf)
                                 * (unsigned) value divided by
                                 * sizeof (struct pcap_ng_if).
                                 */
-                               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                               snprintf(errbuf, PCAP_ERRBUF_SIZE,
                                    "more than %u interfaces in the file",
                                    0xFFFFFFFFU / ((u_int)sizeof (struct pcap_ng_if)));
                                return (0);
@@ -662,7 +691,7 @@ add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf)
                         * We ran out of memory.
                         * Give up.
                         */
-                       pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                       snprintf(errbuf, PCAP_ERRBUF_SIZE,
                            "out of memory for per-interface information (%u interfaces)",
                            ps->ifcount);
                        return (0);
@@ -671,6 +700,8 @@ add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf)
                ps->ifaces = new_ifaces;
        }
 
+       ps->ifaces[ps->ifcount - 1].snaplen = idbp->snaplen;
+
        /*
         * Set the default time stamp resolution and offset.
         */
@@ -736,9 +767,10 @@ add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf)
  * relevant information from the header.
  */
 pcap_t *
-pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf,
-    int *err)
+pcap_ng_check_header(const uint8_t *magic, FILE *fp, u_int precision,
+    char *errbuf, int *err)
 {
+       bpf_u_int32 magic_int;
        size_t amt_read;
        bpf_u_int32 total_length;
        bpf_u_int32 byte_order_magic;
@@ -760,7 +792,8 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf,
         * Check whether the first 4 bytes of the file are the block
         * type for a pcapng savefile.
         */
-       if (magic != BT_SHB) {
+       memcpy(&magic_int, magic, sizeof(magic_int));
+       if (magic_int != BT_SHB) {
                /*
                 * XXX - check whether this looks like what the block
                 * type would be after being munged by mapping between
@@ -829,11 +862,14 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf,
        /*
         * Check the sanity of the total length.
         */
-       if (total_length < sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer)) {
-               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
-                   "Section Header Block in pcapng dump file has a length of %u < %lu",
+       if (total_length < sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer) ||
+            (total_length > BT_SHB_INSANE_MAX)) {
+               snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                   "Section Header Block in pcapng dump file has invalid length %zu < _%u_ < %u (BT_SHB_INSANE_MAX)",
+                   sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer),
                    total_length,
-                   (unsigned long)(sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer)));
+                   BT_SHB_INSANE_MAX);
+
                *err = 1;
                return (NULL);
        }
@@ -842,7 +878,7 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf,
         * OK, this is a good pcapng file.
         * Allocate a pcap_t for it.
         */
-       p = pcap_open_offline_common(errbuf, sizeof (struct pcap_ng_sf));
+       p = PCAP_OPEN_OFFLINE_COMMON(errbuf, struct pcap_ng_sf);
        if (p == NULL) {
                /* Allocation failed. */
                *err = 1;
@@ -865,7 +901,7 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf,
                break;
 
        default:
-               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+               snprintf(errbuf, PCAP_ERRBUF_SIZE,
                    "unknown time stamp resolution %u", precision);
                free(p);
                *err = 1;
@@ -885,22 +921,22 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf,
         *      leaving room for some options.
         *
         * If we find a bigger block, we reallocate the buffer, up to
-        * the maximum size.  We start out with a maximum size based
-        * on a maximum snapshot length of MAXIMUM_SNAPLEN; if we see
-        * any link-layer header types with a larger maximum snapshot
-        * length, we boost the maximum.
+        * the maximum size.  We start out with a maximum size of
+        * INITIAL_MAX_BLOCKSIZE; if we see any link-layer header types
+        * with a maximum snapshot that results in a larger maximum
+        * block length, we boost the maximum.
         */
        p->bufsize = 2048;
        if (p->bufsize < total_length)
                p->bufsize = total_length;
        p->buffer = malloc(p->bufsize);
        if (p->buffer == NULL) {
-               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
+               snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
                free(p);
                *err = 1;
                return (NULL);
        }
-       ps->max_blocksize = MAX_BLOCKSIZE(MAXIMUM_SNAPLEN);
+       ps->max_blocksize = INITIAL_MAX_BLOCKSIZE;
 
        /*
         * Copy the stuff we've read to the buffer, and read the rest
@@ -908,12 +944,12 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf,
         */
        bhdrp = (struct block_header *)p->buffer;
        shbp = (struct section_header_block *)((u_char *)p->buffer + sizeof(struct block_header));
-       bhdrp->block_type = magic;
+       bhdrp->block_type = magic_int;
        bhdrp->total_length = total_length;
        shbp->byte_order_magic = byte_order_magic;
        if (read_bytes(fp,
-           (u_char *)p->buffer + (sizeof(magic) + sizeof(total_length) + sizeof(byte_order_magic)),
-           total_length - (sizeof(magic) + sizeof(total_length) + sizeof(byte_order_magic)),
+           (u_char *)p->buffer + (sizeof(magic_int) + sizeof(total_length) + sizeof(byte_order_magic)),
+           total_length - (sizeof(magic_int) + sizeof(total_length) + sizeof(byte_order_magic)),
            1, errbuf) == -1)
                goto fail;
 
@@ -928,10 +964,24 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf,
                 * XXX - we don't care about the section length.
                 */
        }
-       /* currently only SHB version 1.0 is supported */
+       /* Currently only SHB versions 1.0 and 1.2 are supported;
+          version 1.2 is treated as being the same as version 1.0.
+          See the current version of the pcapng specification.
+
+          Version 1.2 is written by some programs that write additional
+          block types (which can be read by any code that handles them,
+          regardless of whether the minor version if 0 or 2, so that's
+          not a reason to change the minor version number).
+
+          XXX - the pcapng specification says that readers should
+          just ignore sections with an unsupported version number;
+          presumably they can also report an error if they skip
+          all the way to the end of the file without finding
+          any versions that they support. */
        if (! (shbp->major_version == PCAP_NG_VERSION_MAJOR &&
-              shbp->minor_version == PCAP_NG_VERSION_MINOR)) {
-               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+              (shbp->minor_version == PCAP_NG_VERSION_MINOR ||
+               shbp->minor_version == 2))) {
+               snprintf(errbuf, PCAP_ERRBUF_SIZE,
                    "unsupported pcapng savefile version %u.%u",
                    shbp->major_version, shbp->minor_version);
                goto fail;
@@ -954,7 +1004,7 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf,
                status = read_block(fp, p, &cursor, errbuf);
                if (status == 0) {
                        /* EOF - no IDB in this file */
-                       pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                       snprintf(errbuf, PCAP_ERRBUF_SIZE,
                            "the capture file has no Interface Description Blocks");
                        goto fail;
                }
@@ -983,7 +1033,7 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf,
                        /*
                         * Try to add this interface.
                         */
-                       if (!add_interface(p, &cursor, errbuf))
+                       if (!add_interface(p, idbp, &cursor, errbuf))
                                goto fail;
 
                        goto done;
@@ -996,7 +1046,7 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf,
                         * not valid, as we don't know what link-layer
                         * encapsulation the packet has.
                         */
-                       pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                       snprintf(errbuf, PCAP_ERRBUF_SIZE,
                            "the capture file has a packet block before any Interface Description Blocks");
                        goto fail;
 
@@ -1009,20 +1059,8 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf,
        }
 
 done:
-       p->tzoff = 0;   /* XXX - not used in pcap */
-       p->snapshot = idbp->snaplen;
-       if (p->snapshot <= 0) {
-               /*
-                * Bogus snapshot length; use the maximum for this
-                * link-layer type as a fallback.
-                *
-                * XXX - the only reason why snapshot is signed is
-                * that pcap_snapshot() returns an int, not an
-                * unsigned int.
-                */
-               p->snapshot = max_snaplen_for_dlt(idbp->linktype);
-       }
        p->linktype = linktype_to_dlt(idbp->linktype);
+       p->snapshot = pcap_adjust_snapshot(p->linktype, idbp->snaplen);
        p->linktype_ext = 0;
 
        /*
@@ -1030,8 +1068,8 @@ done:
         * snapshot length for this DLT_ is bigger than the current
         * maximum block size, increase the maximum.
         */
-       if (MAX_BLOCKSIZE(max_snaplen_for_dlt(p->linktype)) > ps->max_blocksize)
-               ps->max_blocksize = MAX_BLOCKSIZE(max_snaplen_for_dlt(p->linktype));
+       if (MAX_BLOCKSIZE_FOR_SNAPLEN(max_snaplen_for_dlt(p->linktype)) > ps->max_blocksize)
+               ps->max_blocksize = MAX_BLOCKSIZE_FOR_SNAPLEN(max_snaplen_for_dlt(p->linktype));
 
        p->next_packet_op = pcap_ng_next_packet;
        p->cleanup_op = pcap_ng_cleanup;
@@ -1057,7 +1095,7 @@ pcap_ng_cleanup(pcap_t *p)
 
 /*
  * Read and return the next packet from the savefile.  Return the header
- * in hdr and a pointer to the contents in data.  Return 0 on success, 1
+ * in hdr and a pointer to the contents in data.  Return 1 on success, 0
  * if there were no more packets, and -1 on an error.
  */
 static int
@@ -1086,7 +1124,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
                 */
                status = read_block(fp, p, &cursor, p->errbuf);
                if (status == 0)
-                       return (1);     /* EOF */
+                       return (0);     /* EOF */
                if (status == -1)
                        return (-1);    /* error */
                switch (cursor.block_type) {
@@ -1212,14 +1250,20 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
                         * interfaces?
                         */
                        if (p->linktype != idbp->linktype) {
-                               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                                    "an interface has a type %u different from the type of the first interface",
                                    idbp->linktype);
                                return (-1);
                        }
-                       if ((bpf_u_int32)p->snapshot != idbp->snaplen) {
-                               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-                                   "an interface has a snapshot length %u different from the type of the first interface",
+
+                       /*
+                        * Check against the *adjusted* value of this IDB's
+                        * snapshot length.
+                        */
+                       if ((bpf_u_int32)p->snapshot !=
+                           pcap_adjust_snapshot(p->linktype, idbp->snaplen)) {
+                               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                                   "an interface has a snapshot length %u different from the snapshot length of the first interface",
                                    idbp->snaplen);
                                return (-1);
                        }
@@ -1227,7 +1271,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
                        /*
                         * Try to add this interface.
                         */
-                       if (!add_interface(p, &cursor, p->errbuf))
+                       if (!add_interface(p, idbp, &cursor, p->errbuf))
                                return (-1);
                        break;
 
@@ -1270,7 +1314,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
                                /*
                                 * Byte order changes.
                                 */
-                               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                                    "the file has sections with different byte orders");
                                return (-1);
 
@@ -1278,7 +1322,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
                                /*
                                 * Not a valid SHB.
                                 */
-                               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                                    "the file has a section with a bad byte order magic field");
                                return (-1);
                        }
@@ -1288,7 +1332,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
                         * we handle.
                         */
                        if (shbp->major_version != PCAP_NG_VERSION_MAJOR) {
-                               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                                    "unknown pcapng savefile major version number %u",
                                    shbp->major_version);
                                return (-1);
@@ -1322,14 +1366,14 @@ found:
                /*
                 * Yes.  Fail.
                 */
-               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                    "a packet arrived on interface %u, but there's no Interface Description Block for that interface",
                    interface_id);
                return (-1);
        }
 
        if (hdr->caplen > (bpf_u_int32)p->snapshot) {
-               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                    "invalid packet capture length %u, bigger than "
                    "snaplen of %d", hdr->caplen, p->snapshot);
                return (-1);
@@ -1468,8 +1512,7 @@ found:
        if (*data == NULL)
                return (-1);
 
-       if (p->swapped)
-               swap_pseudo_headers(p->linktype, hdr, *data);
+       pcap_post_process(p->linktype, p->swapped, hdr, *data);
 
-       return (0);
+       return (1);
 }