Merge patch series "can: raw: better approach to instantly reject unsupported CAN frames"

Oliver Hartkopp <socketcan@hartkopp.net> says:

This series reverts commit 1a620a7238 ("can: raw: instantly reject
unsupported CAN frames").

and its follow-up fixes for the introduced dependency issues.

commit 1a620a7238 ("can: raw: instantly reject unsupported CAN frames")
commit cb2dc6d286 ("can: Kconfig: select CAN driver infrastructure by default")
commit 6abd4577bc ("can: fix build dependency")
commit 5a5aff6338 ("can: fix build dependency")

The reverted patch was accessing CAN device internal data structures
from the network layer because it needs to know about the CAN protocol
capabilities of the CAN devices.

This data access caused build problems between the CAN network and the
CAN driver layer which introduced unwanted Kconfig dependencies and fixes.

The patches 2 & 3 implement a better approach which makes use of the
CAN specific ml_priv data which is accessible from both sides.

With this change the CAN network layer can check the required features
and the decoupling of the driver layer and network layer is restored.

Link: https://patch.msgid.link/20260109144135.8495-1-socketcan@hartkopp.net
[mkl: give series a more descriptive name]
[mkl: properly format reverted patch commitish]
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
This commit is contained in:
Marc Kleine-Budde
2026-01-15 09:52:34 +01:00
10 changed files with 102 additions and 53 deletions

View File

@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
menuconfig CAN_DEV
bool "CAN Device Drivers"
tristate "CAN Device Drivers"
default y
depends on CAN
help
@@ -17,7 +17,10 @@ menuconfig CAN_DEV
virtual ones. If you own such devices or plan to use the virtual CAN
interfaces to develop applications, say Y here.
if CAN_DEV && CAN
To compile as a module, choose M here: the module will be called
can-dev.
if CAN_DEV
config CAN_VCAN
tristate "Virtual Local CAN Interface (vcan)"

View File

@@ -7,7 +7,7 @@ obj-$(CONFIG_CAN_VCAN) += vcan.o
obj-$(CONFIG_CAN_VXCAN) += vxcan.o
obj-$(CONFIG_CAN_SLCAN) += slcan/
obj-$(CONFIG_CAN_DEV) += dev/
obj-y += dev/
obj-y += esd/
obj-y += rcar/
obj-y += rockchip/

View File

@@ -1,8 +1,9 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_CAN) += can-dev.o
obj-$(CONFIG_CAN_DEV) += can-dev.o
can-dev-y += skb.o
can-dev-$(CONFIG_CAN_DEV) += skb.o
can-dev-$(CONFIG_CAN_CALC_BITTIMING) += calc_bittiming.o
can-dev-$(CONFIG_CAN_NETLINK) += bittiming.o
can-dev-$(CONFIG_CAN_NETLINK) += dev.o

View File

@@ -375,6 +375,32 @@ void can_set_default_mtu(struct net_device *dev)
}
}
void can_set_cap_info(struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
u32 can_cap;
if (can_dev_in_xl_only_mode(priv)) {
/* XL only mode => no CC/FD capability */
can_cap = CAN_CAP_XL;
} else {
/* mixed mode => CC + FD/XL capability */
can_cap = CAN_CAP_CC;
if (priv->ctrlmode & CAN_CTRLMODE_FD)
can_cap |= CAN_CAP_FD;
if (priv->ctrlmode & CAN_CTRLMODE_XL)
can_cap |= CAN_CAP_XL;
}
if (priv->ctrlmode & (CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_RESTRICTED))
can_cap |= CAN_CAP_RO;
can_set_cap(dev, can_cap);
}
/* helper to define static CAN controller features at device creation time */
int can_set_static_ctrlmode(struct net_device *dev, u32 static_mode)
{
@@ -390,6 +416,7 @@ int can_set_static_ctrlmode(struct net_device *dev, u32 static_mode)
/* override MTU which was set by default in can_setup()? */
can_set_default_mtu(dev);
can_set_cap_info(dev);
return 0;
}

View File

@@ -377,6 +377,7 @@ static int can_ctrlmode_changelink(struct net_device *dev,
}
can_set_default_mtu(dev);
can_set_cap_info(dev);
return 0;
}

View File

@@ -130,6 +130,19 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
static void vcan_set_cap_info(struct net_device *dev)
{
u32 can_cap = CAN_CAP_CC;
if (dev->mtu > CAN_MTU)
can_cap |= CAN_CAP_FD;
if (dev->mtu >= CANXL_MIN_MTU)
can_cap |= CAN_CAP_XL;
can_set_cap(dev, can_cap);
}
static int vcan_change_mtu(struct net_device *dev, int new_mtu)
{
/* Do not allow changing the MTU while running */
@@ -141,6 +154,7 @@ static int vcan_change_mtu(struct net_device *dev, int new_mtu)
return -EINVAL;
WRITE_ONCE(dev->mtu, new_mtu);
vcan_set_cap_info(dev);
return 0;
}
@@ -162,6 +176,7 @@ static void vcan_setup(struct net_device *dev)
dev->tx_queue_len = 0;
dev->flags = IFF_NOARP;
can_set_ml_priv(dev, netdev_priv(dev));
vcan_set_cap_info(dev);
/* set flags according to driver capabilities */
if (echo)

View File

@@ -125,6 +125,19 @@ static int vxcan_get_iflink(const struct net_device *dev)
return iflink;
}
static void vxcan_set_cap_info(struct net_device *dev)
{
u32 can_cap = CAN_CAP_CC;
if (dev->mtu > CAN_MTU)
can_cap |= CAN_CAP_FD;
if (dev->mtu >= CANXL_MIN_MTU)
can_cap |= CAN_CAP_XL;
can_set_cap(dev, can_cap);
}
static int vxcan_change_mtu(struct net_device *dev, int new_mtu)
{
/* Do not allow changing the MTU while running */
@@ -136,6 +149,7 @@ static int vxcan_change_mtu(struct net_device *dev, int new_mtu)
return -EINVAL;
WRITE_ONCE(dev->mtu, new_mtu);
vxcan_set_cap_info(dev);
return 0;
}
@@ -167,6 +181,7 @@ static void vxcan_setup(struct net_device *dev)
can_ml = netdev_priv(dev) + ALIGN(sizeof(struct vxcan_priv), NETDEV_ALIGN);
can_set_ml_priv(dev, can_ml);
vxcan_set_cap_info(dev);
}
/* forward declaration for rtnl_create_link() */

View File

@@ -46,6 +46,12 @@
#include <linux/list.h>
#include <linux/netdevice.h>
/* exposed CAN device capabilities for network layer */
#define CAN_CAP_CC BIT(0) /* CAN CC aka Classical CAN */
#define CAN_CAP_FD BIT(1) /* CAN FD */
#define CAN_CAP_XL BIT(2) /* CAN XL */
#define CAN_CAP_RO BIT(3) /* read-only mode (LISTEN/RESTRICTED) */
#define CAN_SFF_RCV_ARRAY_SZ (1 << CAN_SFF_ID_BITS)
#define CAN_EFF_RCV_HASH_BITS 10
#define CAN_EFF_RCV_ARRAY_SZ (1 << CAN_EFF_RCV_HASH_BITS)
@@ -64,6 +70,7 @@ struct can_ml_priv {
#ifdef CAN_J1939
struct j1939_priv *j1939_priv;
#endif
u32 can_cap;
};
static inline struct can_ml_priv *can_get_ml_priv(struct net_device *dev)
@@ -77,4 +84,21 @@ static inline void can_set_ml_priv(struct net_device *dev,
netdev_set_ml_priv(dev, ml_priv, ML_PRIV_CAN);
}
static inline bool can_cap_enabled(struct net_device *dev, u32 cap)
{
struct can_ml_priv *can_ml = can_get_ml_priv(dev);
if (!can_ml)
return false;
return (can_ml->can_cap & cap);
}
static inline void can_set_cap(struct net_device *dev, u32 cap)
{
struct can_ml_priv *can_ml = can_get_ml_priv(dev);
can_ml->can_cap = cap;
}
#endif /* CAN_ML_H */

View File

@@ -111,18 +111,12 @@ struct net_device *alloc_candev_mqs(int sizeof_priv, unsigned int echo_skb_max,
void free_candev(struct net_device *dev);
/* a candev safe wrapper around netdev_priv */
#if IS_ENABLED(CONFIG_CAN_NETLINK)
struct can_priv *safe_candev_priv(struct net_device *dev);
#else
static inline struct can_priv *safe_candev_priv(struct net_device *dev)
{
return NULL;
}
#endif
int open_candev(struct net_device *dev);
void close_candev(struct net_device *dev);
void can_set_default_mtu(struct net_device *dev);
void can_set_cap_info(struct net_device *dev);
int __must_check can_set_static_ctrlmode(struct net_device *dev,
u32 static_mode);
int can_hwtstamp_get(struct net_device *netdev,

View File

@@ -49,8 +49,8 @@
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <linux/can.h>
#include <linux/can/can-ml.h>
#include <linux/can/core.h>
#include <linux/can/dev.h> /* for can_is_canxl_dev_mtu() */
#include <linux/can/skb.h>
#include <linux/can/raw.h>
#include <net/sock.h>
@@ -892,58 +892,21 @@ static void raw_put_canxl_vcid(struct raw_sock *ro, struct sk_buff *skb)
}
}
static inline bool raw_dev_cc_enabled(struct net_device *dev,
struct can_priv *priv)
{
/* The CANXL-only mode disables error-signalling on the CAN bus
* which is needed to send CAN CC/FD frames
*/
if (priv)
return !can_dev_in_xl_only_mode(priv);
/* virtual CAN interfaces always support CAN CC */
return true;
}
static inline bool raw_dev_fd_enabled(struct net_device *dev,
struct can_priv *priv)
{
/* check FD ctrlmode on real CAN interfaces */
if (priv)
return (priv->ctrlmode & CAN_CTRLMODE_FD);
/* check MTU for virtual CAN FD interfaces */
return (READ_ONCE(dev->mtu) >= CANFD_MTU);
}
static inline bool raw_dev_xl_enabled(struct net_device *dev,
struct can_priv *priv)
{
/* check XL ctrlmode on real CAN interfaces */
if (priv)
return (priv->ctrlmode & CAN_CTRLMODE_XL);
/* check MTU for virtual CAN XL interfaces */
return can_is_canxl_dev_mtu(READ_ONCE(dev->mtu));
}
static unsigned int raw_check_txframe(struct raw_sock *ro, struct sk_buff *skb,
struct net_device *dev)
{
struct can_priv *priv = safe_candev_priv(dev);
/* Classical CAN */
if (can_is_can_skb(skb) && raw_dev_cc_enabled(dev, priv))
if (can_is_can_skb(skb) && can_cap_enabled(dev, CAN_CAP_CC))
return CAN_MTU;
/* CAN FD */
if (ro->fd_frames && can_is_canfd_skb(skb) &&
raw_dev_fd_enabled(dev, priv))
can_cap_enabled(dev, CAN_CAP_FD))
return CANFD_MTU;
/* CAN XL */
if (ro->xl_frames && can_is_canxl_skb(skb) &&
raw_dev_xl_enabled(dev, priv))
can_cap_enabled(dev, CAN_CAP_XL))
return CANXL_MTU;
return 0;
@@ -982,6 +945,12 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
if (!dev)
return -ENXIO;
/* no sending on a CAN device in read-only mode */
if (can_cap_enabled(dev, CAN_CAP_RO)) {
err = -EACCES;
goto put_dev;
}
skb = sock_alloc_send_skb(sk, size + sizeof(struct can_skb_priv),
msg->msg_flags & MSG_DONTWAIT, &err);
if (!skb)