From patchwork Sun Apr 25 12:12:43 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Erik Flodin X-Patchwork-Id: 12223257 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.7 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,URIBL_BLOCKED,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 9307AC43461 for ; Sun, 25 Apr 2021 12:14:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6CDA4613AB for ; Sun, 25 Apr 2021 12:14:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230165AbhDYMP2 (ORCPT ); Sun, 25 Apr 2021 08:15:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41030 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229688AbhDYMP0 (ORCPT ); Sun, 25 Apr 2021 08:15:26 -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 472ECC06175F for ; Sun, 25 Apr 2021 05:14:46 -0700 (PDT) Received: by mail-lj1-x231.google.com with SMTP id m7so49972574ljp.10 for ; Sun, 25 Apr 2021 05:14:46 -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=EZczbmNzbCSUnmbjRkA/DgaLQQasLkMLjLYklXlMNMs=; b=dqWix/0qCKtWma3FxRe7Do1K/Fk6+95T0/H6ryYzLv5QZIF/USLJ3BdsY+a6+obU7s iynTZdfyY8UiGj1+++IvAOf0J+edm1qfOplV5yRPplLP0fVIEkrW8tGYXjOJNa52rvHj sAargBkxQeAwFQBLKttimBqju01aHfo8RDkSUj81Q6+R3PhpuLlJV9zU7Ays5JWhWCuY 6Lkz+WS3A70p9nKffe+hNvJ1BZ9r2DuHZhY2tWMuzlf+CK1FprJV13+/uPg9q/Grad8J Q/nX0WOsaxiVW8yZBgp3+2D+HZAXnfRpj9DuSz5UYde1qVJHhnhZ5Mg+17YZqyArAys6 aRgw== 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=EZczbmNzbCSUnmbjRkA/DgaLQQasLkMLjLYklXlMNMs=; b=YnOAzbN4OopKZ/8Bjq0CCTmUcDr6bXCdouicqWdGBB1DIg11oiBVQj8V8zeeB94XJC Dl+1gBWksjv+KV9iEKk7FMMzxZ5eBomBshXX5i5dxvBaB6R6t5Y0MHJIIsWjc9lLuUhW /HFfWqQyYJkdiOh6GFGJjXu+QkgcLw2olsWwz6uWDRWlqS6zZoDlaBTnnPs/cPMcs6Ij yC6GmvtyilJUgO9Soj8JSU2f8RfV4Tng5KDBimAH2ONYcSj37x7ljGgJOE2WgwXAsubC +1LZalEFostTvBld4gn55RdFk/6RK0LW5cK4kdbkAIPRpT0T7+mWfmRviEvA3fhKnRDe sBPA== X-Gm-Message-State: AOAM533+fK6klTgPJwlqYZPYTGvcAWJzudoMdFWpNALEDyzFFknTWf6d UwW6jFVr2Za/sksw+DyWjSX76w== X-Google-Smtp-Source: ABdhPJzVcZ3NdET2y/ymPeX+wbTxdJJW7biC/wM7kFuvDCLUWvVtZvOynfbMu8iJCW7uSqldkuRpRA== X-Received: by 2002:a05:651c:503:: with SMTP id o3mr9308454ljp.368.1619352884714; Sun, 25 Apr 2021 05:14:44 -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 w16sm1120049lfu.160.2021.04.25.05.14.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 25 Apr 2021 05:14:44 -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 1/2] can: add support for filtering own messages only Date: Sun, 25 Apr 2021 14:12:43 +0200 Message-Id: <20210425121244.217680-2-erik@flodin.me> X-Mailer: git-send-email 2.31.0 In-Reply-To: <20210425121244.217680-1-erik@flodin.me> References: <20210425121244.217680-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 | 9 ++++---- net/can/raw.c | 10 ++++---- 9 files changed, 57 insertions(+), 45 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 837bb8af0ec3..b7d234226fc2 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 0e5c37be4a2b..3d96a0f6b46c 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -727,7 +727,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; @@ -773,6 +774,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); @@ -1191,6 +1193,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); @@ -1200,7 +1203,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 */ @@ -1498,7 +1501,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 8598d9da0e5f..a8514a82ab56 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 3ef7f78e553b..a4dfbbf1614f 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); } } @@ -1322,7 +1322,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 bb914d8b4216..72bb158f1a59 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 5ea8695f507e..ad058a49a5d2 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); } } @@ -205,7 +206,7 @@ static void can_print_recv_banner(struct seq_file *m) * can1. 00000000 00000000 00000000 * ....... 0 tp20 */ - seq_puts(m, " device can_id can_mask function" + seq_puts(m, " device can_id can_mask own function" " userdata matches ident\n"); } diff --git a/net/can/raw.c b/net/can/raw.c index 6ec8aa1d0da4..1b6092a0914f 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -185,13 +185,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; } @@ -207,7 +207,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; } @@ -220,7 +220,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, @@ -231,7 +231,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 Sun Apr 25 12:12:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Erik Flodin X-Patchwork-Id: 12223259 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.7 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,URIBL_BLOCKED,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 53CCFC43470 for ; Sun, 25 Apr 2021 12:14:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 370B560FE3 for ; Sun, 25 Apr 2021 12:14:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230195AbhDYMP3 (ORCPT ); Sun, 25 Apr 2021 08:15:29 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41032 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230155AbhDYMP2 (ORCPT ); Sun, 25 Apr 2021 08:15:28 -0400 Received: from mail-lj1-x235.google.com (mail-lj1-x235.google.com [IPv6:2a00:1450:4864:20::235]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CC225C061574 for ; Sun, 25 Apr 2021 05:14:47 -0700 (PDT) Received: by mail-lj1-x235.google.com with SMTP id l22so53442947ljc.9 for ; Sun, 25 Apr 2021 05:14:47 -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=jf2xAu4iyXP92tkgTrL/Ng80d8omZjIG2kpXpSSVHUo=; b=RNe0QKD7TRzKtKHVS12G6H9WXd5wZ6/jdwbuxFp7VD+X7hbY+yTzk2Y4m1HBADmY3h SfCt468obJbIb5blr7MKWYq1zQ3VyW4/WvUTtHZvlS5QE9rVIBqh8i9aV4K6U3z4YG0v k8EUvJ6U8shfa7nbkDypsqYP3wDa2x45DZX5y/bBiUquwbn5Sgg2VHc8lTU9bJw7yoPU WzCXNA38lwWC0I/SrZqm1eRVn4yoRq2ERpSBZYecJJTMV1auVIq1zBElP6f4tAO2LG40 iBlEBXu9YiD2w8xNBf3WK3AjEP+VBIU25C9trNDiyybaFsc3aLWNOMS9rFohSsaSVqOD Rzog== 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=jf2xAu4iyXP92tkgTrL/Ng80d8omZjIG2kpXpSSVHUo=; b=pRvXg46A/RzUgXWrO8MhfvGbIXpd4xPBoDCugEStz46GnvjD+ifty/DU+ij/okMJSD G4tIvTD+4L9dWpgG085H1YEhrprAGvOm7StMpF7VqhmZ9bUDpMxyvJa6PtqCQkEnDVIU M48eazQ9MNDEeFTtEpPxNs6ZjWtJCRxDnNAz6x2R+WIW8O9ftEk01xXx5fw+9wCyA6wP irG3jfj/87tRiAWzlTWQP0AtNSdSNQG20LMH1ZEzOTY2s9nDPXYnJTZ93wNR9neJlKQa 5pg+1REbT2NsjG6kY53IuH42U9Mls5P5GJTBUtrB3PinG/yjTlJ8olsUWY4RnMJHraen H6Cw== X-Gm-Message-State: AOAM532wFH9xZai8qxxhPR7CUGvuB80iWB/Y3KeNOKRkZvNmVJ7S/r+7 W96t5WXM01ykAL8DqlHJ8M2nXQ== X-Google-Smtp-Source: ABdhPJwthRwCukbeRdgxY9KzpcT6/CF6QLIM9v4bkZdRA7xFk2iMAJunZbzicnyVhFwp1oZ3xSnG3A== X-Received: by 2002:a2e:a491:: with SMTP id h17mr6373152lji.236.1619352886342; Sun, 25 Apr 2021 05:14:46 -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 w16sm1120049lfu.160.2021.04.25.05.14.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 25 Apr 2021 05:14:46 -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 2/2] can: raw: add CAN_RAW_RECV_OWN_MSGS_ALL socket option Date: Sun, 25 Apr 2021 14:12:44 +0200 Message-Id: <20210425121244.217680-3-erik@flodin.me> X-Mailer: git-send-email 2.31.0 In-Reply-To: <20210425121244.217680-1-erik@flodin.me> References: <20210425121244.217680-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 f8dae662e454..86f5c4963d90 100644 --- a/Documentation/networking/can.rst +++ b/Documentation/networking/can.rst @@ -609,6 +609,13 @@ demand: &recv_own_msgs, sizeof(recv_own_msgs)); +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 1b6092a0914f..2f5461de5058 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -84,6 +84,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 */ @@ -120,7 +121,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 */ @@ -130,7 +131,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) @@ -143,8 +145,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 */ @@ -212,6 +216,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) @@ -234,6 +250,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) @@ -242,6 +265,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, @@ -251,13 +275,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; } @@ -321,10 +351,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); @@ -493,6 +524,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; @@ -637,6 +669,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; } @@ -708,6 +767,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; }