Move the new files to the same places as in automake.
[obnox/wireshark/wip.git] / wiretap / pcap-common.c
index 46d8328f1ff08778ac7a330c5958d61730ca5249..576e5d82d4d918f73a3e03892833dc3da7eebe71 100644 (file)
@@ -33,7 +33,9 @@
 #include <errno.h>
 #include "wtap-int.h"
 #include "file_wrappers.h"
+#include "atm.h"
 #include "erf.h"
+#include "pcap-encap.h"
 #include "pcap-common.h"
 
 /*
@@ -225,9 +227,9 @@ static const struct {
        { 127,          WTAP_ENCAP_IEEE_802_11_WLAN_RADIOTAP },  /* 802.11 plus radiotap WLAN header */
        { 128,          WTAP_ENCAP_TZSP },      /* Tazmen Sniffer Protocol */
        { 129,          WTAP_ENCAP_ARCNET_LINUX },
-        { 130,          WTAP_ENCAP_JUNIPER_MLPPP }, /* Juniper MLPPP on ML-, LS-, AS- PICs */
-        { 131,          WTAP_ENCAP_JUNIPER_MLFR }, /* Juniper MLFR (FRF.15) on ML-, LS-, AS- PICs */
-        { 133,          WTAP_ENCAP_JUNIPER_GGSN},
+       { 130,          WTAP_ENCAP_JUNIPER_MLPPP }, /* Juniper MLPPP on ML-, LS-, AS- PICs */
+       { 131,          WTAP_ENCAP_JUNIPER_MLFR }, /* Juniper MLFR (FRF.15) on ML-, LS-, AS- PICs */
+       { 133,          WTAP_ENCAP_JUNIPER_GGSN},
        /*
         * Values 132-134, 136 not listed here are reserved for use
         * in Juniper hardware.
@@ -279,8 +281,8 @@ static const struct {
         * but it is used for some Linux IP filtering (ipfilter?).
         */
 
-        /* Ethernet PPPoE frames captured on a service PIC */
-        { 167,          WTAP_ENCAP_JUNIPER_PPPOE },
+       /* Ethernet PPPoE frames captured on a service PIC */
+       { 167,          WTAP_ENCAP_JUNIPER_PPPOE },
 
         /*
         * 168 is reserved for more Juniper private-chassis-
@@ -300,16 +302,16 @@ static const struct {
 
        { 177,          WTAP_ENCAP_LINUX_LAPD },
 
-        /* Ethernet frames prepended with meta-information */
-        { 178,          WTAP_ENCAP_JUNIPER_ETHER },
-        /* PPP frames prepended with meta-information */
-        { 179,          WTAP_ENCAP_JUNIPER_PPP },
-        /* Frame-Relay frames prepended with meta-information */
-        { 180,          WTAP_ENCAP_JUNIPER_FRELAY },
-        /* C-HDLC frames prepended with meta-information */
-        { 181,          WTAP_ENCAP_JUNIPER_CHDLC },
-        /* VOIP Frames prepended with meta-information */
-        { 183,          WTAP_ENCAP_JUNIPER_VP },
+    /* Ethernet frames prepended with meta-information */
+       { 178,          WTAP_ENCAP_JUNIPER_ETHER },
+       /* PPP frames prepended with meta-information */
+       { 179,          WTAP_ENCAP_JUNIPER_PPP },
+       /* Frame-Relay frames prepended with meta-information */
+       { 180,          WTAP_ENCAP_JUNIPER_FRELAY },
+       /* C-HDLC frames prepended with meta-information */
+       { 181,          WTAP_ENCAP_JUNIPER_CHDLC },
+       /* VOIP Frames prepended with meta-information */
+       { 183,          WTAP_ENCAP_JUNIPER_VP },
        /* raw USB packets */
        { 186,          WTAP_ENCAP_USB },
        /* Bluetooth HCI UART transport (part H:4) frames, like hcidump */
@@ -320,18 +322,21 @@ static const struct {
        { 189,          WTAP_ENCAP_USB_LINUX },
        /* CAN 2.0b frame */
        { 190,          WTAP_ENCAP_CAN20B },
-        /* Per-Packet Information header */
-        { 192,          WTAP_ENCAP_PPI },
+       /* Per-Packet Information header */
+       { 192,          WTAP_ENCAP_PPI },
        /* IEEE 802.15.4 Wireless PAN */
        { 195,          WTAP_ENCAP_IEEE802_15_4 },
        /* SITA File Encapsulation */
-       { 196,          WTAP_ENCAP_SITA },
+       { 196,          WTAP_ENCAP_SITA },
        /* Endace Record File Encapsulation */
-       { 197,          WTAP_ENCAP_ERF },
+       { 197,          WTAP_ENCAP_ERF },
        /* IPMB */
        { 199,          WTAP_ENCAP_IPMB },
        /* Bluetooth HCI UART transport (part H:4) frames, like hcidump */
        { 201,          WTAP_ENCAP_BLUETOOTH_H4_WITH_PHDR },
+       /* LAPD frame */
+       { 203,          WTAP_ENCAP_LAPD },
+       /* PPP with pseudoheader */
        { 204,          WTAP_ENCAP_PPP_WITH_PHDR },
        /* IPMB/I2C */
        { 209,          WTAP_ENCAP_I2C },
@@ -350,14 +355,31 @@ static const struct {
        /* USB packets with padded Linux-specified header */
        { 220,          WTAP_ENCAP_USB_LINUX_MMAPPED },
        /* Fibre Channel FC-2 frame */
-       { 224,          WTAP_ENCAP_FIBRE_CHANNEL_FC2 },
+       { 224,          WTAP_ENCAP_FIBRE_CHANNEL_FC2 },
        /* Fibre Channel FC-2 frame with Delimiter */
-       { 225,          WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS },
-       /* Solaris DLPI */
-       { 226,          WTAP_ENCAP_IPNET },
-
+       { 225,          WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS },
+       /* Solaris IPNET */
+       { 226,          WTAP_ENCAP_IPNET },
        /* SocketCAN frame */
-       { 227,          WTAP_ENCAP_SOCKETCAN },
+       { 227,          WTAP_ENCAP_SOCKETCAN },
+       /* Raw IPv4 */
+       { 228,          WTAP_ENCAP_RAW_IP4 },
+       /* Raw IPv6 */
+       { 229,          WTAP_ENCAP_RAW_IP6 },
+       /* IEEE 802.15.4 Wireless PAN no fcs */
+       { 230,          WTAP_ENCAP_IEEE802_15_4_NOFCS },
+       /* DVB-CI (Common Interface) */
+       { 235,          WTAP_ENCAP_DVBCI },
+       /* MUX27010 */
+       { 236,          WTAP_ENCAP_MUX27010 },
+       /* netANALYZER pseudo-header followed by Ethernet with CRC */
+       { 240,          WTAP_ENCAP_NETANALYZER },
+       /* netANALYZER pseudo-header in transparent mode */
+       { 241,          WTAP_ENCAP_NETANALYZER_TRANSPARENT },
+       /* IP-over-Infiniband, as specified by RFC 4391 section 6 */
+       { 242,          WTAP_ENCAP_IP_OVER_IB },
+       /* ISO/IEC 13818-1 MPEG2-TS packets */
+       { 243,          WTAP_ENCAP_MPEG_2_TS },
 
        /*
         * To repeat:
@@ -699,7 +721,7 @@ struct i2c_file_hdr {
 
 static gboolean
 pcap_read_sunatm_pseudoheader(FILE_T fh,
-    union wtap_pseudo_header *pseudo_header, int *err)
+    union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info)
 {
        guint8  atm_phdr[SUNATM_LEN];
        int     bytes_read;
@@ -707,9 +729,9 @@ pcap_read_sunatm_pseudoheader(FILE_T fh,
        guint16 vci;
 
        errno = WTAP_ERR_CANT_READ;
-       bytes_read = file_read(atm_phdr, 1, SUNATM_LEN, fh);
+       bytes_read = file_read(atm_phdr, SUNATM_LEN, fh);
        if (bytes_read != SUNATM_LEN) {
-               *err = file_error(fh);
+               *err = file_error(fh, err_info);
                if (*err == 0)
                        *err = WTAP_ERR_SHORT_READ;
                return FALSE;
@@ -787,7 +809,7 @@ pcap_read_sunatm_pseudoheader(FILE_T fh,
 
 static gboolean
 pcap_read_nokiaatm_pseudoheader(FILE_T fh,
-    union wtap_pseudo_header *pseudo_header, int *err)
+    union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info)
 {
        guint8  atm_phdr[NOKIAATM_LEN];
        int     bytes_read;
@@ -795,9 +817,9 @@ pcap_read_nokiaatm_pseudoheader(FILE_T fh,
        guint16 vci;
 
        errno = WTAP_ERR_CANT_READ;
-       bytes_read = file_read(atm_phdr, 1, NOKIAATM_LEN, fh);
+       bytes_read = file_read(atm_phdr, NOKIAATM_LEN, fh);
        if (bytes_read != NOKIAATM_LEN) {
-               *err = file_error(fh);
+               *err = file_error(fh, err_info);
                if (*err == 0)
                        *err = WTAP_ERR_SHORT_READ;
                return FALSE;
@@ -828,16 +850,16 @@ pcap_read_irda_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
        int     bytes_read;
 
        errno = WTAP_ERR_CANT_READ;
-       bytes_read = file_read(irda_phdr, 1, IRDA_SLL_LEN, fh);
+       bytes_read = file_read(irda_phdr, IRDA_SLL_LEN, fh);
        if (bytes_read != IRDA_SLL_LEN) {
-               *err = file_error(fh);
+               *err = file_error(fh, err_info);
                if (*err == 0)
                        *err = WTAP_ERR_SHORT_READ;
                return FALSE;
        }
 
        if (pntohs(&irda_phdr[IRDA_SLL_PROTOCOL_OFFSET]) != 0x0017) {
-               *err = WTAP_ERR_BAD_RECORD;
+               *err = WTAP_ERR_BAD_FILE;
                if (err_info != NULL)
                        *err_info = g_strdup("libpcap: IrDA capture has a packet with an invalid sll_protocol field");
                return FALSE;
@@ -849,15 +871,15 @@ pcap_read_irda_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
 }
 
 static gboolean
-pcap_read_mtp2_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info _U_)
+pcap_read_mtp2_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info)
 {
        guint8 mtp2_hdr[MTP2_HDR_LEN];
        int    bytes_read;
 
        errno = WTAP_ERR_CANT_READ;
-       bytes_read = file_read(mtp2_hdr, 1, MTP2_HDR_LEN, fh);
+       bytes_read = file_read(mtp2_hdr, MTP2_HDR_LEN, fh);
        if (bytes_read != MTP2_HDR_LEN) {
-               *err = file_error(fh);
+               *err = file_error(fh, err_info);
                if (*err == 0)
                        *err = WTAP_ERR_SHORT_READ;
                return FALSE;
@@ -878,16 +900,16 @@ pcap_read_lapd_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
        int     bytes_read;
 
        errno = WTAP_ERR_CANT_READ;
-       bytes_read = file_read(lapd_phdr, 1, LAPD_SLL_LEN, fh);
+       bytes_read = file_read(lapd_phdr, LAPD_SLL_LEN, fh);
        if (bytes_read != LAPD_SLL_LEN) {
-               *err = file_error(fh);
+               *err = file_error(fh, err_info);
                if (*err == 0)
                        *err = WTAP_ERR_SHORT_READ;
                return FALSE;
        }
 
        if (pntohs(&lapd_phdr[LAPD_SLL_PROTOCOL_OFFSET]) != ETH_P_LAPD) {
-               *err = WTAP_ERR_BAD_RECORD;
+               *err = WTAP_ERR_BAD_FILE;
                if (err_info != NULL)
                        *err_info = g_strdup("libpcap: LAPD capture has a packet with an invalid sll_protocol field");
                return FALSE;
@@ -900,70 +922,287 @@ pcap_read_lapd_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
 }
 
 static gboolean
-pcap_read_sita_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info _U_)
+pcap_read_sita_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info)
 {
        guint8  sita_phdr[SITA_HDR_LEN];
        int     bytes_read;
 
        errno = WTAP_ERR_CANT_READ;
-       bytes_read = file_read(sita_phdr, 1, SITA_HDR_LEN, fh);
+       bytes_read = file_read(sita_phdr, SITA_HDR_LEN, fh);
        if (bytes_read != SITA_HDR_LEN) {
-               *err = file_error(fh);
+               *err = file_error(fh, err_info);
                if (*err == 0)
                        *err = WTAP_ERR_SHORT_READ;
                return FALSE;
        }
 
-       pseudo_header->sita.flags   = sita_phdr[SITA_FLAGS_OFFSET];
-       pseudo_header->sita.signals = sita_phdr[SITA_SIGNALS_OFFSET];
-       pseudo_header->sita.errors1 = sita_phdr[SITA_ERRORS1_OFFSET];
-       pseudo_header->sita.errors2 = sita_phdr[SITA_ERRORS2_OFFSET];
-       pseudo_header->sita.proto   = sita_phdr[SITA_PROTO_OFFSET];
+       pseudo_header->sita.sita_flags   = sita_phdr[SITA_FLAGS_OFFSET];
+       pseudo_header->sita.sita_signals = sita_phdr[SITA_SIGNALS_OFFSET];
+       pseudo_header->sita.sita_errors1 = sita_phdr[SITA_ERRORS1_OFFSET];
+       pseudo_header->sita.sita_errors2 = sita_phdr[SITA_ERRORS2_OFFSET];
+       pseudo_header->sita.sita_proto   = sita_phdr[SITA_PROTO_OFFSET];
 
        return TRUE;
 }
 
-static gboolean
-pcap_read_linux_usb_pseudoheader(FILE_T fh,
-    union wtap_pseudo_header *pseudo_header, gboolean byte_swapped, int *err)
-{
-       int     bytes_read;
+/*
+ * When not using the memory-mapped interface to capture USB events,
+ * code that reads those events can use the MON_IOCX_GET ioctl to
+ * read a 48-byte header consisting of a "struct linux_usb_phdr", as
+ * defined below, followed immediately by one of:
+ *
+ *     8 bytes of a "struct usb_device_setup_hdr", if "setup_flag"
+ *     in the preceding "struct linux_usb_phdr" is 0;
+ *
+ *     in Linux 2.6.30 or later, 8 bytes of a "struct iso_rec", if
+ *     this is an isochronous transfer;
+ *
+ *     8 bytes of junk, otherwise.
+ *
+ * In Linux 2.6.31 and later, it can also use the MON_IOCX_GETX ioctl
+ * to read a 64-byte header; that header consists of the 48 bytes
+ * above, followed immediately by 16 bytes of a "struct linux_usb_phdr_ext",
+ * as defined below.
+ *
+ * In Linux 2.6.21 and later, there's a memory-mapped interface to
+ * capture USB events.  In that interface, the events in the memory-mapped
+ * buffer have a 64-byte header, followed immediately by the data.
+ * In Linux 2.6.21 through 2.6.30.x, the 64-byte header is the 48-byte
+ * header described above, followed by 16 bytes of zeroes; in Linux
+ * 2.6.31 and later, the 64-byte header is the 64-byte header described
+ * above.
+ *
+ * See linux/Documentation/usb/usbmon.txt and libpcap/pcap/usb.h for details.
+ *
+ * With WTAP_ENCAP_USB_LINUX, packets have the 48-byte header; with
+ * WTAP_ENCAP_USB_LINUX_MMAPPED, they have the 64-byte header.  There
+ * is no indication of whether the header has the "struct iso_rec", or
+ * whether the last 16 bytes of a 64-byte header are all zeros or are
+ * a "struct linux_usb_phdr_ext".
+ */
 
-       errno = WTAP_ERR_CANT_READ;
-       bytes_read = file_read(&pseudo_header->linux_usb, 1,
-           sizeof (struct linux_usb_phdr), fh);
-       if (bytes_read != sizeof (struct linux_usb_phdr)) {
-               *err = file_error(fh);
-               if (*err == 0)
-                       *err = WTAP_ERR_SHORT_READ;
-               return FALSE;
-       }
+/*
+ * URB transfer_type values
+ */
+#define URB_ISOCHRONOUS   0x0
+#define URB_INTERRUPT     0x1
+#define URB_CONTROL       0x2
+#define URB_BULK          0x3
+
+/*
+ * Information from the URB for Isochronous transfers.
+ *
+ * This structure is 8 bytes long.
+ */
+struct iso_rec {
+    gint32 error_count;
+    gint32 numdesc;
+};
+
+/*
+ * Header prepended by Linux kernel to each USB event.
+ *
+ * (Setup flag is '-', 'D', 'Z', or 0.  Data flag is '<', '>', 'Z', or 0.)
+ *
+ * The values are in *host* byte order.
+ */
+struct linux_usb_phdr {
+    guint64 id;             /* urb id, to link submission and completion events */
+    guint8 event_type;      /* Submit ('S'), Completed ('C'), Error ('E') */
+    guint8 transfer_type;   /* ISO (0), Intr, Control, Bulk (3) */
+    guint8 endpoint_number; /* Endpoint number (0-15) and transfer direction */
+    guint8 device_address;  /* 0-127 */
+    guint16 bus_id;
+    gint8 setup_flag;       /* 0, if the urb setup header is meaningful */
+    gint8 data_flag;        /* 0, if urb data is present */
+    gint64 ts_sec;
+    gint32 ts_usec;
+    gint32 status;
+    guint32 urb_len;        /* whole len of urb this event refers to */
+    guint32 data_len;       /* amount of urb data really present in this event */
+
+    /*
+     * Packet-type-dependent data.
+     * USB setup information of setup_flag is true.
+     * Otherwise, some isochronous transfer information.
+     */
+    union {
+        guint8 data[8];
+        struct iso_rec iso;
+    } s;
+
+    /*
+     * This data is provided by Linux 2.6.31 and later kernels.
+     *
+     * For WTAP_ENCAP_USB_LINUX, it's not in the pseudo-header, so
+     * the pseudo-header is always 48 bytes long, including the
+     * packet-type-dependent data.
+     *
+     * For WTAP_ENCAP_USB_LINUX_MMAPPED, the pseudo-header is always
+     * 64 bytes long, with the packet-type-dependent data preceding
+     * these last 16 bytes.  In pre-2.6.31 kernels, it's zero padding;
+     * in 2.6.31 and later, it's the following data.
+     */
+    gint32 interval;    /* only for Interrupt and Isochronous events */
+    gint32 start_frame; /* for Isochronous */
+    guint32 xfer_flags; /* copy of URB's transfer_flags */
+    guint32 ndesc;      /* actual number of isochronous descriptors */
+};
+
+struct linux_usb_isodesc {
+    gint32 iso_status;
+    guint32 iso_off;
+    guint32 iso_len;
+    guint32 _pad;
+};
+
+/*
+ * USB setup header as defined in USB specification
+ * See usb_20.pdf, Chapter 9.3 'USB Device Requests' for details.
+ * http://www.usb.org/developers/docs/usb_20_122909-2.zip
+ *
+ * This structure is 8 bytes long.
+ */
+struct usb_device_setup_hdr {
+    gint8 bmRequestType;
+    guint8 bRequest;
+    guint16 wValue;
+    guint16 wIndex;
+    guint16 wLength;
+};
+
+
+/*
+ * Offset of the *end* of a field within a particular structure.
+ */
+#define END_OFFSETOF(basep, fieldp) \
+       (((char *)(void *)(fieldp)) - ((char *)(void *)(basep)) + \
+           sizeof(*fieldp))
+
+static void
+pcap_process_linux_usb_pseudoheader(guint packet_size, gboolean byte_swapped,
+    gboolean header_len_64_bytes, guint8 *pd)
+{
+       struct linux_usb_phdr *phdr;
+       struct linux_usb_isodesc *pisodesc;
+       gint32 iso_numdesc, i;
 
        if (byte_swapped) {
-               pseudo_header->linux_usb.id = GUINT64_SWAP_LE_BE(pseudo_header->linux_usb.id);
-               pseudo_header->linux_usb.bus_id = GUINT16_SWAP_LE_BE(pseudo_header->linux_usb.bus_id);
-               pseudo_header->linux_usb.ts_sec = GUINT64_SWAP_LE_BE(pseudo_header->linux_usb.ts_sec);
-               pseudo_header->linux_usb.ts_usec = GUINT32_SWAP_LE_BE(pseudo_header->linux_usb.ts_usec);
-               pseudo_header->linux_usb.status = GUINT32_SWAP_LE_BE(pseudo_header->linux_usb.status);
-               pseudo_header->linux_usb.urb_len = GUINT32_SWAP_LE_BE(pseudo_header->linux_usb.urb_len);
-               pseudo_header->linux_usb.data_len = GUINT32_SWAP_LE_BE(pseudo_header->linux_usb.data_len);
-       }
+               /*
+                * Greasy hack, but we never directly direference any of
+                * the fields in *phdr, we just get offsets of and
+                * addresses of its members, so it's safe.
+                */
+               phdr = (struct linux_usb_phdr *)(void *)pd;
+
+               if (packet_size < END_OFFSETOF(phdr, &phdr->id))
+                       return;
+               PBSWAP64((guint8 *)&phdr->id);
+               if (packet_size < END_OFFSETOF(phdr, &phdr->bus_id))
+                       return;
+               PBSWAP16((guint8 *)&phdr->bus_id);
+               if (packet_size < END_OFFSETOF(phdr, &phdr->ts_sec))
+                       return;
+               PBSWAP64((guint8 *)&phdr->ts_sec);
+               if (packet_size < END_OFFSETOF(phdr, &phdr->ts_usec))
+                       return;
+               PBSWAP32((guint8 *)&phdr->ts_usec);
+               if (packet_size < END_OFFSETOF(phdr, &phdr->status))
+                       return;
+               PBSWAP32((guint8 *)&phdr->status);
+               if (packet_size < END_OFFSETOF(phdr, &phdr->urb_len))
+                       return;
+               PBSWAP32((guint8 *)&phdr->urb_len);
+               if (packet_size < END_OFFSETOF(phdr, &phdr->data_len))
+                       return;
+               PBSWAP32((guint8 *)&phdr->data_len);
+
+               if (phdr->transfer_type == URB_ISOCHRONOUS) {
+                       if (packet_size < END_OFFSETOF(phdr, &phdr->s.iso.error_count))
+                               return;
+                       PBSWAP32((guint8 *)&phdr->s.iso.error_count);
+
+                       if (packet_size < END_OFFSETOF(phdr, &phdr->s.iso.numdesc))
+                               return;
+                       PBSWAP32((guint8 *)&phdr->s.iso.numdesc);
 
-       return TRUE;
+               }
+
+               if (header_len_64_bytes) {
+                       /*
+                        * This is either the "version 1" header, with
+                        * 16 bytes of additional fields at the end, or
+                        * a "version 0" header from a memory-mapped
+                        * capture, with 16 bytes of zeroed-out padding
+                        * at the end.  Byte swap them as if this were
+                        * a "version 1" header.
+                        *
+                        * Yes, the first argument to END_OFFSETOF() should
+                        * be phdr, not phdr_ext; we want the offset of
+                        * the additional fields from the beginning of
+                        * the packet.
+                        */
+                       if (packet_size < END_OFFSETOF(phdr, &phdr->interval))
+                               return;
+                       PBSWAP32((guint8 *)&phdr->interval);
+                       if (packet_size < END_OFFSETOF(phdr, &phdr->start_frame))
+                               return;
+                       PBSWAP32((guint8 *)&phdr->start_frame);
+                       if (packet_size < END_OFFSETOF(phdr, &phdr->xfer_flags))
+                               return;
+                       PBSWAP32((guint8 *)&phdr->xfer_flags);
+                       if (packet_size < END_OFFSETOF(phdr, &phdr->ndesc))
+                               return;
+                       PBSWAP32((guint8 *)&phdr->ndesc);
+               }
+
+               if (phdr->transfer_type == URB_ISOCHRONOUS) {
+                       /* swap the values in struct linux_usb_isodesc */
+
+                       /*
+                        * See previous "Greasy hack" comment.
+                        */
+                       if (header_len_64_bytes) {
+                               pisodesc = (struct linux_usb_isodesc*)(void *)(pd + 64);
+                       } else {
+                               pisodesc = (struct linux_usb_isodesc*)(void *)(pd + 48);
+                       }
+                       iso_numdesc = phdr->s.iso.numdesc;
+                       for (i = 0; i < iso_numdesc; i++) {
+                               /* always check if we have enough data from the
+                                * beginnig of the packet (phdr)
+                                */
+                               if (packet_size < END_OFFSETOF(phdr, &pisodesc->iso_status))
+                                       return;
+                               PBSWAP32((guint8 *)&pisodesc->iso_status);
+                               if (packet_size < END_OFFSETOF(phdr, &pisodesc->iso_off))
+                                       return;
+                               PBSWAP32((guint8 *)&pisodesc->iso_off);
+                               if (packet_size < END_OFFSETOF(phdr, &pisodesc->iso_len))
+                                       return;
+                               PBSWAP32((guint8 *)&pisodesc->iso_len);
+                               if (packet_size < END_OFFSETOF(phdr, &pisodesc->_pad))
+                                       return;
+                               PBSWAP32((guint8 *)&pisodesc->_pad);
+
+                               pisodesc++;
+                       }
+               }
+       }
 }
 
 static gboolean
 pcap_read_bt_pseudoheader(FILE_T fh,
-    union wtap_pseudo_header *pseudo_header, int *err)
+    union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info)
 {
        int     bytes_read;
        struct libpcap_bt_phdr phdr;
 
        errno = WTAP_ERR_CANT_READ;
-       bytes_read = file_read(&phdr, 1,
+       bytes_read = file_read(&phdr,
            sizeof (struct libpcap_bt_phdr), fh);
        if (bytes_read != sizeof (struct libpcap_bt_phdr)) {
-               *err = file_error(fh);
+               *err = file_error(fh, err_info);
                if (*err == 0)
                        *err = WTAP_ERR_SHORT_READ;
                return FALSE;
@@ -974,16 +1213,16 @@ pcap_read_bt_pseudoheader(FILE_T fh,
 
 static gboolean
 pcap_read_ppp_pseudoheader(FILE_T fh,
-    union wtap_pseudo_header *pseudo_header, int *err)
+    union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info)
 {
        int     bytes_read;
        struct libpcap_ppp_phdr phdr;
 
        errno = WTAP_ERR_CANT_READ;
-       bytes_read = file_read(&phdr, 1,
+       bytes_read = file_read(&phdr,
            sizeof (struct libpcap_ppp_phdr), fh);
        if (bytes_read != sizeof (struct libpcap_ppp_phdr)) {
-               *err = file_error(fh);
+               *err = file_error(fh, err_info);
                if (*err == 0)
                        *err = WTAP_ERR_SHORT_READ;
                return FALSE;
@@ -994,15 +1233,15 @@ pcap_read_ppp_pseudoheader(FILE_T fh,
 
 static gboolean
 pcap_read_erf_pseudoheader(FILE_T fh, struct wtap_pkthdr *whdr,
-                             union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info _U_)
+                             union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info)
 {
   guint8 erf_hdr[sizeof(struct erf_phdr)];
   int    bytes_read;
 
   errno = WTAP_ERR_CANT_READ;
-  bytes_read = file_read(erf_hdr, 1, sizeof(struct erf_phdr), fh);
+  bytes_read = file_read(erf_hdr, sizeof(struct erf_phdr), fh);
   if (bytes_read != sizeof(struct erf_phdr)) {
-    *err = file_error(fh);
+    *err = file_error(fh, err_info);
     if (*err == 0)
       *err = WTAP_ERR_SHORT_READ;
     return FALSE;
@@ -1037,26 +1276,26 @@ pcap_read_erf_pseudoheader(FILE_T fh, struct wtap_pkthdr *whdr,
  */
 static gboolean
 pcap_read_erf_exheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
-                          int *err, gchar **err_info _U_, guint * psize)
+                          int *err, gchar **err_info, guint * psize)
 {
   int bytes_read = 0;
   guint8 erf_exhdr[8];
   guint64 erf_exhdr_sw;
   int i = 0, max = sizeof(pseudo_header->erf.ehdr_list)/sizeof(struct erf_ehdr);
-  guint8 type = pseudo_header->erf.phdr.type;
+  guint8 type;
   *psize = 0;
   if (pseudo_header->erf.phdr.type & 0x80){
     do{
       errno = WTAP_ERR_CANT_READ;
-      bytes_read = file_read(erf_exhdr, 1, 8, fh);
+      bytes_read = file_read(erf_exhdr, 8, fh);
       if (bytes_read != 8 ) {
-       *err = file_error(fh);
+       *err = file_error(fh, err_info);
        if (*err == 0)
          *err = WTAP_ERR_SHORT_READ;
        return FALSE;
       }
       type = erf_exhdr[0];
-      erf_exhdr_sw = pntohll((guint64*) &(erf_exhdr[0]));
+      erf_exhdr_sw = pntohll(erf_exhdr);
       if (i < max)
        memcpy(&pseudo_header->erf.ehdr_list[i].ehdr, &erf_exhdr_sw, sizeof(erf_exhdr_sw));
       *psize += 8;
@@ -1072,7 +1311,7 @@ pcap_read_erf_exheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
  */
 static gboolean
 pcap_read_erf_subheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
-                          int *err, gchar **err_info _U_, guint * psize)
+                          int *err, gchar **err_info, guint * psize)
 {
   guint8 erf_subhdr[sizeof(union erf_subhdr)];
   int    bytes_read;
@@ -1088,9 +1327,9 @@ pcap_read_erf_subheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
   case ERF_TYPE_COLOR_MC_HDLC_POS:
     /* Extract the Multi Channel header to include it in the pseudo header part */
     errno = WTAP_ERR_CANT_READ;
-    bytes_read = file_read(erf_subhdr, 1, sizeof(erf_mc_header_t), fh);
+    bytes_read = file_read(erf_subhdr, sizeof(erf_mc_header_t), fh);
     if (bytes_read != sizeof(erf_mc_header_t) ) {
-      *err = file_error(fh);
+      *err = file_error(fh, err_info);
       if (*err == 0)
        *err = WTAP_ERR_SHORT_READ;
       return FALSE;
@@ -1103,9 +1342,9 @@ pcap_read_erf_subheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
   case ERF_TYPE_DSM_COLOR_ETH:
     /* Extract the Ethernet additional header to include it in the pseudo header part */
     errno = WTAP_ERR_CANT_READ;
-    bytes_read = file_read(erf_subhdr, 1, sizeof(erf_eth_header_t), fh);
+    bytes_read = file_read(erf_subhdr, sizeof(erf_eth_header_t), fh);
     if (bytes_read != sizeof(erf_eth_header_t) ) {
-      *err = file_error(fh);
+      *err = file_error(fh, err_info);
       if (*err == 0)
        *err = WTAP_ERR_SHORT_READ;
       return FALSE;
@@ -1121,15 +1360,15 @@ pcap_read_erf_subheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
 }
 
 static gboolean
-pcap_read_i2c_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info _U_)
+pcap_read_i2c_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info)
 {
        struct i2c_file_hdr i2c_hdr;
        int    bytes_read;
 
        errno = WTAP_ERR_CANT_READ;
-       bytes_read = file_read(&i2c_hdr, 1, sizeof (i2c_hdr), fh);
+       bytes_read = file_read(&i2c_hdr, sizeof (i2c_hdr), fh);
        if (bytes_read != sizeof (i2c_hdr)) {
-               *err = file_error(fh);
+               *err = file_error(fh, err_info);
                if (*err == 0)
                        *err = WTAP_ERR_SHORT_READ;
                return FALSE;
@@ -1143,8 +1382,8 @@ pcap_read_i2c_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header, i
 }
 
 int
-pcap_process_pseudo_header(FILE_T fh, int file_type, int wtap_encap, gboolean bytes_swapped, guint packet_size,
-    gboolean check_packet_size, struct wtap_pkthdr *phdr,
+pcap_process_pseudo_header(FILE_T fh, int file_type, int wtap_encap,
+    guint packet_size, gboolean check_packet_size, struct wtap_pkthdr *phdr,
     union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info)
 {
        int phdr_len = 0;
@@ -1162,13 +1401,13 @@ pcap_process_pseudo_header(FILE_T fh, int file_type, int wtap_encap, gboolean by
                                 * Uh-oh, the packet isn't big enough to even
                                 * have a pseudo-header.
                                 */
-                               *err = WTAP_ERR_BAD_RECORD;
+                               *err = WTAP_ERR_BAD_FILE;
                                *err_info = g_strdup_printf("pcap: Nokia IPSO ATM file has a %u-byte packet, too small to have even an ATM pseudo-header",
                                    packet_size);
                                return -1;
                        }
                        if (!pcap_read_nokiaatm_pseudoheader(fh,
-                           pseudo_header, err))
+                           pseudo_header, err, err_info))
                                return -1;      /* Read error */
 
                        phdr_len = NOKIAATM_LEN;
@@ -1181,13 +1420,13 @@ pcap_process_pseudo_header(FILE_T fh, int file_type, int wtap_encap, gboolean by
                                 * Uh-oh, the packet isn't big enough to even
                                 * have a pseudo-header.
                                 */
-                               *err = WTAP_ERR_BAD_RECORD;
+                               *err = WTAP_ERR_BAD_FILE;
                                *err_info = g_strdup_printf("pcap: SunATM file has a %u-byte packet, too small to have even an ATM pseudo-header",
                                    packet_size);
                                return -1;
                        }
                        if (!pcap_read_sunatm_pseudoheader(fh,
-                           pseudo_header, err))
+                           pseudo_header, err, err_info))
                                return -1;      /* Read error */
 
                        phdr_len = SUNATM_LEN;
@@ -1222,7 +1461,7 @@ pcap_process_pseudo_header(FILE_T fh, int file_type, int wtap_encap, gboolean by
                         * Uh-oh, the packet isn't big enough to even
                         * have a pseudo-header.
                         */
-                       *err = WTAP_ERR_BAD_RECORD;
+                       *err = WTAP_ERR_BAD_FILE;
                        *err_info = g_strdup_printf("pcap: IrDA file has a %u-byte packet, too small to have even an IrDA pseudo-header",
                            packet_size);
                        return -1;
@@ -1240,7 +1479,7 @@ pcap_process_pseudo_header(FILE_T fh, int file_type, int wtap_encap, gboolean by
                         * Uh-oh, the packet isn't big enough to even
                         * have a pseudo-header.
                         */
-                       *err = WTAP_ERR_BAD_RECORD;
+                       *err = WTAP_ERR_BAD_FILE;
                        *err_info = g_strdup_printf("pcap: MTP2 file has a %u-byte packet, too small to have even an MTP2 pseudo-header",
                            packet_size);
                        return -1;
@@ -1258,7 +1497,7 @@ pcap_process_pseudo_header(FILE_T fh, int file_type, int wtap_encap, gboolean by
                         * Uh-oh, the packet isn't big enough to even
                         * have a pseudo-header.
                         */
-                       *err = WTAP_ERR_BAD_RECORD;
+                       *err = WTAP_ERR_BAD_FILE;
                        *err_info = g_strdup_printf("pcap: LAPD file has a %u-byte packet, too small to have even a LAPD pseudo-header",
                            packet_size);
                        return -1;
@@ -1276,7 +1515,7 @@ pcap_process_pseudo_header(FILE_T fh, int file_type, int wtap_encap, gboolean by
                         * Uh-oh, the packet isn't big enough to even
                         * have a pseudo-header.
                         */
-                       *err = WTAP_ERR_BAD_RECORD;
+                       *err = WTAP_ERR_BAD_FILE;
                        *err_info = g_strdup_printf("pcap: SITA file has a %u-byte packet, too small to have even a SITA pseudo-header",
                            packet_size);
                        return -1;
@@ -1288,26 +1527,6 @@ pcap_process_pseudo_header(FILE_T fh, int file_type, int wtap_encap, gboolean by
                phdr_len = SITA_HDR_LEN;
                break;
 
-       case WTAP_ENCAP_USB_LINUX:
-       case WTAP_ENCAP_USB_LINUX_MMAPPED:
-               if (check_packet_size &&
-                   packet_size < sizeof (struct linux_usb_phdr)) {
-                       /*
-                        * Uh-oh, the packet isn't big enough to even
-                        * have a pseudo-header.
-                        */
-                       *err = WTAP_ERR_BAD_RECORD;
-                       *err_info = g_strdup_printf("pcap: Linux USB file has a %u-byte packet, too small to have even a Linux USB pseudo-header",
-                           packet_size);
-                       return -1;
-               }
-               if (!pcap_read_linux_usb_pseudoheader(fh,
-                   pseudo_header, bytes_swapped, err))
-                       return -1;      /* Read error */
-
-               phdr_len = (int)sizeof (struct linux_usb_phdr);
-               break;
-
        case WTAP_ENCAP_BLUETOOTH_H4:
                /* We don't have pseudoheader, so just pretend we received everything. */
                pseudo_header->p2p.sent = FALSE;
@@ -1320,13 +1539,13 @@ pcap_process_pseudo_header(FILE_T fh, int file_type, int wtap_encap, gboolean by
                         * Uh-oh, the packet isn't big enough to even
                         * have a pseudo-header.
                         */
-                       *err = WTAP_ERR_BAD_RECORD;
-                       *err_info = g_strdup_printf("pcap: lipcap bluetooth file has a %u-byte packet, too small to have even a pseudo-header",
+                       *err = WTAP_ERR_BAD_FILE;
+                       *err_info = g_strdup_printf("pcap: libpcap bluetooth file has a %u-byte packet, too small to have even a pseudo-header",
                            packet_size);
                        return -1;
                }
                if (!pcap_read_bt_pseudoheader(fh,
-                   pseudo_header, err))
+                   pseudo_header, err, err_info))
                        return -1;      /* Read error */
 
                phdr_len = (int)sizeof (struct libpcap_bt_phdr);
@@ -1339,13 +1558,13 @@ pcap_process_pseudo_header(FILE_T fh, int file_type, int wtap_encap, gboolean by
                         * Uh-oh, the packet isn't big enough to even
                         * have a pseudo-header.
                         */
-                       *err = WTAP_ERR_BAD_RECORD;
-                       *err_info = g_strdup_printf("pcap: lipcap ppp file has a %u-byte packet, too small to have even a pseudo-header",
+                       *err = WTAP_ERR_BAD_FILE;
+                       *err_info = g_strdup_printf("pcap: libpcap ppp file has a %u-byte packet, too small to have even a pseudo-header",
                            packet_size);
                        return -1;
                }
                if (!pcap_read_ppp_pseudoheader(fh,
-                   pseudo_header, err))
+                   pseudo_header, err, err_info))
                        return -1;      /* Read error */
 
                phdr_len = (int)sizeof (struct libpcap_ppp_phdr);
@@ -1358,7 +1577,7 @@ pcap_process_pseudo_header(FILE_T fh, int file_type, int wtap_encap, gboolean by
                         * Uh-oh, the packet isn't big enough to even
                         * have a pseudo-header.
                         */
-                       *err = WTAP_ERR_BAD_RECORD;
+                       *err = WTAP_ERR_BAD_FILE;
                        *err_info = g_strdup_printf("pcap: ERF file has a %u-byte packet, too small to have even an ERF pseudo-header",
                            packet_size);
                        return -1;
@@ -1383,6 +1602,18 @@ pcap_process_pseudo_header(FILE_T fh, int file_type, int wtap_encap, gboolean by
                        return -1;      /* Read error */
 
                phdr_len += size;
+
+               if (check_packet_size &&
+                   packet_size < (guint)phdr_len) {
+                       /*
+                        * Uh-oh, the packet isn't big enough for the pseudo-
+                        * header.
+                        */
+                       *err = WTAP_ERR_BAD_FILE;
+                       *err_info = g_strdup_printf("pcap: ERF file has a %u-byte packet, too small for a pseudo-header with ex- and sub-headers (%d)",
+                           packet_size, phdr_len);
+                       return -1;
+               }
                break;
 
        case WTAP_ENCAP_I2C:
@@ -1392,7 +1623,7 @@ pcap_process_pseudo_header(FILE_T fh, int file_type, int wtap_encap, gboolean by
                         * Uh-oh, the packet isn't big enough to even
                         * have a pseudo-header.
                         */
-                       *err = WTAP_ERR_BAD_RECORD;
+                       *err = WTAP_ERR_BAD_FILE;
                        *err_info = g_strdup_printf("pcap: I2C file has a %u-byte packet, too small to have even a I2C pseudo-header",
                            packet_size);
                        return -1;
@@ -1411,6 +1642,64 @@ pcap_process_pseudo_header(FILE_T fh, int file_type, int wtap_encap, gboolean by
        return phdr_len;
 }
 
+void
+pcap_read_post_process(int file_type, int wtap_encap,
+    union wtap_pseudo_header *pseudo_header,
+    guint8 *pd, guint packet_size, gboolean bytes_swapped, int fcs_len)
+{
+       switch (wtap_encap) {
+
+       case WTAP_ENCAP_ATM_PDUS:
+               if (file_type == WTAP_FILE_PCAP_NOKIA) {
+                       /*
+                        * Nokia IPSO ATM.
+                        *
+                        * Guess the traffic type based on the packet
+                        * contents.
+                        */
+                       atm_guess_traffic_type(pd, packet_size, pseudo_header);
+               } else {
+                       /*
+                        * SunATM.
+                        *
+                        * If this is ATM LANE traffic, try to guess what
+                        * type of LANE traffic it is based on the packet
+                        * contents.
+                        */
+                       if (pseudo_header->atm.type == TRAF_LANE)
+                               atm_guess_lane_type(pd, packet_size,
+                                   pseudo_header);
+               }
+               break;
+
+       case WTAP_ENCAP_ETHERNET:
+               pseudo_header->eth.fcs_len = fcs_len;
+               break;
+
+       case WTAP_ENCAP_USB_LINUX:
+               pcap_process_linux_usb_pseudoheader(packet_size,
+                   bytes_swapped, FALSE, pd);
+               break;
+
+       case WTAP_ENCAP_USB_LINUX_MMAPPED:
+               pcap_process_linux_usb_pseudoheader(packet_size,
+                   bytes_swapped, TRUE, pd);
+               break;
+
+       case WTAP_ENCAP_NETANALYZER:
+               /*
+                * Not strictly necessary, as the netANALYZER
+                * dissector calls the "Ethernet with FCS"
+                * dissector, but we might as well set it.
+                */
+               pseudo_header->eth.fcs_len = 4;
+               break;
+
+       default:
+               break;
+       }
+}
+
 int
 pcap_get_phdr_size(int encap, const union wtap_pseudo_header *pseudo_header)
 {
@@ -1438,15 +1727,8 @@ pcap_get_phdr_size(int encap, const union wtap_pseudo_header *pseudo_header)
                hdrsize = SITA_HDR_LEN;
                break;
 
-       case WTAP_ENCAP_USB_LINUX:
-       case WTAP_ENCAP_USB_LINUX_MMAPPED:
-               hdrsize = (int)sizeof (struct linux_usb_phdr);
-               break;
-
        case WTAP_ENCAP_ERF:
                hdrsize = (int)sizeof (struct erf_phdr);
-               if (pseudo_header->erf.phdr.type & 0x80)
-                       hdrsize += 8;
                switch (pseudo_header->erf.phdr.type & 0x7F) {
 
                case ERF_TYPE_MC_HDLC:
@@ -1468,6 +1750,22 @@ pcap_get_phdr_size(int encap, const union wtap_pseudo_header *pseudo_header)
                default:
                        break;
                }
+
+               /*
+                * Add in the lengths of the extension headers.
+                */
+               if (pseudo_header->erf.phdr.type & 0x80) {
+                       int i = 0, max = sizeof(pseudo_header->erf.ehdr_list)/sizeof(struct erf_ehdr);
+                       guint8 erf_exhdr[8];
+                       guint8 type;
+
+                       do {
+                               phtonll(erf_exhdr, pseudo_header->erf.ehdr_list[i].ehdr);
+                               type = erf_exhdr[0];
+                               hdrsize += 8;
+                               i++;
+                       } while (type & 0x80 && i < max);
+               }
                break;
 
        case WTAP_ENCAP_I2C:
@@ -1503,7 +1801,6 @@ pcap_write_phdr(wtap_dumper *wdh, int encap, const union wtap_pseudo_header *pse
        struct i2c_file_hdr i2c_hdr;
        struct libpcap_bt_phdr bt_hdr;
        struct libpcap_ppp_phdr ppp_hdr;
-       size_t nwritten;
        size_t size;
 
        switch (encap) {
@@ -1543,14 +1840,8 @@ pcap_write_phdr(wtap_dumper *wdh, int encap, const union wtap_pseudo_header *pse
                }
                atm_hdr[SUNATM_VPI] = (guint8)pseudo_header->atm.vpi;
                phtons(&atm_hdr[SUNATM_VCI], pseudo_header->atm.vci);
-               nwritten = wtap_dump_file_write(wdh, atm_hdr, sizeof(atm_hdr));
-               if (nwritten != sizeof(atm_hdr)) {
-                       if (nwritten == 0 && wtap_dump_file_ferror(wdh))
-                               *err = wtap_dump_file_ferror(wdh);
-                       else
-                               *err = WTAP_ERR_SHORT_WRITE;
+               if (!wtap_dump_file_write(wdh, atm_hdr, sizeof(atm_hdr), err))
                        return FALSE;
-               }
                wdh->bytes_dumped += sizeof(atm_hdr);
                break;
 
@@ -1562,14 +1853,8 @@ pcap_write_phdr(wtap_dumper *wdh, int encap, const union wtap_pseudo_header *pse
                phtons(&irda_hdr[IRDA_SLL_PKTTYPE_OFFSET],
                    pseudo_header->irda.pkttype);
                phtons(&irda_hdr[IRDA_SLL_PROTOCOL_OFFSET], 0x0017);
-               nwritten = wtap_dump_file_write(wdh, irda_hdr, sizeof(irda_hdr));
-               if (nwritten != sizeof(irda_hdr)) {
-                       if (nwritten == 0 && wtap_dump_file_ferror(wdh))
-                               *err = wtap_dump_file_ferror(wdh);
-                       else
-                               *err = WTAP_ERR_SHORT_WRITE;
+               if (!wtap_dump_file_write(wdh, irda_hdr, sizeof(irda_hdr), err))
                        return FALSE;
-               }
                wdh->bytes_dumped += sizeof(irda_hdr);
                break;
 
@@ -1582,14 +1867,8 @@ pcap_write_phdr(wtap_dumper *wdh, int encap, const union wtap_pseudo_header *pse
                mtp2_hdr[MTP2_ANNEX_A_USED_OFFSET] = pseudo_header->mtp2.annex_a_used;
                phtons(&mtp2_hdr[MTP2_LINK_NUMBER_OFFSET],
                    pseudo_header->mtp2.link_number);
-               nwritten = wtap_dump_file_write(wdh, mtp2_hdr, sizeof(mtp2_hdr));
-               if (nwritten != sizeof(mtp2_hdr)) {
-                       if (nwritten == 0 && wtap_dump_file_ferror(wdh))
-                               *err = wtap_dump_file_ferror(wdh);
-                       else
-                               *err = WTAP_ERR_SHORT_WRITE;
+               if (!wtap_dump_file_write(wdh, mtp2_hdr, sizeof(mtp2_hdr), err))
                        return FALSE;
-               }
                wdh->bytes_dumped += sizeof(mtp2_hdr);
                break;
 
@@ -1603,14 +1882,8 @@ pcap_write_phdr(wtap_dumper *wdh, int encap, const union wtap_pseudo_header *pse
                phtons(&lapd_hdr[LAPD_SLL_PROTOCOL_OFFSET], ETH_P_LAPD);
                lapd_hdr[LAPD_SLL_ADDR_OFFSET + 0] =
                    pseudo_header->lapd.we_network?0x01:0x00;
-               nwritten = fwrite(&lapd_hdr, 1, sizeof(lapd_hdr), wdh->fh);
-               if (nwritten != sizeof(lapd_hdr)) {
-                       if (nwritten == 0 && ferror(wdh->fh))
-                               *err = errno;
-                       else
-                               *err = WTAP_ERR_SHORT_WRITE;
+               if (!wtap_dump_file_write(wdh, lapd_hdr, sizeof(lapd_hdr), err))
                        return FALSE;
-               }
                wdh->bytes_dumped += sizeof(lapd_hdr);
                break;
 
@@ -1619,48 +1892,22 @@ pcap_write_phdr(wtap_dumper *wdh, int encap, const union wtap_pseudo_header *pse
                 * Write the SITA header.
                 */
                memset(&sita_hdr, 0, sizeof(sita_hdr));
-               sita_hdr[SITA_FLAGS_OFFSET]   = pseudo_header->sita.flags;
-               sita_hdr[SITA_SIGNALS_OFFSET] = pseudo_header->sita.signals;
-               sita_hdr[SITA_ERRORS1_OFFSET] = pseudo_header->sita.errors1;
-               sita_hdr[SITA_ERRORS2_OFFSET] = pseudo_header->sita.errors2;
-               sita_hdr[SITA_PROTO_OFFSET]   = pseudo_header->sita.proto;
-               nwritten = fwrite(&sita_hdr, 1, sizeof(sita_hdr), wdh->fh);
-               if (nwritten != sizeof(sita_hdr)) {
-                       if (nwritten == 0 && ferror(wdh->fh))
-                               *err = errno;
-                       else
-                               *err = WTAP_ERR_SHORT_WRITE;
+               sita_hdr[SITA_FLAGS_OFFSET]   = pseudo_header->sita.sita_flags;
+               sita_hdr[SITA_SIGNALS_OFFSET] = pseudo_header->sita.sita_signals;
+               sita_hdr[SITA_ERRORS1_OFFSET] = pseudo_header->sita.sita_errors1;
+               sita_hdr[SITA_ERRORS2_OFFSET] = pseudo_header->sita.sita_errors2;
+               sita_hdr[SITA_PROTO_OFFSET]   = pseudo_header->sita.sita_proto;
+               if (!wtap_dump_file_write(wdh, sita_hdr, sizeof(sita_hdr), err))
                        return FALSE;
-               }
                wdh->bytes_dumped += sizeof(sita_hdr);
                break;
 
-       case WTAP_ENCAP_USB_LINUX:
-       case WTAP_ENCAP_USB_LINUX_MMAPPED:
-               /*
-                * Write out the pseudo-header; it has the same format
-                * as the Linux USB header, and that header is supposed
-                * to be written in the host byte order of the machine
-                * writing the file.
-                */
-               nwritten = fwrite(&pseudo_header->linux_usb, 1,
-                   sizeof(pseudo_header->linux_usb), wdh->fh);
-               if (nwritten != sizeof(pseudo_header->linux_usb)) {
-                       if (nwritten == 0 && ferror(wdh->fh))
-                               *err = errno;
-                       else
-                               *err = WTAP_ERR_SHORT_WRITE;
-                       return FALSE;
-               }
-               wdh->bytes_dumped += sizeof(lapd_hdr);
-               break;
-
        case WTAP_ENCAP_ERF:
-                /*
+               /*
                 * Write the ERF header.
                 */
                memset(&erf_hdr, 0, sizeof(erf_hdr));
-               pletonll(&erf_hdr[0], pseudo_header->erf.phdr.ts);
+               phtolell(&erf_hdr[0], pseudo_header->erf.phdr.ts);
                erf_hdr[8] = pseudo_header->erf.phdr.type;
                erf_hdr[9] = pseudo_header->erf.phdr.flags;
                phtons(&erf_hdr[10], pseudo_header->erf.phdr.rlen);
@@ -1688,15 +1935,27 @@ pcap_write_phdr(wtap_dumper *wdh, int encap, const union wtap_pseudo_header *pse
                default:
                  break;
                }
-               nwritten = wtap_dump_file_write(wdh, erf_hdr, size);
-               if (nwritten != (guint) size) {
-                       if (nwritten == 0 && wtap_dump_file_ferror(wdh))
-                               *err = wtap_dump_file_ferror(wdh);
-                       else
-                               *err = WTAP_ERR_SHORT_WRITE;
+               if (!wtap_dump_file_write(wdh, erf_hdr, size, err))
                        return FALSE;
-               }
                wdh->bytes_dumped += size;
+
+               /*
+                * Now write out the extension headers.
+                */
+               if (pseudo_header->erf.phdr.type & 0x80) {
+                       int i = 0, max = sizeof(pseudo_header->erf.ehdr_list)/sizeof(struct erf_ehdr);
+                       guint8 erf_exhdr[8];
+                       guint8 type;
+
+                       do {
+                               phtonll(erf_exhdr, pseudo_header->erf.ehdr_list[i].ehdr);
+                               type = erf_exhdr[0];
+                               if (!wtap_dump_file_write(wdh, erf_exhdr, 8, err))
+                                       return FALSE;
+                               wdh->bytes_dumped += 8;
+                               i++;
+                       } while (type & 0x80 && i < max);
+               }
                break;
 
        case WTAP_ENCAP_I2C:
@@ -1707,40 +1966,22 @@ pcap_write_phdr(wtap_dumper *wdh, int encap, const union wtap_pseudo_header *pse
                i2c_hdr.bus = pseudo_header->i2c.bus |
                        (pseudo_header->i2c.is_event ? 0x80 : 0x00);
                phtonl((guint8 *)&i2c_hdr.flags, pseudo_header->i2c.flags);
-               nwritten = fwrite(&i2c_hdr, 1, sizeof(i2c_hdr), wdh->fh);
-               if (nwritten != sizeof(i2c_hdr)) {
-                       if (nwritten == 0 && ferror(wdh->fh))
-                               *err = errno;
-                       else
-                               *err = WTAP_ERR_SHORT_WRITE;
+               if (!wtap_dump_file_write(wdh, &i2c_hdr, sizeof(i2c_hdr), err))
                        return FALSE;
-               }
                wdh->bytes_dumped += sizeof(i2c_hdr);
                break;
 
        case WTAP_ENCAP_BLUETOOTH_H4_WITH_PHDR:
                bt_hdr.direction = GUINT32_TO_BE(pseudo_header->p2p.sent ? LIBPCAP_BT_PHDR_SENT : LIBPCAP_BT_PHDR_RECV);
-               nwritten = wtap_dump_file_write(wdh, &bt_hdr, sizeof bt_hdr);
-               if (nwritten != sizeof bt_hdr) {
-                       if (nwritten == 0 && wtap_dump_file_ferror(wdh))
-                               *err = wtap_dump_file_ferror(wdh);
-                       else
-                               *err = WTAP_ERR_SHORT_WRITE;
+               if (!wtap_dump_file_write(wdh, &bt_hdr, sizeof bt_hdr, err))
                        return FALSE;
-               }
                wdh->bytes_dumped += sizeof bt_hdr;
                break;
 
        case WTAP_ENCAP_PPP_WITH_PHDR:
                ppp_hdr.direction = (pseudo_header->p2p.sent ? LIBPCAP_PPP_PHDR_SENT : LIBPCAP_PPP_PHDR_RECV);
-               nwritten = wtap_dump_file_write(wdh, &ppp_hdr, sizeof ppp_hdr);
-               if (nwritten != sizeof ppp_hdr) {
-                       if (nwritten == 0 && wtap_dump_file_ferror(wdh))
-                               *err = wtap_dump_file_ferror(wdh);
-                       else
-                               *err = WTAP_ERR_SHORT_WRITE;
+               if (!wtap_dump_file_write(wdh, &ppp_hdr, sizeof ppp_hdr, err))
                        return FALSE;
-               }
                wdh->bytes_dumped += sizeof ppp_hdr;
                break;
        }