Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Oliver Hartkopp and committed by
Marc Kleine-Budde
166e8732 4650ff58

+83
+27
drivers/net/can/dev/dev.c
··· 375 375 } 376 376 } 377 377 378 + void can_set_cap_info(struct net_device *dev) 379 + { 380 + struct can_priv *priv = netdev_priv(dev); 381 + u32 can_cap; 382 + 383 + if (can_dev_in_xl_only_mode(priv)) { 384 + /* XL only mode => no CC/FD capability */ 385 + can_cap = CAN_CAP_XL; 386 + } else { 387 + /* mixed mode => CC + FD/XL capability */ 388 + can_cap = CAN_CAP_CC; 389 + 390 + if (priv->ctrlmode & CAN_CTRLMODE_FD) 391 + can_cap |= CAN_CAP_FD; 392 + 393 + if (priv->ctrlmode & CAN_CTRLMODE_XL) 394 + can_cap |= CAN_CAP_XL; 395 + } 396 + 397 + if (priv->ctrlmode & (CAN_CTRLMODE_LISTENONLY | 398 + CAN_CTRLMODE_RESTRICTED)) 399 + can_cap |= CAN_CAP_RO; 400 + 401 + can_set_cap(dev, can_cap); 402 + } 403 + 378 404 /* helper to define static CAN controller features at device creation time */ 379 405 int can_set_static_ctrlmode(struct net_device *dev, u32 static_mode) 380 406 { ··· 416 390 417 391 /* override MTU which was set by default in can_setup()? */ 418 392 can_set_default_mtu(dev); 393 + can_set_cap_info(dev); 419 394 420 395 return 0; 421 396 }
+1
drivers/net/can/dev/netlink.c
··· 377 377 } 378 378 379 379 can_set_default_mtu(dev); 380 + can_set_cap_info(dev); 380 381 381 382 return 0; 382 383 }
+15
drivers/net/can/vcan.c
··· 130 130 return NETDEV_TX_OK; 131 131 } 132 132 133 + static void vcan_set_cap_info(struct net_device *dev) 134 + { 135 + u32 can_cap = CAN_CAP_CC; 136 + 137 + if (dev->mtu > CAN_MTU) 138 + can_cap |= CAN_CAP_FD; 139 + 140 + if (dev->mtu >= CANXL_MIN_MTU) 141 + can_cap |= CAN_CAP_XL; 142 + 143 + can_set_cap(dev, can_cap); 144 + } 145 + 133 146 static int vcan_change_mtu(struct net_device *dev, int new_mtu) 134 147 { 135 148 /* Do not allow changing the MTU while running */ ··· 154 141 return -EINVAL; 155 142 156 143 WRITE_ONCE(dev->mtu, new_mtu); 144 + vcan_set_cap_info(dev); 157 145 return 0; 158 146 } 159 147 ··· 176 162 dev->tx_queue_len = 0; 177 163 dev->flags = IFF_NOARP; 178 164 can_set_ml_priv(dev, netdev_priv(dev)); 165 + vcan_set_cap_info(dev); 179 166 180 167 /* set flags according to driver capabilities */ 181 168 if (echo)
+15
drivers/net/can/vxcan.c
··· 125 125 return iflink; 126 126 } 127 127 128 + static void vxcan_set_cap_info(struct net_device *dev) 129 + { 130 + u32 can_cap = CAN_CAP_CC; 131 + 132 + if (dev->mtu > CAN_MTU) 133 + can_cap |= CAN_CAP_FD; 134 + 135 + if (dev->mtu >= CANXL_MIN_MTU) 136 + can_cap |= CAN_CAP_XL; 137 + 138 + can_set_cap(dev, can_cap); 139 + } 140 + 128 141 static int vxcan_change_mtu(struct net_device *dev, int new_mtu) 129 142 { 130 143 /* Do not allow changing the MTU while running */ ··· 149 136 return -EINVAL; 150 137 151 138 WRITE_ONCE(dev->mtu, new_mtu); 139 + vxcan_set_cap_info(dev); 152 140 return 0; 153 141 } 154 142 ··· 181 167 182 168 can_ml = netdev_priv(dev) + ALIGN(sizeof(struct vxcan_priv), NETDEV_ALIGN); 183 169 can_set_ml_priv(dev, can_ml); 170 + vxcan_set_cap_info(dev); 184 171 } 185 172 186 173 /* forward declaration for rtnl_create_link() */
+24
include/linux/can/can-ml.h
··· 46 46 #include <linux/list.h> 47 47 #include <linux/netdevice.h> 48 48 49 + /* exposed CAN device capabilities for network layer */ 50 + #define CAN_CAP_CC BIT(0) /* CAN CC aka Classical CAN */ 51 + #define CAN_CAP_FD BIT(1) /* CAN FD */ 52 + #define CAN_CAP_XL BIT(2) /* CAN XL */ 53 + #define CAN_CAP_RO BIT(3) /* read-only mode (LISTEN/RESTRICTED) */ 54 + 49 55 #define CAN_SFF_RCV_ARRAY_SZ (1 << CAN_SFF_ID_BITS) 50 56 #define CAN_EFF_RCV_HASH_BITS 10 51 57 #define CAN_EFF_RCV_ARRAY_SZ (1 << CAN_EFF_RCV_HASH_BITS) ··· 70 64 #ifdef CAN_J1939 71 65 struct j1939_priv *j1939_priv; 72 66 #endif 67 + u32 can_cap; 73 68 }; 74 69 75 70 static inline struct can_ml_priv *can_get_ml_priv(struct net_device *dev) ··· 82 75 struct can_ml_priv *ml_priv) 83 76 { 84 77 netdev_set_ml_priv(dev, ml_priv, ML_PRIV_CAN); 78 + } 79 + 80 + static inline bool can_cap_enabled(struct net_device *dev, u32 cap) 81 + { 82 + struct can_ml_priv *can_ml = can_get_ml_priv(dev); 83 + 84 + if (!can_ml) 85 + return false; 86 + 87 + return (can_ml->can_cap & cap); 88 + } 89 + 90 + static inline void can_set_cap(struct net_device *dev, u32 cap) 91 + { 92 + struct can_ml_priv *can_ml = can_get_ml_priv(dev); 93 + 94 + can_ml->can_cap = cap; 85 95 } 86 96 87 97 #endif /* CAN_ML_H */
+1
include/linux/can/dev.h
··· 116 116 int open_candev(struct net_device *dev); 117 117 void close_candev(struct net_device *dev); 118 118 void can_set_default_mtu(struct net_device *dev); 119 + void can_set_cap_info(struct net_device *dev); 119 120 int __must_check can_set_static_ctrlmode(struct net_device *dev, 120 121 u32 static_mode); 121 122 int can_hwtstamp_get(struct net_device *netdev,