]> Gentwo Git Trees - linux/.git/commitdiff
can: raw: instantly reject unsupported CAN frames
authorOliver Hartkopp <socketcan@hartkopp.net>
Wed, 26 Nov 2025 10:16:17 +0000 (11:16 +0100)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Wed, 26 Nov 2025 10:20:44 +0000 (11:20 +0100)
For real CAN interfaces the CAN_CTRLMODE_FD and CAN_CTRLMODE_XL control
modes indicate whether an interface can handle those CAN FD/XL frames.

In the case a CAN XL interface is configured in CANXL-only mode with
disabled error-signalling neither CAN CC nor CAN FD frames can be sent.

The checks are performed on CAN_RAW sockets to give an instant feedback
to the user when writing unsupported CAN frames to the interface.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20251126-canxl-v8-16-e7e3eb74f889@pengutronix.de
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
net/can/raw.c

index f36a83d3447cfd6d70364dbd49534507f059660e..be1ef7cf4204ecdc7aa0a943a3aab644e7e2c1dc 100644 (file)
@@ -892,20 +892,58 @@ static void raw_put_canxl_vcid(struct raw_sock *ro, struct sk_buff *skb)
        }
 }
 
-static unsigned int raw_check_txframe(struct raw_sock *ro, struct sk_buff *skb, int mtu)
+static inline bool raw_dev_cc_enabled(struct net_device *dev,
+                                     struct can_priv *priv)
 {
-       /* Classical CAN -> no checks for flags and device capabilities */
-       if (can_is_can_skb(skb))
+       /* 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))
                return CAN_MTU;
 
-       /* CAN FD -> needs to be enabled and a CAN FD or CAN XL device */
+       /* CAN FD */
        if (ro->fd_frames && can_is_canfd_skb(skb) &&
-           (mtu == CANFD_MTU || can_is_canxl_dev_mtu(mtu)))
+           raw_dev_fd_enabled(dev, priv))
                return CANFD_MTU;
 
-       /* CAN XL -> needs to be enabled and a CAN XL device */
+       /* CAN XL */
        if (ro->xl_frames && can_is_canxl_skb(skb) &&
-           can_is_canxl_dev_mtu(mtu))
+           raw_dev_xl_enabled(dev, priv))
                return CANXL_MTU;
 
        return 0;
@@ -961,7 +999,7 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
        err = -EINVAL;
 
        /* check for valid CAN (CC/FD/XL) frame content */
-       txmtu = raw_check_txframe(ro, skb, READ_ONCE(dev->mtu));
+       txmtu = raw_check_txframe(ro, skb, dev);
        if (!txmtu)
                goto free_skb;