All of lore.kernel.org
 help / color / mirror / Atom feed
From: Erik Flodin <erik@flodin.me>
To: socketcan@hartkopp.net, mkl@pengutronix.de
Cc: davem@davemloft.net, kuba@kernel.org, corbet@lwn.net,
	linux-can@vger.kernel.org, netdev@vger.kernel.org,
	linux-doc@vger.kernel.org, Erik Flodin <erik@flodin.me>
Subject: [PATCH v2 2/2] can: raw: add CAN_RAW_RECV_OWN_MSGS_ALL socket option
Date: Tue,  4 May 2021 22:35:46 +0200	[thread overview]
Message-ID: <20210504203546.115734-3-erik@flodin.me> (raw)
In-Reply-To: <20210504203546.115734-1-erik@flodin.me>

CAN_RAW_RECV_OWN_MSGS_ALL works as CAN_RAW_RECV_OWN_MSGS with the
difference that all sent frames are received as no filtering is applied
on the socket's own frames in this case.

Signed-off-by: Erik Flodin <erik@flodin.me>
---
 Documentation/networking/can.rst |  7 +++
 include/uapi/linux/can/raw.h     | 18 ++++---
 net/can/raw.c                    | 91 +++++++++++++++++++++++++++-----
 3 files changed, 95 insertions(+), 21 deletions(-)

diff --git a/Documentation/networking/can.rst b/Documentation/networking/can.rst
index f34cb0e4460e..80c70357cd33 100644
--- a/Documentation/networking/can.rst
+++ b/Documentation/networking/can.rst
@@ -611,6 +611,13 @@ demand:
 Note that reception of a socket's own CAN frames are subject to the same
 filtering as other CAN frames (see :ref:`socketcan-rawfilter`).
 
+RAW socket option CAN_RAW_RECV_OWN_MSGS_ALL
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Identical to CAN_RAW_RECV_OWN_MSGS except that all sent messages are
+received. I.e. reception is not subject to filtering.
+
+
 .. _socketcan-rawfd:
 
 RAW Socket Option CAN_RAW_FD_FRAMES
diff --git a/include/uapi/linux/can/raw.h b/include/uapi/linux/can/raw.h
index 3386aa81fdf2..6e29b2b145e2 100644
--- a/include/uapi/linux/can/raw.h
+++ b/include/uapi/linux/can/raw.h
@@ -53,15 +53,17 @@ enum {
 	SCM_CAN_RAW_ERRQUEUE = 1,
 };
 
-/* for socket options affecting the socket (not the global system) */
-
+/* For socket options affecting the socket (not the global system).
+ * Options default to off unless noted otherwise.
+ */
 enum {
-	CAN_RAW_FILTER = 1,	/* set 0 .. n can_filter(s)          */
-	CAN_RAW_ERR_FILTER,	/* set filter for error frames       */
-	CAN_RAW_LOOPBACK,	/* local loopback (default:on)       */
-	CAN_RAW_RECV_OWN_MSGS,	/* receive my own msgs (default:off) */
-	CAN_RAW_FD_FRAMES,	/* allow CAN FD frames (default:off) */
-	CAN_RAW_JOIN_FILTERS,	/* all filters must match to trigger */
+	CAN_RAW_FILTER = 1,	   /* set 0 .. n can_filter(s)          */
+	CAN_RAW_ERR_FILTER,	   /* set filter for error frames       */
+	CAN_RAW_LOOPBACK,	   /* local loopback (default on)       */
+	CAN_RAW_RECV_OWN_MSGS,	   /* receive my own msgs w/ filtering  */
+	CAN_RAW_FD_FRAMES,	   /* allow CAN FD frames               */
+	CAN_RAW_JOIN_FILTERS,	   /* all filters must match to trigger */
+	CAN_RAW_RECV_OWN_MSGS_ALL, /* receive my own msgs w/o filtering */
 };
 
 #endif /* !_UAPI_CAN_RAW_H */
diff --git a/net/can/raw.c b/net/can/raw.c
index acfbae28d451..79c29942b0be 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -86,6 +86,7 @@ struct raw_sock {
 	struct notifier_block notifier;
 	int loopback;
 	int recv_own_msgs;
+	int recv_own_msgs_all;
 	int fd_frames;
 	int join_filters;
 	int count;                 /* number of active filters */
@@ -122,7 +123,7 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
 	unsigned int *pflags;
 
 	/* check the received tx sock reference */
-	if (!ro->recv_own_msgs && oskb->sk == sk)
+	if (!ro->recv_own_msgs && !ro->recv_own_msgs_all && oskb->sk == sk)
 		return;
 
 	/* do not pass non-CAN2.0 frames to a legacy socket */
@@ -132,7 +133,8 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
 	/* eliminate multiple filter matches for the same skb */
 	if (this_cpu_ptr(ro->uniq)->skb == oskb &&
 	    this_cpu_ptr(ro->uniq)->skbcnt == can_skb_prv(oskb)->skbcnt) {
-		if (ro->join_filters) {
+		if (ro->join_filters &&
+		    (!ro->recv_own_msgs_all || oskb->sk != sk)) {
 			this_cpu_inc(ro->uniq->join_rx_count);
 			/* drop frame until all enabled filters matched */
 			if (this_cpu_ptr(ro->uniq)->join_rx_count < ro->count)
@@ -145,8 +147,10 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
 		this_cpu_ptr(ro->uniq)->skbcnt = can_skb_prv(oskb)->skbcnt;
 		this_cpu_ptr(ro->uniq)->join_rx_count = 1;
 		/* drop first frame to check all enabled filters? */
-		if (ro->join_filters && ro->count > 1)
+		if (ro->join_filters && ro->count > 1 &&
+		    (!ro->recv_own_msgs_all || oskb->sk != sk)) {
 			return;
+		}
 	}
 
 	/* clone the given skb to be able to enqueue it into the rcv queue */
@@ -214,6 +218,18 @@ static int raw_enable_errfilter(struct net *net, struct net_device *dev,
 	return err;
 }
 
+static int raw_enable_ownfilter(struct net *net, struct net_device *dev,
+				struct sock *sk, bool recv_own_msgs_all)
+{
+	int err = 0;
+
+	if (recv_own_msgs_all)
+		err = can_rx_register(net, dev, 0, MASK_ALL, true, raw_rcv,
+				      sk, "raw", sk);
+
+	return err;
+}
+
 static void raw_disable_filters(struct net *net, struct net_device *dev,
 				struct sock *sk, struct can_filter *filter,
 				int count)
@@ -236,6 +252,13 @@ static inline void raw_disable_errfilter(struct net *net,
 				  false, raw_rcv, sk);
 }
 
+static void raw_disable_ownfilter(struct net *net, struct net_device *dev,
+				  struct sock *sk, bool recv_own_msgs_all)
+{
+	if (recv_own_msgs_all)
+		can_rx_unregister(net, dev, 0, MASK_ALL, true, raw_rcv, sk);
+}
+
 static inline void raw_disable_allfilters(struct net *net,
 					  struct net_device *dev,
 					  struct sock *sk)
@@ -244,6 +267,7 @@ static inline void raw_disable_allfilters(struct net *net,
 
 	raw_disable_filters(net, dev, sk, ro->filter, ro->count);
 	raw_disable_errfilter(net, dev, sk, ro->err_mask);
+	raw_disable_ownfilter(net, dev, sk, ro->recv_own_msgs_all);
 }
 
 static int raw_enable_allfilters(struct net *net, struct net_device *dev,
@@ -253,13 +277,19 @@ static int raw_enable_allfilters(struct net *net, struct net_device *dev,
 	int err;
 
 	err = raw_enable_filters(net, dev, sk, ro->filter, ro->count);
-	if (!err) {
-		err = raw_enable_errfilter(net, dev, sk, ro->err_mask);
-		if (err)
-			raw_disable_filters(net, dev, sk, ro->filter,
-					    ro->count);
-	}
+	if (err)
+		goto out;
+	err = raw_enable_errfilter(net, dev, sk, ro->err_mask);
+	if (err)
+		goto out_disable;
+	err = raw_enable_ownfilter(net, dev, sk, ro->recv_own_msgs_all);
+	if (!err)
+		goto out;
 
+	raw_disable_errfilter(net, dev, sk, ro->err_mask);
+out_disable:
+	raw_disable_filters(net, dev, sk, ro->filter, ro->count);
+out:
 	return err;
 }
 
@@ -323,10 +353,11 @@ static int raw_init(struct sock *sk)
 	ro->count            = 1;
 
 	/* set default loopback behaviour */
-	ro->loopback         = 1;
-	ro->recv_own_msgs    = 0;
-	ro->fd_frames        = 0;
-	ro->join_filters     = 0;
+	ro->loopback          = 1;
+	ro->recv_own_msgs     = 0;
+	ro->recv_own_msgs_all = 0;
+	ro->fd_frames         = 0;
+	ro->join_filters      = 0;
 
 	/* alloc_percpu provides zero'ed memory */
 	ro->uniq = alloc_percpu(struct uniqframe);
@@ -495,6 +526,7 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
 	can_err_mask_t err_mask = 0;
 	int count = 0;
 	int err = 0;
+	int old_val;
 
 	if (level != SOL_CAN_RAW)
 		return -EINVAL;
@@ -639,6 +671,33 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
 
 		break;
 
+	case CAN_RAW_RECV_OWN_MSGS_ALL:
+		if (optlen != sizeof(ro->recv_own_msgs_all))
+			return -EINVAL;
+
+		old_val = ro->recv_own_msgs_all;
+		if (copy_from_sockptr(&ro->recv_own_msgs_all, optval, optlen))
+			return -EFAULT;
+
+		lock_sock(sk);
+
+		if (ro->bound && ro->ifindex)
+			dev = dev_get_by_index(sock_net(sk), ro->ifindex);
+
+		if (ro->bound) {
+			if (old_val && !ro->recv_own_msgs_all)
+				raw_disable_ownfilter(sock_net(sk), dev, sk, true);
+			else if (!old_val && ro->recv_own_msgs_all)
+				err = raw_enable_ownfilter(sock_net(sk), dev, sk, true);
+		}
+
+		if (dev)
+			dev_put(dev);
+
+		release_sock(sk);
+
+		break;
+
 	default:
 		return -ENOPROTOOPT;
 	}
@@ -718,6 +777,12 @@ static int raw_getsockopt(struct socket *sock, int level, int optname,
 		val = &ro->join_filters;
 		break;
 
+	case CAN_RAW_RECV_OWN_MSGS_ALL:
+		if (len > sizeof(int))
+			len = sizeof(int);
+		val = &ro->recv_own_msgs_all;
+		break;
+
 	default:
 		return -ENOPROTOOPT;
 	}
-- 
2.31.1


      parent reply	other threads:[~2021-05-04 20:36 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-04 20:35 [PATCH v2 0/2] can: Add CAN_RAW_RECV_OWN_MSGS_ALL socket option Erik Flodin
2021-05-04 20:35 ` [PATCH v2 1/2] can: add support for filtering own messages only Erik Flodin
2021-05-05  6:58   ` Oliver Hartkopp
2021-05-05  8:37     ` Erik Flodin
2021-05-05  9:15       ` Oliver Hartkopp
2021-05-05 18:54         ` Erik Flodin
2021-05-06  5:26           ` Oliver Hartkopp
2021-05-09 11:28             ` Erik Flodin
2021-05-10 12:28               ` Oliver Hartkopp
2021-05-16 20:02                 ` Erik Flodin
2021-05-17  7:36                   ` Oliver Hartkopp
2021-05-17 18:09                     ` Erik Flodin
2021-05-04 20:35 ` Erik Flodin [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210504203546.115734-3-erik@flodin.me \
    --to=erik@flodin.me \
    --cc=corbet@lwn.net \
    --cc=davem@davemloft.net \
    --cc=kuba@kernel.org \
    --cc=linux-can@vger.kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=mkl@pengutronix.de \
    --cc=netdev@vger.kernel.org \
    --cc=socketcan@hartkopp.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.