From: Oliver Hartkopp <socketcan@xxxxxxxxxxxx> With can_create_echo_skb() the skb which is forwarded to the peer CAN interface shares the sk pointer from the originating socket. This makes the CAN frame show up in the peer namespace as a TX packet. With the use of skb_clone() analogue to the handling in gw.c the peer skb gets a new start in the peer namespace and correctly appears as a RX packet. Link: https://lore.kernel.org/all/20220309120416.83514-4-socketcan@xxxxxxxxxxxx Signed-off-by: Oliver Hartkopp <socketcan@xxxxxxxxxxxx> Signed-off-by: Marc Kleine-Budde <mkl@xxxxxxxxxxxxxx> --- drivers/net/can/vxcan.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c index 556f1a12ec9a..51501af8d9fc 100644 --- a/drivers/net/can/vxcan.c +++ b/drivers/net/can/vxcan.c @@ -33,28 +33,33 @@ struct vxcan_priv { struct net_device __rcu *peer; }; -static netdev_tx_t vxcan_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t vxcan_xmit(struct sk_buff *oskb, struct net_device *dev) { struct vxcan_priv *priv = netdev_priv(dev); struct net_device *peer; - struct canfd_frame *cfd = (struct canfd_frame *)skb->data; + struct canfd_frame *cfd = (struct canfd_frame *)oskb->data; struct net_device_stats *peerstats, *srcstats = &dev->stats; + struct sk_buff *skb; u8 len; - if (can_dropped_invalid_skb(dev, skb)) + if (can_dropped_invalid_skb(dev, oskb)) return NETDEV_TX_OK; rcu_read_lock(); peer = rcu_dereference(priv->peer); if (unlikely(!peer)) { - kfree_skb(skb); + kfree_skb(oskb); dev->stats.tx_dropped++; goto out_unlock; } - skb = can_create_echo_skb(skb); - if (!skb) + skb = skb_clone(oskb, GFP_ATOMIC); + if (skb) { + consume_skb(oskb); + } else { + kfree(oskb); goto out_unlock; + } /* reset CAN GW hop counter */ skb->csum_start = 0; -- 2.35.1