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@xxxxxxxxx> --- 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