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

can: raw: instantly reject unsupported CAN frames

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>

authored by

Oliver Hartkopp and committed by
Marc Kleine-Budde
1a620a72 816cf430

+46 -8
+46 -8
net/can/raw.c
··· 892 892 } 893 893 } 894 894 895 - static unsigned int raw_check_txframe(struct raw_sock *ro, struct sk_buff *skb, int mtu) 895 + static inline bool raw_dev_cc_enabled(struct net_device *dev, 896 + struct can_priv *priv) 896 897 { 897 - /* Classical CAN -> no checks for flags and device capabilities */ 898 - if (can_is_can_skb(skb)) 898 + /* The CANXL-only mode disables error-signalling on the CAN bus 899 + * which is needed to send CAN CC/FD frames 900 + */ 901 + if (priv) 902 + return !can_dev_in_xl_only_mode(priv); 903 + 904 + /* virtual CAN interfaces always support CAN CC */ 905 + return true; 906 + } 907 + 908 + static inline bool raw_dev_fd_enabled(struct net_device *dev, 909 + struct can_priv *priv) 910 + { 911 + /* check FD ctrlmode on real CAN interfaces */ 912 + if (priv) 913 + return (priv->ctrlmode & CAN_CTRLMODE_FD); 914 + 915 + /* check MTU for virtual CAN FD interfaces */ 916 + return (READ_ONCE(dev->mtu) >= CANFD_MTU); 917 + } 918 + 919 + static inline bool raw_dev_xl_enabled(struct net_device *dev, 920 + struct can_priv *priv) 921 + { 922 + /* check XL ctrlmode on real CAN interfaces */ 923 + if (priv) 924 + return (priv->ctrlmode & CAN_CTRLMODE_XL); 925 + 926 + /* check MTU for virtual CAN XL interfaces */ 927 + return can_is_canxl_dev_mtu(READ_ONCE(dev->mtu)); 928 + } 929 + 930 + static unsigned int raw_check_txframe(struct raw_sock *ro, struct sk_buff *skb, 931 + struct net_device *dev) 932 + { 933 + struct can_priv *priv = safe_candev_priv(dev); 934 + 935 + /* Classical CAN */ 936 + if (can_is_can_skb(skb) && raw_dev_cc_enabled(dev, priv)) 899 937 return CAN_MTU; 900 938 901 - /* CAN FD -> needs to be enabled and a CAN FD or CAN XL device */ 939 + /* CAN FD */ 902 940 if (ro->fd_frames && can_is_canfd_skb(skb) && 903 - (mtu == CANFD_MTU || can_is_canxl_dev_mtu(mtu))) 941 + raw_dev_fd_enabled(dev, priv)) 904 942 return CANFD_MTU; 905 943 906 - /* CAN XL -> needs to be enabled and a CAN XL device */ 944 + /* CAN XL */ 907 945 if (ro->xl_frames && can_is_canxl_skb(skb) && 908 - can_is_canxl_dev_mtu(mtu)) 946 + raw_dev_xl_enabled(dev, priv)) 909 947 return CANXL_MTU; 910 948 911 949 return 0; ··· 999 961 err = -EINVAL; 1000 962 1001 963 /* check for valid CAN (CC/FD/XL) frame content */ 1002 - txmtu = raw_check_txframe(ro, skb, READ_ONCE(dev->mtu)); 964 + txmtu = raw_check_txframe(ro, skb, dev); 1003 965 if (!txmtu) 1004 966 goto free_skb; 1005 967