Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0ae89beb authored by Oliver Hartkopp's avatar Oliver Hartkopp Committed by David S. Miller
Browse files

can: add destructor for self generated skbs



Self generated skbuffs in net/can/bcm.c are setting a skb->sk reference but
no explicit destructor which is enforced since Linux 3.11 with commit
376c7311 (net: add a temporary sanity check in skb_orphan()).

This patch adds some helper functions to make sure that a destructor is
properly defined when a sock reference is assigned to a CAN related skb.
To create an unshared skb owned by the original sock a common helper function
has been introduced to replace open coded functions to create CAN echo skbs.

Signed-off-by: default avatarOliver Hartkopp <socketcan@hartkopp.net>
Tested-by: default avatarAndre Naujoks <nautsch2@gmail.com>
Reviewed-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 920a0fde
Loading
Loading
Loading
Loading
+3 −12
Original line number Diff line number Diff line
@@ -323,19 +323,10 @@ void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
	}

	if (!priv->echo_skb[idx]) {
		struct sock *srcsk = skb->sk;

		if (atomic_read(&skb->users) != 1) {
			struct sk_buff *old_skb = skb;

			skb = skb_clone(old_skb, GFP_ATOMIC);
			kfree_skb(old_skb);
		skb = can_create_echo_skb(skb);
		if (!skb)
			return;
		} else
			skb_orphan(skb);

		skb->sk = srcsk;

		/* make settings for echo to reduce code in irq context */
		skb->protocol = htons(ETH_P_CAN);
+4 −14
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/netdevice.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/skb.h>
#include <linux/can/error.h>

#include <linux/mfd/janz.h>
@@ -1133,20 +1134,9 @@ static void ican3_handle_message(struct ican3_dev *mod, struct ican3_msg *msg)
 */
static void ican3_put_echo_skb(struct ican3_dev *mod, struct sk_buff *skb)
{
	struct sock *srcsk = skb->sk;

	if (atomic_read(&skb->users) != 1) {
		struct sk_buff *old_skb = skb;

		skb = skb_clone(old_skb, GFP_ATOMIC);
		kfree_skb(old_skb);
	skb = can_create_echo_skb(skb);
	if (!skb)
		return;
	} else {
		skb_orphan(skb);
	}

	skb->sk = srcsk;

	/* save this skb for tx interrupt echo handling */
	skb_queue_tail(&mod->echoq, skb);
+4 −5
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@
#include <linux/if_ether.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/skb.h>
#include <linux/slab.h>
#include <net/rtnetlink.h>

@@ -109,25 +110,23 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
			stats->rx_packets++;
			stats->rx_bytes += cfd->len;
		}
		kfree_skb(skb);
		consume_skb(skb);
		return NETDEV_TX_OK;
	}

	/* perform standard echo handling for CAN network interfaces */

	if (loop) {
		struct sock *srcsk = skb->sk;

		skb = skb_share_check(skb, GFP_ATOMIC);
		skb = can_create_echo_skb(skb);
		if (!skb)
			return NETDEV_TX_OK;

		/* receive with packet counting */
		skb->sk = srcsk;
		vcan_rx(skb, dev);
	} else {
		/* no looped packets => no counting */
		kfree_skb(skb);
		consume_skb(skb);
	}
	return NETDEV_TX_OK;
}
+38 −0
Original line number Diff line number Diff line
@@ -11,7 +11,9 @@
#define CAN_SKB_H

#include <linux/types.h>
#include <linux/skbuff.h>
#include <linux/can.h>
#include <net/sock.h>

/*
 * The struct can_skb_priv is used to transport additional information along
@@ -42,4 +44,40 @@ static inline void can_skb_reserve(struct sk_buff *skb)
	skb_reserve(skb, sizeof(struct can_skb_priv));
}

static inline void can_skb_destructor(struct sk_buff *skb)
{
	sock_put(skb->sk);
}

static inline void can_skb_set_owner(struct sk_buff *skb, struct sock *sk)
{
	if (sk) {
		sock_hold(sk);
		skb->destructor = can_skb_destructor;
		skb->sk = sk;
	}
}

/*
 * returns an unshared skb owned by the original sock to be echo'ed back
 */
static inline struct sk_buff *can_create_echo_skb(struct sk_buff *skb)
{
	if (skb_shared(skb)) {
		struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);

		if (likely(nskb)) {
			can_skb_set_owner(nskb, skb->sk);
			consume_skb(skb);
			return nskb;
		} else {
			kfree_skb(skb);
			return NULL;
		}
	}

	/* we can assume to have an unshared skb with proper owner */
	return skb;
}

#endif /* CAN_SKB_H */
+2 −1
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@
#include <linux/skbuff.h>
#include <linux/can.h>
#include <linux/can/core.h>
#include <linux/can/skb.h>
#include <linux/ratelimit.h>
#include <net/net_namespace.h>
#include <net/sock.h>
@@ -290,7 +291,7 @@ int can_send(struct sk_buff *skb, int loop)
				return -ENOMEM;
			}

			newskb->sk = skb->sk;
			can_skb_set_owner(newskb, skb->sk);
			newskb->ip_summed = CHECKSUM_UNNECESSARY;
			newskb->pkt_type = PACKET_BROADCAST;
		}
Loading