Handle the new LINKTYPE_CAN_SOCKETCAN_HOSTENDIAN.
Unfortunately, only one libpcap code path puts the CAN ID in the SocketCAN header in network byte order; the others leave it in host byte order. Therefore, a new LINKTYPE_/DLT_ value was introduced, and libpcap was changed to use that for the cases where the CAN ID is in host byte order. Support them both. This means we need to, when reading pcap and pcapng files, fix up the CAN ID if the host that wrote the file has a different byte order from ours (as libpcap also now does). This includes Linux "cooked" captures, which can include CAN packets. Change-Id: I75ff2d68d1fbdb42753ce85d18f04166f21736dd Reviewed-on: https://code.wireshark.org/review/17155 Reviewed-by: Guy Harris <guy@alum.mit.edu>
This commit is contained in:
parent
2a4d6f1b3c
commit
95c4c432c4
|
@ -96,8 +96,14 @@ static gpointer can_value(packet_info *pinfo _U_)
|
|||
return 0;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
SOCKETCAN_BIG_ENDIAN,
|
||||
SOCKETCAN_HOST_ENDIAN
|
||||
} socketcan_endianness;
|
||||
|
||||
static int
|
||||
dissect_socketcan(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
|
||||
dissect_socketcan_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
|
||||
socketcan_endianness endianness)
|
||||
{
|
||||
proto_tree *can_tree;
|
||||
proto_item *ti;
|
||||
|
@ -110,7 +116,9 @@ dissect_socketcan(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* dat
|
|||
col_clear(pinfo->cinfo,COL_INFO);
|
||||
|
||||
frame_len = tvb_get_guint8( tvb, CAN_LEN_OFFSET);
|
||||
can_id.id = tvb_get_ntohl(tvb, 0);
|
||||
can_id.id = (endianness == SOCKETCAN_BIG_ENDIAN) ?
|
||||
tvb_get_ntohl(tvb, 0) :
|
||||
tvb_get_h_guint32(tvb, 0);
|
||||
|
||||
if (can_id.id & CAN_RTR_FLAG)
|
||||
{
|
||||
|
@ -157,6 +165,20 @@ dissect_socketcan(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* dat
|
|||
return tvb_captured_length(tvb);
|
||||
}
|
||||
|
||||
static int
|
||||
dissect_socketcan_bigendian(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
|
||||
void* data _U_)
|
||||
{
|
||||
return dissect_socketcan_common(tvb, pinfo, tree, SOCKETCAN_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
static int
|
||||
dissect_socketcan_hostendian(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
|
||||
void* data _U_)
|
||||
{
|
||||
return dissect_socketcan_common(tvb, pinfo, tree, SOCKETCAN_HOST_ENDIAN);
|
||||
}
|
||||
|
||||
void
|
||||
proto_register_socketcan(void)
|
||||
{
|
||||
|
@ -227,7 +249,10 @@ proto_register_socketcan(void)
|
|||
"CAN", /* short name */
|
||||
"can" /* abbrev */
|
||||
);
|
||||
register_dissector("can", dissect_socketcan, proto_can);
|
||||
register_dissector("can-bigendian", dissect_socketcan_bigendian,
|
||||
proto_can);
|
||||
register_dissector("can-hostendian", dissect_socketcan_hostendian,
|
||||
proto_can);
|
||||
|
||||
proto_register_field_array(proto_can, hf, array_length(hf));
|
||||
proto_register_subtree_array(ett, array_length(ett));
|
||||
|
@ -245,11 +270,19 @@ proto_register_socketcan(void)
|
|||
void
|
||||
proto_reg_handoff_socketcan(void)
|
||||
{
|
||||
dissector_handle_t can_handle;
|
||||
dissector_handle_t socketcan_bigendian_handle;
|
||||
dissector_handle_t socketcan_hostendian_handle;
|
||||
|
||||
can_handle = create_dissector_handle(dissect_socketcan, proto_can);
|
||||
dissector_add_uint("wtap_encap", WTAP_ENCAP_SOCKETCAN, can_handle);
|
||||
dissector_add_uint("sll.ltype", LINUX_SLL_P_CAN, can_handle);
|
||||
socketcan_bigendian_handle = create_dissector_handle(dissect_socketcan_bigendian,
|
||||
proto_can);
|
||||
dissector_add_uint("wtap_encap", WTAP_ENCAP_SOCKETCAN_BIGENDIAN,
|
||||
socketcan_bigendian_handle);
|
||||
socketcan_hostendian_handle = create_dissector_handle(dissect_socketcan_hostendian,
|
||||
proto_can);
|
||||
dissector_add_uint("wtap_encap", WTAP_ENCAP_SOCKETCAN_HOSTENDIAN,
|
||||
socketcan_hostendian_handle);
|
||||
dissector_add_uint("sll.ltype", LINUX_SLL_P_CAN,
|
||||
socketcan_hostendian_handle);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -378,8 +378,8 @@ static const struct {
|
|||
{ 225, WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS },
|
||||
/* Solaris IPNET */
|
||||
{ 226, WTAP_ENCAP_IPNET },
|
||||
/* SocketCAN frame */
|
||||
{ 227, WTAP_ENCAP_SOCKETCAN },
|
||||
/* SocketCAN frame, with CAN ID in big-endian byte order */
|
||||
{ 227, WTAP_ENCAP_SOCKETCAN_BIGENDIAN },
|
||||
/* Raw IPv4 */
|
||||
{ 228, WTAP_ENCAP_RAW_IP4 },
|
||||
/* Raw IPv6 */
|
||||
|
@ -437,6 +437,9 @@ static const struct {
|
|||
/* ISO14443 contactless smartcard standards */
|
||||
{ 264, WTAP_ENCAP_ISO14443 },
|
||||
|
||||
/* SocketCAN frame, with CAN ID in host-endian byte order */
|
||||
{ 265, WTAP_ENCAP_SOCKETCAN_HOSTENDIAN },
|
||||
|
||||
/*
|
||||
* To repeat:
|
||||
*
|
||||
|
@ -744,6 +747,12 @@ wtap_encap_requires_phdr(int wtap_encap)
|
|||
*/
|
||||
#define NOKIA_LEN 4 /* length of the header */
|
||||
|
||||
/*
|
||||
* The fake link-layer header of Linux cooked packets.
|
||||
*/
|
||||
#define LINUX_SLL_PROTOCOL_OFFSET 14 /* protocol */
|
||||
#define LINUX_SLL_LEN 16 /* length of the header */
|
||||
|
||||
/*
|
||||
* The fake link-layer header of IrDA packets as introduced by Jean Tourrilhes
|
||||
* to libpcap.
|
||||
|
@ -1136,7 +1145,6 @@ struct usb_device_setup_hdr {
|
|||
guint16 wLength;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Offset of the *end* of a field within a particular structure.
|
||||
*/
|
||||
|
@ -1171,6 +1179,57 @@ struct usb_device_setup_hdr {
|
|||
PBSWAP64((guint8 *)fieldp); \
|
||||
}
|
||||
|
||||
struct can_socketcan_hdr {
|
||||
guint32 can_id; /* CAN ID and flags */
|
||||
guint8 payload_length; /* Frame payload length */
|
||||
guint8 padding;
|
||||
guint8 reserved1;
|
||||
guint8 reserved2;
|
||||
};
|
||||
|
||||
static void
|
||||
pcap_byteswap_linux_sll_pseudoheader(struct wtap_pkthdr *phdr, guint8 *pd)
|
||||
{
|
||||
guint packet_size;
|
||||
guint16 protocol;
|
||||
struct can_socketcan_hdr *can_socketcan_phdr;
|
||||
|
||||
/*
|
||||
* Minimum of captured and actual length (just in case the
|
||||
* actual length < the captured length, which Should Never
|
||||
* Happen).
|
||||
*/
|
||||
packet_size = phdr->caplen;
|
||||
if (packet_size > phdr->len)
|
||||
packet_size = phdr->len;
|
||||
|
||||
if (packet_size < LINUX_SLL_LEN) {
|
||||
/* Not enough data to have the protocol */
|
||||
return;
|
||||
}
|
||||
|
||||
protocol = pntoh16(&pd[LINUX_SLL_PROTOCOL_OFFSET]);
|
||||
if (protocol != 0x000C) {
|
||||
/* Not a CAN packet; nothing to fix */
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Greasy hack, but we never directly dereference any of
|
||||
* the fields in *can_socketcan_phdr, we just get offsets
|
||||
* of and addresses of its members and byte-swap it with a
|
||||
* byte-at-a-time macro, so it's alignment-safe.
|
||||
*/
|
||||
can_socketcan_phdr = (struct can_socketcan_hdr *)(void *)(pd + LINUX_SLL_LEN);
|
||||
|
||||
if (packet_size < LINUX_SLL_LEN + sizeof(can_socketcan_phdr->can_id)) {
|
||||
/* Not enough data to have the full CAN ID */
|
||||
return;
|
||||
}
|
||||
|
||||
PBSWAP32((guint8 *)&can_socketcan_phdr->can_id);
|
||||
}
|
||||
|
||||
static void
|
||||
pcap_byteswap_linux_usb_pseudoheader(struct wtap_pkthdr *phdr, guint8 *pd,
|
||||
gboolean header_len_64_bytes)
|
||||
|
@ -1328,6 +1387,37 @@ pcap_byteswap_nflog_pseudoheader(struct wtap_pkthdr *phdr, guint8 *pd)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pcap_byteswap_can_socketcan_pseudoheader(struct wtap_pkthdr *phdr, guint8 *pd)
|
||||
{
|
||||
guint packet_size;
|
||||
struct can_socketcan_hdr *can_socketcan_phdr;
|
||||
|
||||
/*
|
||||
* Minimum of captured and actual length (just in case the
|
||||
* actual length < the captured length, which Should Never
|
||||
* Happen).
|
||||
*/
|
||||
packet_size = phdr->caplen;
|
||||
if (packet_size > phdr->len)
|
||||
packet_size = phdr->len;
|
||||
|
||||
/*
|
||||
* Greasy hack, but we never directly dereference any of
|
||||
* the fields in *can_socketcan_phdr, we just get offsets
|
||||
* of and addresses of its members and byte-swap it with a
|
||||
* byte-at-a-time macro, so it's alignment-safe.
|
||||
*/
|
||||
can_socketcan_phdr = (struct can_socketcan_hdr *)(void *)pd;
|
||||
|
||||
if (packet_size < sizeof(can_socketcan_phdr->can_id)) {
|
||||
/* Not enough data to have the full CAN ID */
|
||||
return;
|
||||
}
|
||||
|
||||
PBSWAP32((guint8 *)&can_socketcan_phdr->can_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pseudo-header at the beginning of DLT_BLUETOOTH_HCI_H4_WITH_PHDR frames.
|
||||
* Values in network byte order.
|
||||
|
@ -1871,6 +1961,11 @@ pcap_read_post_process(int file_type, int wtap_encap,
|
|||
phdr->pseudo_header.eth.fcs_len = fcs_len;
|
||||
break;
|
||||
|
||||
case WTAP_ENCAP_SLL:
|
||||
if (bytes_swapped)
|
||||
pcap_byteswap_linux_sll_pseudoheader(phdr, pd);
|
||||
break;
|
||||
|
||||
case WTAP_ENCAP_USB_LINUX:
|
||||
if (bytes_swapped)
|
||||
pcap_byteswap_linux_usb_pseudoheader(phdr, pd, FALSE);
|
||||
|
@ -1894,6 +1989,7 @@ pcap_read_post_process(int file_type, int wtap_encap,
|
|||
if (bytes_swapped)
|
||||
pcap_byteswap_nflog_pseudoheader(phdr, pd);
|
||||
break;
|
||||
|
||||
case WTAP_ENCAP_ERF:
|
||||
/*
|
||||
* Update packet size to account for ERF padding and snapping.
|
||||
|
@ -1904,6 +2000,11 @@ pcap_read_post_process(int file_type, int wtap_encap,
|
|||
phdr->caplen = MIN(phdr->len, phdr->caplen);
|
||||
break;
|
||||
|
||||
case WTAP_ENCAP_SOCKETCAN_HOSTENDIAN:
|
||||
if (bytes_swapped)
|
||||
pcap_byteswap_can_socketcan_pseudoheader(phdr, pd);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -751,8 +751,8 @@ static struct encap_type_info encap_table_base[] = {
|
|||
/* WTAP_ENCAP_IPNET */
|
||||
{ "Solaris IPNET", "ipnet" },
|
||||
|
||||
/* WTAP_ENCAP_SOCKETCAN */
|
||||
{ "SocketCAN", "socketcan" },
|
||||
/* WTAP_ENCAP_SOCKETCAN_BIGENDIAN */
|
||||
{ "SocketCAN with big-endian CAN ID", "socketcan-bigendian" },
|
||||
|
||||
/* WTAP_ENCAP_IEEE_802_11_NETMON */
|
||||
{ "IEEE 802.11 plus Network Monitor radio header", "ieee-802-11-netmon" },
|
||||
|
@ -921,6 +921,9 @@ static struct encap_type_info encap_table_base[] = {
|
|||
|
||||
/* WTAP_ENCAP_JUNIPER_VN */
|
||||
{ "Juniper VN", "juniper-vn" },
|
||||
|
||||
/* WTAP_ENCAP_SOCKETCAN_HOSTENDIAN */
|
||||
{ "SocketCAN with host-endian CAN ID", "socketcan-hostendian" },
|
||||
};
|
||||
|
||||
WS_DLL_LOCAL
|
||||
|
|
|
@ -212,7 +212,7 @@ extern "C" {
|
|||
#define WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS 122
|
||||
#define WTAP_ENCAP_JPEG_JFIF 123 /* obsoleted by WTAP_ENCAP_MIME*/
|
||||
#define WTAP_ENCAP_IPNET 124
|
||||
#define WTAP_ENCAP_SOCKETCAN 125
|
||||
#define WTAP_ENCAP_SOCKETCAN_BIGENDIAN 125
|
||||
#define WTAP_ENCAP_IEEE_802_11_NETMON 126
|
||||
#define WTAP_ENCAP_IEEE802_15_4_NOFCS 127
|
||||
#define WTAP_ENCAP_RAW_IPFIX 128
|
||||
|
@ -269,6 +269,7 @@ extern "C" {
|
|||
#define WTAP_ENCAP_GFP_F 179
|
||||
#define WTAP_ENCAP_IP_OVER_IB_PCAP 180
|
||||
#define WTAP_ENCAP_JUNIPER_VN 181
|
||||
#define WTAP_ENCAP_SOCKETCAN_HOSTENDIAN 182
|
||||
/* After adding new item here, please also add new item to encap_table_base array */
|
||||
|
||||
#define WTAP_NUM_ENCAP_TYPES wtap_get_num_encap_types()
|
||||
|
|
Loading…
Reference in New Issue