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. Signed-off-by: Oliver Hartkopp <socketcan@xxxxxxxxxxxx> --- drivers/net/can/vxcan.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c index be5566168d0f..e5fd8b9bfca5 100644 --- a/drivers/net/can/vxcan.c +++ b/drivers/net/can/vxcan.c @@ -35,10 +35,11 @@ struct vxcan_priv { static netdev_tx_t vxcan_xmit(struct sk_buff *skb, struct net_device *dev) { struct vxcan_priv *priv = netdev_priv(dev); struct net_device *peer; + struct sk_buff *nskb; struct canfd_frame *cfd = (struct canfd_frame *)skb->data; struct net_device_stats *peerstats, *srcstats = &dev->stats; u8 len; if (can_dropped_invalid_skb(dev, skb)) @@ -50,22 +51,26 @@ static netdev_tx_t vxcan_xmit(struct sk_buff *skb, struct net_device *dev) kfree_skb(skb); dev->stats.tx_dropped++; goto out_unlock; } - skb = can_create_echo_skb(skb); - if (!skb) + nskb = skb_clone(skb, GFP_ATOMIC); + if (nskb) + consume_skb(skb); + else { + kfree_skb(skb); goto out_unlock; + } /* reset CAN GW hop counter */ - skb->csum_start = 0; - skb->pkt_type = PACKET_BROADCAST; - skb->dev = peer; - skb->ip_summed = CHECKSUM_UNNECESSARY; + nskb->csum_start = 0; + nskb->pkt_type = PACKET_BROADCAST; + nskb->dev = peer; + nskb->ip_summed = CHECKSUM_UNNECESSARY; len = cfd->len; - if (netif_rx_ni(skb) == NET_RX_SUCCESS) { + if (netif_rx_ni(nskb) == NET_RX_SUCCESS) { srcstats->tx_packets++; srcstats->tx_bytes += len; peerstats = &peer->stats; peerstats->rx_packets++; peerstats->rx_bytes += len; -- 2.30.2