From: Guy Harris Date: Fri, 19 Aug 2016 00:29:32 +0000 (-0700) Subject: For DLT_LINUX_SLL SocketCAN packets, fix up the header when reading. X-Git-Tag: libpcap-1.8.1~30 X-Git-Url: https://git.tcpdump.org/libpcap/commitdiff_plain/5bb9c18cf6ee5586e96da4b7df93e8093ecc88ae For DLT_LINUX_SLL SocketCAN packets, fix up the header when reading. 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. --- diff --git a/Makefile.in b/Makefile.in index b77d5f1d..cdf4f618 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 index 00000000..cb62ebdd --- /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))) diff --git a/pcap-common.c b/pcap-common.c index 229e1a18..71bf9278 100644 --- a/pcap-common.c +++ b/pcap-common.c @@ -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; diff --git a/pcap/sll.h b/pcap/sll.h index 38da29f5..69ffa8b0 100644 --- a/pcap/sll.h +++ b/pcap/sll.h @@ -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