]> The Tcpdump Group git mirrors - libpcap/commitdiff
For DLT_LINUX_SLL SocketCAN packets, fix up the header when reading.
authorGuy Harris <[email protected]>
Fri, 19 Aug 2016 00:29:32 +0000 (17:29 -0700)
committerGuy Harris <[email protected]>
Fri, 19 Aug 2016 00:29:32 +0000 (17:29 -0700)
As with other SocketCAN headers, except for those captured with
pcap-can-linux.c, the CAN ID and flags field is in host byte order, and
needs to be fixed up if we're reading a capture written by a host with
the opposite byte order.

Makefile.in
extract.h [new file with mode: 0644]
pcap-common.c
pcap/sll.h

index b77d5f1dfa54d7d02e29ca182b9bb75f29620557..cdf4f618db9dcad4096707748a377180a322eb32 100644 (file)
@@ -114,6 +114,7 @@ HDR = $(PUBHDR) \
        arcnet.h \
        atmuni31.h \
        ethertype.h \
+       extract.h \
        gencode.h \
        ieee80211.h \
        llc.h \
diff --git a/extract.h b/extract.h
new file mode 100644 (file)
index 0000000..cb62ebd
--- /dev/null
+++ b/extract.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 1992, 1993, 1994, 1995, 1996
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Macros to extract possibly-unaligned big-endian integral values.
+ */
+#ifdef LBL_ALIGN
+/*
+ * The processor doesn't natively handle unaligned loads.
+ */
+#if defined(__GNUC__) && defined(HAVE___ATTRIBUTE__) && \
+    (defined(__alpha) || defined(__alpha__) || \
+     defined(__mips) || defined(__mips__))
+
+/*
+ * This is a GCC-compatible compiler and we have __attribute__, which
+ * we assume that mean we have __attribute__((packed)), and this is
+ * MIPS or Alpha, which has instructions that can help when doing
+ * unaligned loads.
+ *
+ * Declare packed structures containing a uint16_t and a uint32_t,
+ * cast the pointer to point to one of those, and fetch through it;
+ * the GCC manual doesn't appear to explicitly say that
+ * __attribute__((packed)) causes the compiler to generate unaligned-safe
+ * code, but it apppears to do so.
+ *
+ * We do this in case the compiler can generate code using those
+ * instructions to do an unaligned load and pass stuff to "ntohs()" or
+ * "ntohl()", which might be better than than the code to fetch the
+ * bytes one at a time and assemble them.  (That might not be the
+ * case on a little-endian platform, such as DEC's MIPS machines and
+ * Alpha machines, where "ntohs()" and "ntohl()" might not be done
+ * inline.)
+ *
+ * We do this only for specific architectures because, for example,
+ * at least some versions of GCC, when compiling for 64-bit SPARC,
+ * generate code that assumes alignment if we do this.
+ *
+ * XXX - add other architectures and compilers as possible and
+ * appropriate.
+ *
+ * HP's C compiler, indicated by __HP_cc being defined, supports
+ * "#pragma unaligned N" in version A.05.50 and later, where "N"
+ * specifies a number of bytes at which the typedef on the next
+ * line is aligned, e.g.
+ *
+ *     #pragma unalign 1
+ *     typedef uint16_t unaligned_uint16_t;
+ *
+ * to define unaligned_uint16_t as a 16-bit unaligned data type.
+ * This could be presumably used, in sufficiently recent versions of
+ * the compiler, with macros similar to those below.  This would be
+ * useful only if that compiler could generate better code for PA-RISC
+ * or Itanium than would be generated by a bunch of shifts-and-ORs.
+ *
+ * DEC C, indicated by __DECC being defined, has, at least on Alpha,
+ * an __unaligned qualifier that can be applied to pointers to get the
+ * compiler to generate code that does unaligned loads and stores when
+ * dereferencing the pointer in question.
+ *
+ * XXX - what if the native C compiler doesn't support
+ * __attribute__((packed))?  How can we get it to generate unaligned
+ * accesses for *specific* items?
+ */
+typedef struct {
+       uint16_t        val;
+} __attribute__((packed)) unaligned_uint16_t;
+
+typedef struct {
+       uint32_t        val;
+} __attribute__((packed)) unaligned_uint32_t;
+
+static inline uint16_t
+EXTRACT_16BITS(const void *p)
+{
+       return ((uint16_t)ntohs(((const unaligned_uint16_t *)(p))->val));
+}
+
+static inline uint32_t
+EXTRACT_32BITS(const void *p)
+{
+       return ((uint32_t)ntohl(((const unaligned_uint32_t *)(p))->val));
+}
+
+static inline uint64_t
+EXTRACT_64BITS(const void *p)
+{
+       return ((uint64_t)(((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 0)->val)) << 32 | \
+               ((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 1)->val)) << 0));
+}
+
+#else /* have to do it a byte at a time */
+/*
+ * This isn't a GCC-compatible compiler, we don't have __attribute__,
+ * or we do but we don't know of any better way with this instruction
+ * set to do unaligned loads, so do unaligned loads of big-endian
+ * quantities the hard way - fetch the bytes one at a time and
+ * assemble them.
+ */
+#define EXTRACT_16BITS(p) \
+       ((uint16_t)(((uint16_t)(*((const uint8_t *)(p) + 0)) << 8) | \
+                   ((uint16_t)(*((const uint8_t *)(p) + 1)) << 0)))
+#define EXTRACT_32BITS(p) \
+       ((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 0)) << 24) | \
+                   ((uint32_t)(*((const uint8_t *)(p) + 1)) << 16) | \
+                   ((uint32_t)(*((const uint8_t *)(p) + 2)) << 8) | \
+                   ((uint32_t)(*((const uint8_t *)(p) + 3)) << 0)))
+#define EXTRACT_64BITS(p) \
+       ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 56) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 1)) << 48) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 2)) << 40) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 3)) << 32) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 4)) << 24) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 5)) << 16) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 6)) << 8) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 7)) << 0)))
+#endif /* must special-case unaligned accesses */
+#else /* LBL_ALIGN */
+/*
+ * The processor natively handles unaligned loads, so we can just
+ * cast the pointer and fetch through it.
+ */
+static inline uint16_t
+EXTRACT_16BITS(const void *p)
+{
+       return ((uint16_t)ntohs(*(const uint16_t *)(p)));
+}
+
+static inline uint32_t
+EXTRACT_32BITS(const void *p)
+{
+       return ((uint32_t)ntohl(*(const uint32_t *)(p)));
+}
+
+static inline uint64_t
+EXTRACT_64BITS(const void *p)
+{
+       return ((uint64_t)(((uint64_t)ntohl(*((const uint32_t *)(p) + 0))) << 32 | \
+               ((uint64_t)ntohl(*((const uint32_t *)(p) + 1))) << 0));
+
+}
+
+#endif /* LBL_ALIGN */
+
+#define EXTRACT_24BITS(p) \
+       ((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 0)) << 16) | \
+                   ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+                   ((uint32_t)(*((const uint8_t *)(p) + 2)) << 0)))
+
+#define EXTRACT_40BITS(p) \
+       ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 32) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 1)) << 24) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 3)) << 8) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 4)) << 0)))
+
+#define EXTRACT_48BITS(p) \
+       ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 40) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 1)) << 32) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 2)) << 24) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 3)) << 16) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 4)) << 8) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 5)) << 0)))
+
+#define EXTRACT_56BITS(p) \
+       ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 48) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 1)) << 40) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 2)) << 32) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 4)) << 16) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 5)) << 8) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 6)) << 0)))
+
+/*
+ * Macros to extract possibly-unaligned little-endian integral values.
+ * XXX - do loads on little-endian machines that support unaligned loads?
+ */
+#define EXTRACT_LE_8BITS(p) (*(p))
+#define EXTRACT_LE_16BITS(p) \
+       ((uint16_t)(((uint16_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+                   ((uint16_t)(*((const uint8_t *)(p) + 0)) << 0)))
+#define EXTRACT_LE_32BITS(p) \
+       ((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 3)) << 24) | \
+                   ((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \
+                   ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+                   ((uint32_t)(*((const uint8_t *)(p) + 0)) << 0)))
+#define EXTRACT_LE_24BITS(p) \
+       ((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \
+                   ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+                   ((uint32_t)(*((const uint8_t *)(p) + 0)) << 0)))
+#define EXTRACT_LE_64BITS(p) \
+       ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 7)) << 56) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 6)) << 48) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 5)) << 40) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 4)) << 32) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 0)) << 0)))
index 229e1a18027cc597d556f9bac12b97ce8dd622b2..71bf927825dbda04ce6f0b1cb3f1f62b10b7e329 100644 (file)
@@ -40,6 +40,8 @@
 #endif /* _WIN32 */
 
 #include "pcap-int.h"
+#include "extract.h"
+#include "pcap/sll.h"
 #include "pcap/usb.h"
 #include "pcap/nflog.h"
 #include "pcap/can_socketcan.h"
@@ -1176,6 +1178,48 @@ linktype_to_dlt(int linktype)
        return linktype;
 }
 
+#define EXTRACT_
+
+/*
+ * DLT_LINUX_SLL packets with a protocol type of LINUX_SLL_P_CAN have
+ * SocketCAN headers in front of the payload, with the CAN ID being
+ * in host byte order.
+ *
+ * When reading a DLT_LINUX_SLL capture file, we need to check for those
+ * packets and convert the CAN ID from the byte order of the host that
+ * wrote the file to this host's byte order.
+ */
+static void
+swap_linux_sll_header(const struct pcap_pkthdr *hdr, u_char *buf)
+{
+       u_int caplen = hdr->caplen;
+       u_int length = hdr->len;
+       struct sll_header *shdr = (struct sll_header *)buf;
+       u_int16_t protocol;
+       pcap_can_socketcan_hdr *chdr;
+
+       if (caplen < (u_int) sizeof(struct sll_header) ||
+           length < (u_int) sizeof(struct sll_header)) {
+               /* Not enough data to have the protocol field */
+               return;
+       }
+
+       protocol = EXTRACT_16BITS(&shdr->sll_protocol);
+       if (protocol != LINUX_SLL_P_CAN)
+               return;
+
+       /*
+        * SocketCAN packet; fix up the packet's header.
+        */
+       chdr = (pcap_can_socketcan_hdr *)(buf + sizeof(struct sll_header));
+       if (caplen < (u_int) sizeof(struct sll_header) + sizeof(chdr->can_id) ||
+           length < (u_int) sizeof(struct sll_header) + sizeof(chdr->can_id)) {
+               /* Not enough data to have the CAN ID */
+               return;
+       }
+       chdr->can_id = SWAPLONG(chdr->can_id);
+}
+
 /*
  * The DLT_USB_LINUX and DLT_USB_LINUX_MMAPPED headers are in host
  * byte order when capturing (it's supplied directly from a
@@ -1392,9 +1436,9 @@ swap_nflog_header(const struct pcap_pkthdr *hdr, u_char *buf)
 }
 
 /*
- * The DLT_CAN_SOCKETCAN_HOSTENDIAN header is in host byte order when
- * capturing (it's filled in by the kernel and provided on a PF_PACKET
- * socket).
+ * The CAN ID in the DLT_CAN_SOCKETCAN_HOSTENDIAN header is in host byte
+ * order when capturing (the header is filled in by the kernel and provided
+ * on a PF_PACKET socket).
  *
  * When reading a DLT_CAN_SOCKETCAN_HOSTENDIAN capture file, we need to
  * convert it from the byte order of the host that wrote the file to
@@ -1409,7 +1453,7 @@ swap_can_socketcan_header(const struct pcap_pkthdr *hdr, u_char *buf)
 
        if (caplen < (u_int) sizeof(chdr->can_id) ||
            length < (u_int) sizeof(chdr->can_id)) {
-               /* Not enough data to have the ID */
+               /* Not enough data to have the CAN ID */
                return;
        }
 
@@ -1426,6 +1470,10 @@ swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr, u_char *data)
         */
        switch (linktype) {
 
+       case DLT_LINUX_SLL:
+               swap_linux_sll_header(hdr, data);
+               break;
+
        case DLT_USB_LINUX:
                swap_linux_usb_header(hdr, data, 0);
                break;
index 38da29f5090e914964822fb6b099ce5ca17799ed..69ffa8b0d4f0058d0d7cfa86dcea33167e8260e6 100644 (file)
@@ -123,5 +123,6 @@ struct sll_header {
  */
 #define LINUX_SLL_P_802_3      0x0001  /* Novell 802.3 frames without 802.2 LLC header */
 #define LINUX_SLL_P_802_2      0x0004  /* 802.2 frames (not D/I/X Ethernet) */
+#define LINUX_SLL_P_CAN                0x000C  /* CAN frames, with SocketCAN pseudo-headers */
 
 #endif