aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2016-08-18 11:44:32 -0700
committerGuy Harris <guy@alum.mit.edu>2016-08-18 11:44:32 -0700
commit6aa0f48883bf69a5c8fb09532ec47edfb9750ee7 (patch)
tree6361ca880787655f10b8c64d3df93dd7b800aafb
parent18bf0f9560fcf0fdc331c8109990bf46d63941de (diff)
Have separate DLTs for big-endian and host-endian SocketCAN headers.
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.
-rw-r--r--Makefile.in1
-rw-r--r--gencode.c3
-rw-r--r--pcap-can-linux.c2
-rw-r--r--pcap-canusb-linux.c2
-rw-r--r--pcap-common.c52
-rw-r--r--pcap-linux.c19
-rw-r--r--pcap.c3
-rw-r--r--pcap/can_socketcan.h54
-rw-r--r--pcap/dlt.h18
9 files changed, 141 insertions, 13 deletions
diff --git a/Makefile.in b/Makefile.in
index 087c10ff..b77d5f1d 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -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 \
diff --git a/gencode.c b/gencode.c
index b0cadc32..d1326f70 100644
--- 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:
diff --git a/pcap-can-linux.c b/pcap-can-linux.c
index 5715f973..dce4a28c 100644
--- a/pcap-can-linux.c
+++ b/pcap-can-linux.c
@@ -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;
diff --git a/pcap-canusb-linux.c b/pcap-canusb-linux.c
index 9a176c30..3201edc9 100644
--- a/pcap-canusb-linux.c
+++ b/pcap-canusb-linux.c
@@ -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);
diff --git a/pcap-common.c b/pcap-common.c
index 1aca831a..229e1a18 100644
--- a/pcap-common.c
+++ b/pcap-common.c
@@ -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"
@@ -743,12 +744,14 @@
/*
* 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 <felix@obenhuber.de>.
*/
-#define LINKTYPE_CAN_SOCKETCAN 227
+#define LINKTYPE_CAN_SOCKETCAN_BIGENDIAN 227
/*
* Raw IPv4/IPv6; different from DLT_RAW in that the DLT_ value specifies
@@ -1017,7 +1020,16 @@
*/
#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;
}
}
diff --git a/pcap-linux.c b/pcap-linux.c
index 4df339c2..a2ace7b7 100644
--- a/pcap-linux.c
+++ b/pcap-linux.c
@@ -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 20c15699..052551fd 100644
--- 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
index 00000000..68d2a131
--- /dev/null
+++ b/pcap/can_socketcan.h
@@ -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
diff --git a/pcap/dlt.h b/pcap/dlt.h
index 4cebe31c..63866c25 100644
--- a/pcap/dlt.h
+++ b/pcap/dlt.h
@@ -993,11 +993,14 @@
/*
* 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 <felix@obenhuber.de>.
*/
+#define DLT_CAN_SOCKETCAN_BIGENDIAN 227
#define DLT_CAN_SOCKETCAN 227
/*
@@ -1299,6 +1302,15 @@
#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,
* with a different value (perhaps because that OS hasn't picked up
@@ -1308,7 +1320,7 @@
#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