mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
synced 2026-10-30 13:52:50 +01:00
Commitd4fb6514ff("can: use skb hash instead of private variable in headroom") moved the per-skb unique identifier used for raw_rcv() duplicate detection into skb->hash. With RPS enabled, get_rps_cpu() calls skb_get_hash() before the frame reaches the CAN subsystem. Since CAN skbs have no L3/L4 headers, the flow dissector assigns every CAN frame the same non-zero software hash. can_set_skb_uid() only generated a new identifier when skb->hash was 0, so it kept this constant hash. When the SLAB allocator later reused the same skb address, raw_rcv() mistook the next legitimate frame for a duplicate and dropped it. Fix this by storing the CAN UID in the CAN skb extension (struct can_skb_ext::can_skb_uid) instead of skb->hash, decoupling it from any hash the network stack may compute. can_set_skb_uid() keeps its "assign only if unset" behaviour, which preserves UIDs set before transmission (e.g. by isotp to identify echo frames) across the local loopback path. Frames whose extension is shared with another clone (e.g. via tc mirred or netem duplicate) are given a private extension copy before the UID is assigned, so that independently received skb clones from real CAN interfaces (can_skb_uid = 0) don't end up with the same UID. The limitation that tc mirred/netem skb duplicates might be dropped in raw_rcv for looped back isotp echo frame skbs is accepted. There is no valid use-case for tc mirred or netem together with isotp which is not capable to operate on different CAN interfaces simultaneously. For routing and modifying CAN frames together with isotp use can-gw. can-gw and vxcan additionally clear the UID of forwarded/duplicated frames so each newly routed frame gets its own unique identifier. Fixes:d4fb6514ff("can: use skb hash instead of private variable in headroom") Reported-by: Joerg Willmann <[email protected]> Closes: https://lore.kernel.org/linux-can/[email protected]/ Cc: [email protected] Tested-by: Oliver Hartkopp <[email protected]> Tested-by: Joerg Willmann <[email protected]> Signed-off-by: Oliver Hartkopp <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Marc Kleine-Budde <[email protected]>
66 lines
1.9 KiB
C
66 lines
1.9 KiB
C
/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
|
|
/*
|
|
* linux/can/core.h
|
|
*
|
|
* Prototypes and definitions for CAN protocol modules using the PF_CAN core
|
|
*
|
|
* Authors: Oliver Hartkopp <[email protected]>
|
|
* Urs Thuermann <[email protected]>
|
|
* Copyright (c) 2002-2017 Volkswagen Group Electronic Research
|
|
* All rights reserved.
|
|
*
|
|
*/
|
|
|
|
#ifndef _CAN_CORE_H
|
|
#define _CAN_CORE_H
|
|
|
|
#include <linux/can.h>
|
|
#include <linux/skbuff.h>
|
|
#include <linux/netdevice.h>
|
|
#include <net/can.h>
|
|
|
|
#define DNAME(dev) ((dev) ? (dev)->name : "any")
|
|
|
|
/**
|
|
* struct can_proto - CAN protocol structure
|
|
* @type: type argument in socket() syscall, e.g. SOCK_DGRAM.
|
|
* @protocol: protocol number in socket() syscall.
|
|
* @ops: pointer to struct proto_ops for sock->ops.
|
|
* @prot: pointer to struct proto structure.
|
|
*/
|
|
struct can_proto {
|
|
int type;
|
|
int protocol;
|
|
const struct proto_ops *ops;
|
|
struct proto *prot;
|
|
};
|
|
|
|
/* required_size
|
|
* macro to find the minimum size of a struct
|
|
* that includes a requested member
|
|
*/
|
|
#define CAN_REQUIRED_SIZE(struct_type, member) \
|
|
(offsetof(typeof(struct_type), member) + \
|
|
sizeof(((typeof(struct_type) *)(NULL))->member))
|
|
|
|
/* function prototypes for the CAN networklayer core (af_can.c) */
|
|
|
|
extern int can_proto_register(const struct can_proto *cp);
|
|
extern void can_proto_unregister(const struct can_proto *cp);
|
|
|
|
int can_rx_register(struct net *net, struct net_device *dev,
|
|
canid_t can_id, canid_t mask,
|
|
void (*func)(struct sk_buff *, void *),
|
|
void *data, char *ident, struct sock *sk);
|
|
|
|
extern void can_rx_unregister(struct net *net, struct net_device *dev,
|
|
canid_t can_id, canid_t mask,
|
|
void (*func)(struct sk_buff *, void *),
|
|
void *data);
|
|
|
|
extern int can_send(struct sk_buff *skb, int loop);
|
|
void can_set_skb_uid(struct can_skb_ext *csx);
|
|
void can_sock_destruct(struct sock *sk);
|
|
|
|
#endif /* !_CAN_CORE_H */
|