summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorOliver Hartkopp <socketcan@hartkopp.net>2026-01-09 15:41:34 +0100
committerMarc Kleine-Budde <mkl@pengutronix.de>2026-01-15 09:52:04 +0100
commit166e87329ce6f1eaa3475ba2d14ed30e54727c0d (patch)
tree47c59a7ce1ed0ec85ce02bb732118c70922532b7 /drivers
parent4650ff58a1b9ee68b2d3a207047998dd42e939b2 (diff)
can: propagate CAN device capabilities via ml_priv
Commit 1a620a723853 ("can: raw: instantly reject unsupported CAN frames") caused a sequence of dependency and linker fixes. Instead of accessing CAN device internal data structures which caused the dependency problems this patch introduces capability information into 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. Fixes: 1a620a723853 ("can: raw: instantly reject unsupported CAN frames") Cc: Marc Kleine-Budde <mkl@pengutronix.de> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Vincent Mailhol <mailhol@kernel.org> Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net> Link: https://patch.msgid.link/20260109144135.8495-3-socketcan@hartkopp.net Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/can/dev/dev.c27
-rw-r--r--drivers/net/can/dev/netlink.c1
-rw-r--r--drivers/net/can/vcan.c15
-rw-r--r--drivers/net/can/vxcan.c15
4 files changed, 58 insertions, 0 deletions
diff --git a/drivers/net/can/dev/dev.c b/drivers/net/can/dev/dev.c
index 091f30e94c61..7ab9578f5b89 100644
--- a/drivers/net/can/dev/dev.c
+++ b/drivers/net/can/dev/dev.c
@@ -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;
}
diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c
index d6b0e686fb11..0498198a4696 100644
--- a/drivers/net/can/dev/netlink.c
+++ b/drivers/net/can/dev/netlink.c
@@ -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;
}
diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
index fdc662aea279..76e6b7b5c6a1 100644
--- a/drivers/net/can/vcan.c
+++ b/drivers/net/can/vcan.c
@@ -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)
diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c
index b2c19f8c5f8e..f14c6f02b662 100644
--- a/drivers/net/can/vxcan.c
+++ b/drivers/net/can/vxcan.c
@@ -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() */