From patchwork Tue May 4 20:35:45 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Erik Flodin X-Patchwork-Id: 12238555 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5AE1EC43460 for ; Tue, 4 May 2021 20:36:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 23F34613D2 for ; Tue, 4 May 2021 20:36:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232877AbhEDUhP (ORCPT ); Tue, 4 May 2021 16:37:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56016 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231445AbhEDUhN (ORCPT ); Tue, 4 May 2021 16:37:13 -0400 Received: from mail-lf1-x129.google.com (mail-lf1-x129.google.com [IPv6:2a00:1450:4864:20::129]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DD510C06138C for ; Tue, 4 May 2021 13:36:15 -0700 (PDT) Received: by mail-lf1-x129.google.com with SMTP id 124so15257953lff.5 for ; Tue, 04 May 2021 13:36:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=flodin-me.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=iMDuXq8CnWsxBoTteWoy8qTwu96FgJNObP1qaPnL9Fc=; b=ZvpLVLF6Bru8xoW0FnZJVcHEz5vB4KG8DmEn2S58qVvUNVonVz9SQFx25kCr8m4QHg 5mBSVKxjepRbG7l3PoZZiFbh5ADVAZ8eixyqG+P7YPDqviekEeE9tea/V/nt/v5mxSiI /8ifZNgs0m1YmAcQt5doYPmg6E8MlxrV/c52Y0S2yu66xzBcxHI3l1Drzfh0qp2p/djt 9+b4k1IlWYHdW4SBaPefci99pmpNkgsU+1LqWBzdN2v0A/QLo/AryRLM15wZMgRvPZns 8Yeis8L5JMkakfAawjmvCo5SSN+ulrR81h8GRWfS+IBWPQ+ED+/8IepI+SU2fGV0TTU9 IJHA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=iMDuXq8CnWsxBoTteWoy8qTwu96FgJNObP1qaPnL9Fc=; b=AJiM/Z87q+aioNrbOVvYlwWdgMJtYFwObbqUf0arNo90LYmktvQiiKS7+dN0q1lbgo PbVvFcE5Wdt+Mjw5vE/7OceDX727FmaRPuB1pBfTbfR1UfcUVlPi2Zv+IRR5bPhJIkQi oT91DdivnphgSgjoQBeA9XMPYKN4HcfoQf6FDIFUssupoUZSWLI3ad/a87LY7GNxaNxO OyC0dlTRMr2taD0rrv7fGA7M1WqLW/HfQoyRshjzP3+x+fLwTD/nQVbDd7Xw8WqUuY6f M7Lir91f248IgwEkT+NgDdYWF93EHeqx5W5MWYIRm3U4kMtIuyXAGJ1wBYEBtGEn4ozF pogA== X-Gm-Message-State: AOAM533pI41WHKVfUDysBGHMBikmQSF84IraeN50WYJTHfIGYtqvn0Md 3KTYELf7sXM9GUkj3UUp46UIGQ== X-Google-Smtp-Source: ABdhPJy4ppgpyuMkpW1U7TEBPlmF1b3rZpCWlNpGsxNvwVCjUIliXPEIE6KSdJDm888S2Fp+Ac4vUw== X-Received: by 2002:a05:6512:3f8c:: with SMTP id x12mr17822059lfa.622.1620160573491; Tue, 04 May 2021 13:36:13 -0700 (PDT) Received: from trillian.bjorktomta.lan (h-158-174-77-132.NA.cust.bahnhof.se. [158.174.77.132]) by smtp.gmail.com with ESMTPSA id v1sm1792222ljj.77.2021.05.04.13.36.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 May 2021 13:36:12 -0700 (PDT) From: Erik Flodin 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 Subject: [PATCH v2 1/2] can: add support for filtering own messages only Date: Tue, 4 May 2021 22:35:45 +0200 Message-Id: <20210504203546.115734-2-erik@flodin.me> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210504203546.115734-1-erik@flodin.me> References: <20210504203546.115734-1-erik@flodin.me> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org Add a new flag to can_rx_register/unregister that, when set, requires that the received sk_buff's owning socket matches the socket pointer given when setting the filter. This makes it possible to set a filter that matches all frames sent on a given socket and nothing else. Signed-off-by: Erik Flodin --- include/linux/can/core.h | 4 ++-- net/can/af_can.c | 50 ++++++++++++++++++++++------------------ net/can/af_can.h | 1 + net/can/bcm.c | 9 +++++--- net/can/gw.c | 7 +++--- net/can/isotp.c | 8 +++---- net/can/j1939/main.c | 4 ++-- net/can/proc.c | 11 +++++---- net/can/raw.c | 10 ++++---- 9 files changed, 58 insertions(+), 46 deletions(-) diff --git a/include/linux/can/core.h b/include/linux/can/core.h index 5fb8d0e3f9c1..7ee68128dc10 100644 --- a/include/linux/can/core.h +++ b/include/linux/can/core.h @@ -48,12 +48,12 @@ extern int can_proto_register(const struct can_proto *cp); extern void can_proto_unregister(const struct can_proto *cp); int can_rx_register(struct net *net, struct net_device *dev, - canid_t can_id, canid_t mask, + canid_t can_id, canid_t mask, bool match_sk, void (*func)(struct sk_buff *, void *), void *data, char *ident, struct sock *sk); extern void can_rx_unregister(struct net *net, struct net_device *dev, - canid_t can_id, canid_t mask, + canid_t can_id, canid_t mask, bool match_sk, void (*func)(struct sk_buff *, void *), void *data); diff --git a/net/can/af_can.c b/net/can/af_can.c index cce2af10eb3e..7b639c121653 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -414,6 +414,7 @@ static struct hlist_head *can_rcv_list_find(canid_t *can_id, canid_t *mask, * @dev: pointer to netdevice (NULL => subscribe from 'all' CAN devices list) * @can_id: CAN identifier (see description) * @mask: CAN mask (see description) + * @match_sk: match socket pointer on received sk_buff (see description) * @func: callback function on filter match * @data: returned parameter for callback function * @ident: string for calling module identification @@ -428,6 +429,9 @@ static struct hlist_head *can_rcv_list_find(canid_t *can_id, canid_t *mask, * The filter can be inverted (CAN_INV_FILTER bit set in can_id) or it can * filter for error message frames (CAN_ERR_FLAG bit set in mask). * + * If match_sk is true, the received sk_buff's owning socket must also match + * the given socket pointer. + * * The provided pointer to the sk_buff is guaranteed to be valid as long as * the callback function is running. The callback function must *not* free * the given sk_buff while processing it's task. When the given sk_buff is @@ -440,8 +444,9 @@ static struct hlist_head *can_rcv_list_find(canid_t *can_id, canid_t *mask, * -ENODEV unknown device */ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id, - canid_t mask, void (*func)(struct sk_buff *, void *), - void *data, char *ident, struct sock *sk) + canid_t mask, bool match_sk, + void (*func)(struct sk_buff *, void *), void *data, + char *ident, struct sock *sk) { struct receiver *rcv; struct hlist_head *rcv_list; @@ -468,6 +473,7 @@ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id, rcv->can_id = can_id; rcv->mask = mask; + rcv->match_sk = match_sk; rcv->matches = 0; rcv->func = func; rcv->data = data; @@ -503,6 +509,7 @@ static void can_rx_delete_receiver(struct rcu_head *rp) * @dev: pointer to netdevice (NULL => unsubscribe from 'all' CAN devices list) * @can_id: CAN identifier * @mask: CAN mask + * @match_sk: match socket pointer on received sk_buff * @func: callback function on filter match * @data: returned parameter for callback function * @@ -510,8 +517,8 @@ static void can_rx_delete_receiver(struct rcu_head *rp) * Removes subscription entry depending on given (subscription) values. */ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id, - canid_t mask, void (*func)(struct sk_buff *, void *), - void *data) + canid_t mask, bool match_sk, + void (*func)(struct sk_buff *, void *), void *data) { struct receiver *rcv = NULL; struct hlist_head *rcv_list; @@ -535,7 +542,8 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id, */ hlist_for_each_entry_rcu(rcv, rcv_list, list) { if (rcv->can_id == can_id && rcv->mask == mask && - rcv->func == func && rcv->data == data) + rcv->match_sk == match_sk && rcv->func == func && + rcv->data == data) break; } @@ -546,8 +554,8 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id, * a warning here. */ if (!rcv) { - pr_warn("can: receive list entry not found for dev %s, id %03X, mask %03X\n", - DNAME(dev), can_id, mask); + pr_warn("can: receive list entry not found for dev %s, id %03X, mask %03X%s\n", + DNAME(dev), can_id, mask, match_sk ? " (match sk)" : ""); goto out; } @@ -569,10 +577,14 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id, } EXPORT_SYMBOL(can_rx_unregister); -static inline void deliver(struct sk_buff *skb, struct receiver *rcv) +static inline int deliver(struct sk_buff *skb, struct receiver *rcv) { - rcv->func(skb, rcv->data); - rcv->matches++; + if (!rcv->match_sk || skb->sk == rcv->sk) { + rcv->func(skb, rcv->data); + rcv->matches++; + return 1; + } + return 0; } static int can_rcv_filter(struct can_dev_rcv_lists *dev_rcv_lists, struct sk_buff *skb) @@ -589,8 +601,7 @@ static int can_rcv_filter(struct can_dev_rcv_lists *dev_rcv_lists, struct sk_buf /* check for error message frame entries only */ hlist_for_each_entry_rcu(rcv, &dev_rcv_lists->rx[RX_ERR], list) { if (can_id & rcv->mask) { - deliver(skb, rcv); - matches++; + matches += deliver(skb, rcv); } } return matches; @@ -598,23 +609,20 @@ static int can_rcv_filter(struct can_dev_rcv_lists *dev_rcv_lists, struct sk_buf /* check for unfiltered entries */ hlist_for_each_entry_rcu(rcv, &dev_rcv_lists->rx[RX_ALL], list) { - deliver(skb, rcv); - matches++; + matches += deliver(skb, rcv); } /* check for can_id/mask entries */ hlist_for_each_entry_rcu(rcv, &dev_rcv_lists->rx[RX_FIL], list) { if ((can_id & rcv->mask) == rcv->can_id) { - deliver(skb, rcv); - matches++; + matches += deliver(skb, rcv); } } /* check for inverted can_id/mask entries */ hlist_for_each_entry_rcu(rcv, &dev_rcv_lists->rx[RX_INV], list) { if ((can_id & rcv->mask) != rcv->can_id) { - deliver(skb, rcv); - matches++; + matches += deliver(skb, rcv); } } @@ -625,15 +633,13 @@ static int can_rcv_filter(struct can_dev_rcv_lists *dev_rcv_lists, struct sk_buf if (can_id & CAN_EFF_FLAG) { hlist_for_each_entry_rcu(rcv, &dev_rcv_lists->rx_eff[effhash(can_id)], list) { if (rcv->can_id == can_id) { - deliver(skb, rcv); - matches++; + matches += deliver(skb, rcv); } } } else { can_id &= CAN_SFF_MASK; hlist_for_each_entry_rcu(rcv, &dev_rcv_lists->rx_sff[can_id], list) { - deliver(skb, rcv); - matches++; + matches += deliver(skb, rcv); } } diff --git a/net/can/af_can.h b/net/can/af_can.h index 7c2d9161e224..ea98b10d93e7 100644 --- a/net/can/af_can.h +++ b/net/can/af_can.h @@ -52,6 +52,7 @@ struct receiver { struct hlist_node list; canid_t can_id; canid_t mask; + bool match_sk; unsigned long matches; void (*func)(struct sk_buff *skb, void *data); void *data; diff --git a/net/can/bcm.c b/net/can/bcm.c index 909b9e684e04..d89dd82c2178 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -729,7 +729,8 @@ static void bcm_rx_unreg(struct net_device *dev, struct bcm_op *op) { if (op->rx_reg_dev == dev) { can_rx_unregister(dev_net(dev), dev, op->can_id, - REGMASK(op->can_id), bcm_rx_handler, op); + REGMASK(op->can_id), false, bcm_rx_handler, + op); /* mark as removed subscription */ op->rx_reg_dev = NULL; @@ -775,6 +776,7 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh, can_rx_unregister(sock_net(op->sk), NULL, op->can_id, REGMASK(op->can_id), + false, bcm_rx_handler, op); list_del(&op->list); @@ -1193,6 +1195,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, err = can_rx_register(sock_net(sk), dev, op->can_id, REGMASK(op->can_id), + false, bcm_rx_handler, op, "bcm", sk); @@ -1202,7 +1205,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, } else err = can_rx_register(sock_net(sk), NULL, op->can_id, - REGMASK(op->can_id), + REGMASK(op->can_id), false, bcm_rx_handler, op, "bcm", sk); if (err) { /* this bcm rx op is broken -> remove it */ @@ -1500,7 +1503,7 @@ static int bcm_release(struct socket *sock) } } else can_rx_unregister(net, NULL, op->can_id, - REGMASK(op->can_id), + REGMASK(op->can_id), false, bcm_rx_handler, op); bcm_remove_op(op); diff --git a/net/can/gw.c b/net/can/gw.c index ba4124805602..5dbc7b85e0fc 100644 --- a/net/can/gw.c +++ b/net/can/gw.c @@ -567,14 +567,15 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) static inline int cgw_register_filter(struct net *net, struct cgw_job *gwj) { return can_rx_register(net, gwj->src.dev, gwj->ccgw.filter.can_id, - gwj->ccgw.filter.can_mask, can_can_gw_rcv, - gwj, "gw", NULL); + gwj->ccgw.filter.can_mask, false, + can_can_gw_rcv, gwj, "gw", NULL); } static inline void cgw_unregister_filter(struct net *net, struct cgw_job *gwj) { can_rx_unregister(net, gwj->src.dev, gwj->ccgw.filter.can_id, - gwj->ccgw.filter.can_mask, can_can_gw_rcv, gwj); + gwj->ccgw.filter.can_mask, false, can_can_gw_rcv, + gwj); } static int cgw_notifier(struct notifier_block *nb, diff --git a/net/can/isotp.c b/net/can/isotp.c index 9f94ad3caee9..44d943bbe0b1 100644 --- a/net/can/isotp.c +++ b/net/can/isotp.c @@ -1029,7 +1029,7 @@ static int isotp_release(struct socket *sock) if (dev) { can_rx_unregister(net, dev, so->rxid, SINGLE_MASK(so->rxid), - isotp_rcv, sk); + false, isotp_rcv, sk); dev_put(dev); } } @@ -1111,7 +1111,7 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len) if (do_rx_reg) can_rx_register(net, dev, addr->can_addr.tp.rx_id, SINGLE_MASK(addr->can_addr.tp.rx_id), - isotp_rcv, sk, "isotp", sk); + false, isotp_rcv, sk, "isotp", sk); dev_put(dev); @@ -1122,7 +1122,7 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len) if (dev) { can_rx_unregister(net, dev, so->rxid, SINGLE_MASK(so->rxid), - isotp_rcv, sk); + false, isotp_rcv, sk); dev_put(dev); } } @@ -1323,7 +1323,7 @@ static int isotp_notifier(struct notifier_block *nb, unsigned long msg, if (so->bound && (!(so->opt.flags & CAN_ISOTP_SF_BROADCAST))) can_rx_unregister(dev_net(dev), dev, so->rxid, SINGLE_MASK(so->rxid), - isotp_rcv, sk); + false, isotp_rcv, sk); so->ifindex = 0; so->bound = 0; diff --git a/net/can/j1939/main.c b/net/can/j1939/main.c index da3a7a7bcff2..466a20c76fb6 100644 --- a/net/can/j1939/main.c +++ b/net/can/j1939/main.c @@ -177,7 +177,7 @@ static int j1939_can_rx_register(struct j1939_priv *priv) j1939_priv_get(priv); ret = can_rx_register(dev_net(ndev), ndev, J1939_CAN_ID, J1939_CAN_MASK, - j1939_can_recv, priv, "j1939", NULL); + false, j1939_can_recv, priv, "j1939", NULL); if (ret < 0) { j1939_priv_put(priv); return ret; @@ -191,7 +191,7 @@ static void j1939_can_rx_unregister(struct j1939_priv *priv) struct net_device *ndev = priv->ndev; can_rx_unregister(dev_net(ndev), ndev, J1939_CAN_ID, J1939_CAN_MASK, - j1939_can_recv, priv); + false, j1939_can_recv, priv); j1939_priv_put(priv); } diff --git a/net/can/proc.c b/net/can/proc.c index d1fe49e6f16d..d312077832a6 100644 --- a/net/can/proc.c +++ b/net/can/proc.c @@ -191,11 +191,12 @@ static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list, hlist_for_each_entry_rcu(r, rx_list, list) { char *fmt = (r->can_id & CAN_EFF_FLAG)? - " %-5s %08x %08x %pK %pK %8ld %s\n" : - " %-5s %03x %08x %pK %pK %8ld %s\n"; + " %-5s %08x %08x %c %pK %pK %8ld %s\n" : + " %-5s %03x %08x %c %pK %pK %8ld %s\n"; seq_printf(m, fmt, DNAME(dev), r->can_id, r->mask, - r->func, r->data, r->matches, r->ident); + r->match_sk ? '*' : ' ', r->func, r->data, + r->matches, r->ident); } } @@ -206,9 +207,9 @@ static void can_print_recv_banner(struct seq_file *m) * ....... 0 tp20 */ if (IS_ENABLED(CONFIG_64BIT)) - seq_puts(m, " device can_id can_mask function userdata matches ident\n"); + seq_puts(m, " device can_id can_mask own function userdata matches ident\n"); else - seq_puts(m, " device can_id can_mask function userdata matches ident\n"); + seq_puts(m, " device can_id can_mask own function userdata matches ident\n"); } static int can_stats_proc_show(struct seq_file *m, void *v) diff --git a/net/can/raw.c b/net/can/raw.c index 139d9471ddcf..acfbae28d451 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -187,13 +187,13 @@ static int raw_enable_filters(struct net *net, struct net_device *dev, for (i = 0; i < count; i++) { err = can_rx_register(net, dev, filter[i].can_id, - filter[i].can_mask, + filter[i].can_mask, false, raw_rcv, sk, "raw", sk); if (err) { /* clean up successfully registered filters */ while (--i >= 0) can_rx_unregister(net, dev, filter[i].can_id, - filter[i].can_mask, + filter[i].can_mask, false, raw_rcv, sk); break; } @@ -209,7 +209,7 @@ static int raw_enable_errfilter(struct net *net, struct net_device *dev, if (err_mask) err = can_rx_register(net, dev, 0, err_mask | CAN_ERR_FLAG, - raw_rcv, sk, "raw", sk); + false, raw_rcv, sk, "raw", sk); return err; } @@ -222,7 +222,7 @@ static void raw_disable_filters(struct net *net, struct net_device *dev, for (i = 0; i < count; i++) can_rx_unregister(net, dev, filter[i].can_id, - filter[i].can_mask, raw_rcv, sk); + filter[i].can_mask, false, raw_rcv, sk); } static inline void raw_disable_errfilter(struct net *net, @@ -233,7 +233,7 @@ static inline void raw_disable_errfilter(struct net *net, { if (err_mask) can_rx_unregister(net, dev, 0, err_mask | CAN_ERR_FLAG, - raw_rcv, sk); + false, raw_rcv, sk); } static inline void raw_disable_allfilters(struct net *net, From patchwork Tue May 4 20:35:46 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Erik Flodin X-Patchwork-Id: 12238557 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C2A51C433B4 for ; Tue, 4 May 2021 20:36:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8D86E613C5 for ; Tue, 4 May 2021 20:36:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232883AbhEDUhQ (ORCPT ); Tue, 4 May 2021 16:37:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56002 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231546AbhEDUhN (ORCPT ); Tue, 4 May 2021 16:37:13 -0400 Received: from mail-lj1-x231.google.com (mail-lj1-x231.google.com [IPv6:2a00:1450:4864:20::231]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C4B11C06174A for ; Tue, 4 May 2021 13:36:17 -0700 (PDT) Received: by mail-lj1-x231.google.com with SMTP id w4so4156908ljw.9 for ; Tue, 04 May 2021 13:36:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=flodin-me.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=oVZGRUnLTF2ujsME2GvskilHwBjffJIH9l/zY7blY+k=; b=lk6a1HUIdGsM/bQVsENvrSvdkW+3O7gTMZWK3Jnmj6/ULj3S1buH7yU5tfYKbsd3PL EiV8q/K1oYRmRDDxGnOzdMpMhe51rFQpOamWVUvFwvkX1LIGp4jpUD4ISiJ635QLzqfJ Vo1vgi/hDwn36ARlKK3tKQ9evGvDgKzuhDMiBsd12C3UX5Oq40mv9/qfTg7Tsbyu50nj EsX4PGMJu9oLzJz9ZGHJjsU92AKyJAleyZ54H+YgaEdZLwmoU7VwMBjGM9nijPnLHgj0 qGK0emtAOJx7pEkUXkHmKF/FU7TD1G/7GuxSB0oAC00Kf7iQfixjJWT2BomSx3/ZYuG0 q35Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=oVZGRUnLTF2ujsME2GvskilHwBjffJIH9l/zY7blY+k=; b=mUnIZSgE+sfadlAteCbz+EMhdHUkWVlK8VGr5Leqwu/d03TpN4M7MSmwSWfQFhdPMc aiYdvL14sJIHJWbWTjHxm/+BAum1cNlTrJIqbcdpSiEl/1pUtGfo7g1FGnIHOSsveGTE U9stZw263VRbZnu8PgmsiNa/IFVnrUuFAN8fjcYqtPWaT6WTen65+ZWuDpUhpNcTTtlc ySbAvJxlxh3OJ2ROFdGGss92xBYLVSgvw0APd2d6WeYUNeLxw3uv3dsDiPp4gVW+GQx+ bB6zW9JYoGC6P59eHmKD/JQ1ft7raj4yvZK/MWFhvcHOf/QY8y9DESlg4tuX5mUg6X9V 1mZQ== X-Gm-Message-State: AOAM533Bz/UJJpnBiAzIRyXmw7WRO3pAVTDC2Utz0Hnd/nyNwF+zmGA1 IoSikYvjDwR5vuEvmqI753hMUew/sPS86fRm X-Google-Smtp-Source: ABdhPJxUoJpdWIrynpc1QosXAoFSxzQgX0GUa9XVdBfz1+dnSK88qo2t9eZJJ3MaMdZAJvkU3vddxQ== X-Received: by 2002:a2e:a365:: with SMTP id i5mr10860264ljn.344.1620160576339; Tue, 04 May 2021 13:36:16 -0700 (PDT) Received: from trillian.bjorktomta.lan (h-158-174-77-132.NA.cust.bahnhof.se. [158.174.77.132]) by smtp.gmail.com with ESMTPSA id v1sm1792222ljj.77.2021.05.04.13.36.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 May 2021 13:36:15 -0700 (PDT) From: Erik Flodin 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 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 Message-Id: <20210504203546.115734-3-erik@flodin.me> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210504203546.115734-1-erik@flodin.me> References: <20210504203546.115734-1-erik@flodin.me> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org 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 --- 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; }