Skip to content

Commit 2d51a5b

Browse files
Merge patch series "can: rework the CAN MTU logic (CAN XL preparation step 2/3)"
Vincent Mailhol <mailhol@kernel.org> says: The CAN MTU logic is currently broken. can_change_mtu() will update both the MTU and the CAN_CTRLMODE_FD flag. Back then, commit bc05a89 ("can: allow to change the device mtu for CAN FD capable devices") stated that: The configuration can be done either with the 'fd { on | off }' option in the 'ip' tool from iproute2 or by setting the CAN netdevice MTU to CAN_MTU (16) or to CANFD_MTU (72). Link: https://git.kernel.org/torvalds/c/bc05a8944a34 The problem is that after doing for example: $ ip link set can0 mtu 72 bittiming 500000 on a CAN FD interface, we are left with a device on which CAN FD is enabled but which does not have the FD databittiming parameters configured. The same goes on when setting the mtu back to 16: ip link set can0 type can bitrate 500000 fd on dbitrate 5000000 ip link set can0 mtu 16 The device is now in Classical CAN mode but iproute2 is still reporting the databittiming values (although this time, the issue seems less critical as it is only a reporting problem). The only way to resolve the problem and bring the device back to a coherent state is to call again the netlink interface using the "fd on" or "fd off" options. The idea of being able to infer the CAN_CTRLMODE_FD flag from the MTU value is just incorrect for physical devices. Note that this logic remains valid on virtual interfaces (vcan and vxcan) because those do not have control mode flags and thus no conflict occurs. This series reworks the CAN MTU logic. The goal is to always maintain a coherent state between the MTU and the control mode flags as listed in below table: fd off, xl off fd on, xl off fd any, xl on --------------------------------------------------------------------------- default mtu CAN_MTU CANFD_MTU CANXL_MTU min mtu CAN_MTU CANFD_MTU CANXL_MIN_MTU max mtu CAN_MTU CANFD_MTU CANXL_MAX_MTU In order to switch between one column to another, the user must use the fd/xl on/off flags. Directly modifying the MTU from one column to the other is not permitted any more. The CAN XL is not yet supported at the moment, so the last column is just given as a reference to better understand what is coming up. This series will just implement the first two columns. While doing the rewrite, the logic is adjusted to reuse as much as possible the net core infrastructure. By populating: net_device->min_mtu and net_device->max_mtu the net core infrastructure will automatically: 1. validate that the user's inputs are in range. 2. report those min and max MTU values through the netlink interface. Point 1. will allow us to get rid of the can_change_mtu() in a near future for all the physical devices and point 2. allows the end user to see the valid MTU range by doing a: $ ip --details link show can0 Finally, because using the net core, it will be possible after the removal of can_change_mtu() to modify the MTU while the device is up. As stated previously, the only modifications allowed will be within the MTU range of a given CAN protocol. So for Classical CAN and CAN FD, the MTU is fixed to, respectively, CAN_MTU and CANFD_MTU. For the upcoming CAN XL, the user will be able to change the MTU to anything between CANXL_MIN_MTU and CANXL_MAX_MTU even if the device is up. The first patch of this series annotates the read access on net_device->mtu. This preparation is needed to prevent any race condition to occur when modifying the MTU while the device is up. The second patch is another preparation change which moves can_set_static_ctrlmode() from dev.h to dev.c. The third patch populates the MTU minimum and maximum value. The fourth patch is just a clean-up to remove the old can_change_mtu(). The fourth and last patch comes as a bonus content and modifies the default MTU of the vcan and vxcan so that CAN XL is on by default. Note that after this series, the old can_change_mtu() becomes useless. That function can not yet be removed because some pending changes from other maintainers' trees still depend on it. It will be removed in the next development window once all those changes reach net-next. Link: https://patch.msgid.link/20250923-can-fix-mtu-v3-0-581bde113f52@kernel.org [mkl: squashed fixup patch into 3] Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2 parents c0b5952 + b98aceb commit 2d51a5b

File tree

8 files changed

+49
-31
lines changed

8 files changed

+49
-31
lines changed

drivers/net/can/dev/dev.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,8 @@ void can_setup(struct net_device *dev)
240240
{
241241
dev->type = ARPHRD_CAN;
242242
dev->mtu = CAN_MTU;
243+
dev->min_mtu = CAN_MTU;
244+
dev->max_mtu = CAN_MTU;
243245
dev->hard_header_len = 0;
244246
dev->addr_len = 0;
245247
dev->tx_queue_len = 10;
@@ -309,6 +311,21 @@ void free_candev(struct net_device *dev)
309311
}
310312
EXPORT_SYMBOL_GPL(free_candev);
311313

314+
void can_set_default_mtu(struct net_device *dev)
315+
{
316+
struct can_priv *priv = netdev_priv(dev);
317+
318+
if (priv->ctrlmode & CAN_CTRLMODE_FD) {
319+
dev->mtu = CANFD_MTU;
320+
dev->min_mtu = CANFD_MTU;
321+
dev->max_mtu = CANFD_MTU;
322+
} else {
323+
dev->mtu = CAN_MTU;
324+
dev->min_mtu = CAN_MTU;
325+
dev->max_mtu = CAN_MTU;
326+
}
327+
}
328+
312329
/* changing MTU and control mode for CAN/CANFD devices */
313330
int can_change_mtu(struct net_device *dev, int new_mtu)
314331
{
@@ -347,6 +364,26 @@ int can_change_mtu(struct net_device *dev, int new_mtu)
347364
}
348365
EXPORT_SYMBOL_GPL(can_change_mtu);
349366

367+
/* helper to define static CAN controller features at device creation time */
368+
int can_set_static_ctrlmode(struct net_device *dev, u32 static_mode)
369+
{
370+
struct can_priv *priv = netdev_priv(dev);
371+
372+
/* alloc_candev() succeeded => netdev_priv() is valid at this point */
373+
if (priv->ctrlmode_supported & static_mode) {
374+
netdev_warn(dev,
375+
"Controller features can not be supported and static at the same time\n");
376+
return -EINVAL;
377+
}
378+
priv->ctrlmode = static_mode;
379+
380+
/* override MTU which was set by default in can_setup()? */
381+
can_set_default_mtu(dev);
382+
383+
return 0;
384+
}
385+
EXPORT_SYMBOL_GPL(can_set_static_ctrlmode);
386+
350387
/* generic implementation of netdev_ops::ndo_eth_ioctl for CAN devices
351388
* supporting hardware timestamps
352389
*/

drivers/net/can/dev/netlink.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -223,17 +223,16 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
223223
priv->ctrlmode &= ~cm->mask;
224224
priv->ctrlmode |= maskedflags;
225225

226-
/* CAN_CTRLMODE_FD can only be set when driver supports FD */
227-
if (priv->ctrlmode & CAN_CTRLMODE_FD) {
228-
dev->mtu = CANFD_MTU;
229-
} else {
230-
dev->mtu = CAN_MTU;
226+
/* Wipe potential leftovers from previous CAN FD config */
227+
if (!(priv->ctrlmode & CAN_CTRLMODE_FD)) {
231228
memset(&priv->fd.data_bittiming, 0,
232229
sizeof(priv->fd.data_bittiming));
233230
priv->ctrlmode &= ~CAN_CTRLMODE_FD_TDC_MASK;
234231
memset(&priv->fd.tdc, 0, sizeof(priv->fd.tdc));
235232
}
236233

234+
can_set_default_mtu(dev);
235+
237236
fd_tdc_flag_provided = cm->mask & CAN_CTRLMODE_FD_TDC_MASK;
238237
/* CAN_CTRLMODE_TDC_{AUTO,MANUAL} are mutually
239238
* exclusive: make sure to turn the other one off

drivers/net/can/vcan.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ static const struct ethtool_ops vcan_ethtool_ops = {
156156
static void vcan_setup(struct net_device *dev)
157157
{
158158
dev->type = ARPHRD_CAN;
159-
dev->mtu = CANFD_MTU;
159+
dev->mtu = CANXL_MTU;
160160
dev->hard_header_len = 0;
161161
dev->addr_len = 0;
162162
dev->tx_queue_len = 0;

drivers/net/can/vxcan.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ static void vxcan_setup(struct net_device *dev)
156156
struct can_ml_priv *can_ml;
157157

158158
dev->type = ARPHRD_CAN;
159-
dev->mtu = CANFD_MTU;
159+
dev->mtu = CANXL_MTU;
160160
dev->hard_header_len = 0;
161161
dev->addr_len = 0;
162162
dev->tx_queue_len = 0;

include/linux/can/dev.h

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -125,27 +125,6 @@ static inline s32 can_get_relative_tdco(const struct can_priv *priv)
125125
return (s32)priv->fd.tdc.tdco - sample_point_in_tc;
126126
}
127127

128-
/* helper to define static CAN controller features at device creation time */
129-
static inline int __must_check can_set_static_ctrlmode(struct net_device *dev,
130-
u32 static_mode)
131-
{
132-
struct can_priv *priv = netdev_priv(dev);
133-
134-
/* alloc_candev() succeeded => netdev_priv() is valid at this point */
135-
if (priv->ctrlmode_supported & static_mode) {
136-
netdev_warn(dev,
137-
"Controller features can not be supported and static at the same time\n");
138-
return -EINVAL;
139-
}
140-
priv->ctrlmode = static_mode;
141-
142-
/* override MTU which was set by default in can_setup()? */
143-
if (static_mode & CAN_CTRLMODE_FD)
144-
dev->mtu = CANFD_MTU;
145-
146-
return 0;
147-
}
148-
149128
static inline u32 can_get_static_ctrlmode(struct can_priv *priv)
150129
{
151130
return priv->ctrlmode & ~priv->ctrlmode_supported;
@@ -187,7 +166,10 @@ struct can_priv *safe_candev_priv(struct net_device *dev);
187166

188167
int open_candev(struct net_device *dev);
189168
void close_candev(struct net_device *dev);
169+
void can_set_default_mtu(struct net_device *dev);
190170
int can_change_mtu(struct net_device *dev, int new_mtu);
171+
int __must_check can_set_static_ctrlmode(struct net_device *dev,
172+
u32 static_mode);
191173
int can_eth_ioctl_hwts(struct net_device *netdev, struct ifreq *ifr, int cmd);
192174
int can_ethtool_op_get_ts_info_hwts(struct net_device *dev,
193175
struct kernel_ethtool_ts_info *info);

net/can/af_can.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ int can_send(struct sk_buff *skb, int loop)
221221
}
222222

223223
/* Make sure the CAN frame can pass the selected CAN netdevice. */
224-
if (unlikely(skb->len > skb->dev->mtu)) {
224+
if (unlikely(skb->len > READ_ONCE(skb->dev->mtu))) {
225225
err = -EMSGSIZE;
226226
goto inval_skb;
227227
}

net/can/isotp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1313,7 +1313,7 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len)
13131313
err = -ENODEV;
13141314
goto out;
13151315
}
1316-
if (dev->mtu < so->ll.mtu) {
1316+
if (READ_ONCE(dev->mtu) < so->ll.mtu) {
13171317
dev_put(dev);
13181318
err = -EINVAL;
13191319
goto out;

net/can/raw.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -961,7 +961,7 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
961961
err = -EINVAL;
962962

963963
/* check for valid CAN (CC/FD/XL) frame content */
964-
txmtu = raw_check_txframe(ro, skb, dev->mtu);
964+
txmtu = raw_check_txframe(ro, skb, READ_ONCE(dev->mtu));
965965
if (!txmtu)
966966
goto free_skb;
967967

0 commit comments

Comments
 (0)