Commit 1574481b authored by Oliver Hartkopp's avatar Oliver Hartkopp Committed by Marc Kleine-Budde
Browse files

vxcan: remove sk reference in peer skb

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@hartkopp.net


Signed-off-by: default avatarOliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent 9c0c191d
Loading
Loading
Loading
Loading
+11 −6
Original line number Original line Diff line number Diff line
@@ -33,28 +33,33 @@ struct vxcan_priv {
	struct net_device __rcu	*peer;
	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 vxcan_priv *priv = netdev_priv(dev);
	struct net_device *peer;
	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 net_device_stats *peerstats, *srcstats = &dev->stats;
	struct sk_buff *skb;
	u8 len;
	u8 len;


	if (can_dropped_invalid_skb(dev, skb))
	if (can_dropped_invalid_skb(dev, oskb))
		return NETDEV_TX_OK;
		return NETDEV_TX_OK;


	rcu_read_lock();
	rcu_read_lock();
	peer = rcu_dereference(priv->peer);
	peer = rcu_dereference(priv->peer);
	if (unlikely(!peer)) {
	if (unlikely(!peer)) {
		kfree_skb(skb);
		kfree_skb(oskb);
		dev->stats.tx_dropped++;
		dev->stats.tx_dropped++;
		goto out_unlock;
		goto out_unlock;
	}
	}


	skb = can_create_echo_skb(skb);
	skb = skb_clone(oskb, GFP_ATOMIC);
	if (!skb)
	if (skb) {
		consume_skb(oskb);
	} else {
		kfree(oskb);
		goto out_unlock;
		goto out_unlock;
	}


	/* reset CAN GW hop counter */
	/* reset CAN GW hop counter */
	skb->csum_start = 0;
	skb->csum_start = 0;