]> The Tcpdump Group git mirrors - libpcap/commitdiff
Have separate DLTs for big-endian and host-endian SocketCAN headers.
authorGuy Harris <[email protected]>
Thu, 18 Aug 2016 18:44:32 +0000 (11:44 -0700)
committerGuy Harris <[email protected]>
Thu, 18 Aug 2016 18:44:32 +0000 (11:44 -0700)
At least with some versions of the Linux kernel, you can capture on
SocketCAN interfaces with a PF_PACKET socket and get packets with
SocketCAN headers; that code doesn't special-case ARPHRD_CAN, so it
leaves the CAN ID field in host byte order.

In addition, the "capture CAN packets on a USB device" code wasn't
putting that field into host byte order, either.

So have separate DLT_/LINKTYPE_ types, one for packets with the CAN ID
in big-endian byte order and one for packets with the CAN ID in host
byte order.  When reading LINKTYPE_CAN_SOCKETCAN_HOSTENDIAN files, swap
the CAN ID field as necessary to put it into the byte order for the host
reading the file rather than the byte order for the host that wrote the
file.

Makefile.in
gencode.c
pcap-can-linux.c
pcap-canusb-linux.c
pcap-common.c
pcap-linux.c
pcap.c
pcap/can_socketcan.h [new file with mode: 0644]
pcap/dlt.h

index 087c10ffb897474e17179cb204bbdec40a0e3d03..b77d5f1dfa54d7d02e29ca182b9bb75f29620557 100644 (file)
@@ -99,6 +99,7 @@ PUBHDR = \
        pcap-namedb.h \
        pcap/bpf.h \
        pcap/bluetooth.h \
+       pcap/can_socketcan.h \
        pcap/dlt.h \
        pcap/export-defs.h \
        pcap/ipnet.h \
index b0cadc32d702e6483c46d4e440a618c6d76d0d46..d1326f70baba289dd56c734bf396d38b965b5a53 100644 (file)
--- a/gencode.c
+++ b/gencode.c
@@ -3397,7 +3397,8 @@ gen_linktype(compiler_state_t *cstate, int proto)
                bpf_error(cstate, "Bluetooth link-layer type filtering not implemented");
 
        case DLT_CAN20B:
-       case DLT_CAN_SOCKETCAN:
+       case DLT_CAN_SOCKETCAN_BIGENDIAN:
+       case DLT_CAN_SOCKETCAN_HOSTENDIAN:
                bpf_error(cstate, "CAN link-layer type filtering not implemented");
 
        case DLT_IEEE802_15_4:
index 5715f973f9b1fb94393de473cb6326297e3d6fd1..dce4a28c8283b8a30e5bd04c51624575d19c1adb 100644 (file)
@@ -151,7 +151,7 @@ can_activate(pcap_t* handle)
 
        /* Initialize some components of the pcap structure. */
        handle->bufsize = CAN_CONTROL_SIZE + 16;
-       handle->linktype = DLT_CAN_SOCKETCAN;
+       handle->linktype = DLT_CAN_SOCKETCAN_BIGENDIAN;
        handle->read_op = can_read_linux;
        handle->inject_op = can_inject_linux;
        handle->setfilter_op = can_setfilter_linux;
index 9a176c30f1a84e5c1e835d1768f6e88d658894db..3201edc95a64d73e8707e4ea04484ba39ae01ff9 100644 (file)
@@ -368,7 +368,7 @@ static int canusb_activate(pcap_t* handle)
     /* Initialize some components of the pcap structure. */
     handle->bufsize = 32;
     handle->offset = 8;
-    handle->linktype = DLT_CAN_SOCKETCAN;
+    handle->linktype = DLT_CAN_SOCKETCAN_HOSTENDIAN;
     handle->set_datalink_op = NULL;
 
     serial = handle->opt.device + strlen(CANUSB_IFACE);
index 1aca831a873eeda702e6f5ff92de31965d69e2f6..229e1a18027cc597d556f9bac12b97ce8dd622b2 100644 (file)
@@ -42,6 +42,7 @@
 #include "pcap-int.h"
 #include "pcap/usb.h"
 #include "pcap/nflog.h"
+#include "pcap/can_socketcan.h"
 
 #include "pcap-common.h"
 
 
 /*
  * CAN (Controller Area Network) frames, with a pseudo-header as supplied
- * by Linux SocketCAN.  See Documentation/networking/can.txt in the Linux
- * source.
+ * by Linux SocketCAN, and with multi-byte numerical fields in that header
+ * in big-endian byte order.
+ *
+ * See Documentation/networking/can.txt in the Linux source.
  *
  * Requested by Felix Obenhuber <[email protected]>.
  */
-#define LINKTYPE_CAN_SOCKETCAN 227
+#define LINKTYPE_CAN_SOCKETCAN_BIGENDIAN       227
 
 /*
  * Raw IPv4/IPv6; different from DLT_RAW in that the DLT_ value specifies
  */
 #define LINKTYPE_ISO_14443      264
 
-#define LINKTYPE_MATCHING_MAX  264             /* highest value in the "matching" range */
+/*
+ * CAN (Controller Area Network) frames, with a pseudo-header as supplied
+ * by Linux SocketCAN, and with multi-byte numerical fields in that header
+ * in host byte order.
+ *
+ * See Documentation/networking/can.txt in the Linux source.
+ */
+#define LINKTYPE_CAN_SOCKETCAN_HOSTENDIAN      265
+
+#define LINKTYPE_MATCHING_MAX  265             /* highest value in the "matching" range */
 
 static struct linktype_map {
        int     dlt;
@@ -1333,7 +1345,8 @@ swap_nflog_header(const struct pcap_pkthdr *hdr, u_char *buf)
        u_int length = hdr->len;
        u_int16_t size;
 
-       if (caplen < (int) sizeof(nflog_hdr_t) || length < (int) sizeof(nflog_hdr_t)) {
+       if (caplen < (u_int) sizeof(nflog_hdr_t) ||
+           length < (u_int) sizeof(nflog_hdr_t)) {
                /* Not enough data to have any TLVs. */
                return;
        }
@@ -1378,6 +1391,31 @@ 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).
+ *
+ * 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
+ * this host's byte order.
+ */
+static void
+swap_can_socketcan_header(const struct pcap_pkthdr *hdr, u_char *buf)
+{
+       u_int caplen = hdr->caplen;
+       u_int length = hdr->len;
+       pcap_can_socketcan_hdr *chdr = (pcap_can_socketcan_hdr *)buf;
+
+       if (caplen < (u_int) sizeof(chdr->can_id) ||
+           length < (u_int) sizeof(chdr->can_id)) {
+               /* Not enough data to have the ID */
+               return;
+       }
+
+       chdr->can_id = SWAPLONG(chdr->can_id);
+}
+
 void
 swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr, u_char *data)
 {
@@ -1399,5 +1437,9 @@ swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr, u_char *data)
        case DLT_NFLOG:
                swap_nflog_header(hdr, data);
                break;
+
+       case DLT_CAN_SOCKETCAN_HOSTENDIAN:
+               swap_can_socketcan_header(hdr, data);
+               break;
        }
 }
index 4df339c2d96b70c1153d43d61a07980d4a7ab4c1..a2ace7b7fbe3f66deda980400b4666248eaae329 100644 (file)
@@ -2943,7 +2943,24 @@ static void map_arphrd_to_dlt(pcap_t *handle, int sock_fd, int arptype,
 #define ARPHRD_CAN 280
 #endif
        case ARPHRD_CAN:
-               handle->linktype = DLT_CAN_SOCKETCAN;
+               /*
+                * DLT_CAN_SOCKETCAN_BIGENDIAN is defined to have the
+                * can_id field of the pseudo-header in big-endian
+                * (network) byte order.
+                *
+                * The packets delivered to sockets have that field
+                * in host byte order.
+                *
+                * The code that implements it in packet-can-linux.c
+                * passes that field to htonl() to put it into network
+                * byte order.
+                *
+                * The code that reads from a PF_PACKET socket doesn't
+                * change the byte order of that field, so we define
+                * a new DLT_CAN_SOCKETCAN_HOSTENDIAN, where the can_id
+                * is in host byte order.
+                */
+               handle->linktype = DLT_CAN_SOCKETCAN_HOSTENDIAN;
                break;
 
 #ifndef ARPHRD_IEEE802_TR
diff --git a/pcap.c b/pcap.c
index 20c15699adf8ce0d308c842da0e65a5f21f648a3..052551fd17e07e7048b2e2f736d15bf5e1aa67ab 100644 (file)
--- a/pcap.c
+++ b/pcap.c
@@ -1248,7 +1248,7 @@ static struct dlt_choice dlt_choices[] = {
        DLT_CHOICE(DLT_FC_2, "Fibre Channel FC-2"),
        DLT_CHOICE(DLT_FC_2_WITH_FRAME_DELIMS, "Fibre Channel FC-2 with frame delimiters"),
        DLT_CHOICE(DLT_IPNET, "Solaris ipnet"),
-       DLT_CHOICE(DLT_CAN_SOCKETCAN, "CAN-bus with SocketCAN headers"),
+       DLT_CHOICE(DLT_CAN_SOCKETCAN_BIGENDIAN, "CAN-bus with big-endian SocketCAN headers"),
        DLT_CHOICE(DLT_IPV4, "Raw IPv4"),
        DLT_CHOICE(DLT_IPV6, "Raw IPv6"),
        DLT_CHOICE(DLT_IEEE802_15_4_NOFCS, "IEEE 802.15.4 without FCS"),
@@ -1279,6 +1279,7 @@ static struct dlt_choice dlt_choices[] = {
        DLT_CHOICE(DLT_PROFIBUS_DL, "PROFIBUS data link layer"),
        DLT_CHOICE(DLT_PKTAP, "Apple DLT_PKTAP"),
        DLT_CHOICE(DLT_EPON, "Ethernet with 802.3 Clause 65 EPON preamble"),
+       DLT_CHOICE(DLT_CAN_SOCKETCAN_HOSTENDIAN, "CAN-bus with host-endian SocketCAN headers"),
        DLT_CHOICE_SENTINEL
 };
 
diff --git a/pcap/can_socketcan.h b/pcap/can_socketcan.h
new file mode 100644 (file)
index 0000000..68d2a13
--- /dev/null
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lib_pcap_can_socketcan_h
+#define lib_pcap_can_socketcan_h
+
+/*
+ * SocketCAN header, as per Documentation/networking/can.txt in the
+ * Linux source.
+ */
+typedef struct {
+       u_int32_t can_id;
+       u_int8_t payload_length;
+       u_int8_t pad;
+       u_int8_t reserved1;
+       u_int8_t reserved2;
+} pcap_can_socketcan_hdr;
+
+#endif
index 4cebe31c636bbf2a62da7573169cf1f48b74135f..63866c259a527ac6f8f794379885959fcd22d848 100644 (file)
 
 /*
  * CAN (Controller Area Network) frames, with a pseudo-header as supplied
- * by Linux SocketCAN.  See Documentation/networking/can.txt in the Linux
- * source.
+ * by Linux SocketCAN, and with multi-byte numerical fields in that header
+ * in big-endian byte order.
+ *
+ * See Documentation/networking/can.txt in the Linux source.
  *
  * Requested by Felix Obenhuber <[email protected]>.
  */
+#define DLT_CAN_SOCKETCAN_BIGENDIAN    227
 #define DLT_CAN_SOCKETCAN      227
 
 /*
  */
 #define DLT_ISO_14443           264
 
+/*
+ * CAN (Controller Area Network) frames, with a pseudo-header as supplied
+ * by Linux SocketCAN, and with multi-byte numerical fields in that header
+ * in host byte order.
+ *
+ * See Documentation/networking/can.txt in the Linux source.
+ */
+#define DLT_CAN_SOCKETCAN_HOSTENDIAN   265
+
 /*
  * In case the code that includes this file (directly or indirectly)
  * has also included OS files that happen to define DLT_MATCHING_MAX,
 #ifdef DLT_MATCHING_MAX
 #undef DLT_MATCHING_MAX
 #endif
-#define DLT_MATCHING_MAX       264     /* highest value in the "matching" range */
+#define DLT_MATCHING_MAX       265     /* highest value in the "matching" range */
 
 /*
  * DLT and savefile link type values are split into a class and