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

can: raw: add CAN XL support

Enable CAN_RAW sockets to read and write CAN XL frames analogue to the
CAN FD extension (new CAN_RAW_XL_FRAMES sockopt).

A CAN XL network interface is capable to handle Classical CAN, CAN FD and
CAN XL frames. When CAN_RAW_XL_FRAMES is enabled, the CAN_RAW socket checks
whether the addressed CAN network interface is capable to handle the
provided CAN frame.

In opposite to the fixed number of bytes for
- CAN frames (CAN_MTU = sizeof(struct can_frame))
- CAN FD frames (CANFD_MTU = sizeof(struct can_frame))
the number of bytes when reading/writing CAN XL frames depends on the
number of data bytes. For efficiency reasons the length of the struct
canxl_frame is truncated to the needed size for read/write operations.
This leads to a calculated size of CANXL_HDR_SIZE + canxl_frame::len which
is enforced on write() operations and guaranteed on read() operations.

NB: Valid length values are 1 .. 2048 (CANXL_MIN_DLEN .. CANXL_MAX_DLEN).

Acked-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://lore.kernel.org/all/20220912170725.120748-8-socketcan@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Oliver Hartkopp and committed by
Marc Kleine-Budde
62633269 ebf87fc7

+44 -12
+1
include/uapi/linux/can/raw.h
··· 62 62 CAN_RAW_RECV_OWN_MSGS, /* receive my own msgs (default:off) */ 63 63 CAN_RAW_FD_FRAMES, /* allow CAN FD frames (default:off) */ 64 64 CAN_RAW_JOIN_FILTERS, /* all filters must match to trigger */ 65 + CAN_RAW_XL_FRAMES, /* allow CAN XL frames (default:off) */ 65 66 }; 66 67 67 68 #endif /* !_UAPI_CAN_RAW_H */
+43 -12
net/can/raw.c
··· 50 50 #include <linux/skbuff.h> 51 51 #include <linux/can.h> 52 52 #include <linux/can/core.h> 53 + #include <linux/can/dev.h> /* for can_is_canxl_dev_mtu() */ 53 54 #include <linux/can/skb.h> 54 55 #include <linux/can/raw.h> 55 56 #include <net/sock.h> ··· 88 87 int loopback; 89 88 int recv_own_msgs; 90 89 int fd_frames; 90 + int xl_frames; 91 91 int join_filters; 92 92 int count; /* number of active filters */ 93 93 struct can_filter dfilter; /* default/single filter */ ··· 131 129 if (!ro->recv_own_msgs && oskb->sk == sk) 132 130 return; 133 131 134 - /* do not pass non-CAN2.0 frames to a legacy socket */ 135 - if (!ro->fd_frames && oskb->len != CAN_MTU) 132 + /* make sure to not pass oversized frames to the socket */ 133 + if ((can_is_canfd_skb(oskb) && !ro->fd_frames && !ro->xl_frames) || 134 + (can_is_canxl_skb(oskb) && !ro->xl_frames)) 136 135 return; 137 136 138 137 /* eliminate multiple filter matches for the same skb */ ··· 348 345 ro->loopback = 1; 349 346 ro->recv_own_msgs = 0; 350 347 ro->fd_frames = 0; 348 + ro->xl_frames = 0; 351 349 ro->join_filters = 0; 352 350 353 351 /* alloc_percpu provides zero'ed memory */ ··· 672 668 673 669 break; 674 670 671 + case CAN_RAW_XL_FRAMES: 672 + if (optlen != sizeof(ro->xl_frames)) 673 + return -EINVAL; 674 + 675 + if (copy_from_sockptr(&ro->xl_frames, optval, optlen)) 676 + return -EFAULT; 677 + 678 + break; 679 + 675 680 case CAN_RAW_JOIN_FILTERS: 676 681 if (optlen != sizeof(ro->join_filters)) 677 682 return -EINVAL; ··· 763 750 val = &ro->fd_frames; 764 751 break; 765 752 753 + case CAN_RAW_XL_FRAMES: 754 + if (len > sizeof(int)) 755 + len = sizeof(int); 756 + val = &ro->xl_frames; 757 + break; 758 + 766 759 case CAN_RAW_JOIN_FILTERS: 767 760 if (len > sizeof(int)) 768 761 len = sizeof(int); ··· 794 775 struct sk_buff *skb; 795 776 struct net_device *dev; 796 777 int ifindex; 797 - int err; 778 + int err = -EINVAL; 779 + 780 + /* check for valid CAN frame sizes */ 781 + if (size < CANXL_HDR_SIZE + CANXL_MIN_DLEN || size > CANXL_MTU) 782 + return -EINVAL; 798 783 799 784 if (msg->msg_name) { 800 785 DECLARE_SOCKADDR(struct sockaddr_can *, addr, msg->msg_name); ··· 818 795 if (!dev) 819 796 return -ENXIO; 820 797 821 - err = -EINVAL; 822 - if (ro->fd_frames && dev->mtu == CANFD_MTU) { 823 - if (unlikely(size != CANFD_MTU && size != CAN_MTU)) 824 - goto put_dev; 825 - } else { 826 - if (unlikely(size != CAN_MTU)) 827 - goto put_dev; 828 - } 829 - 830 798 skb = sock_alloc_send_skb(sk, size + sizeof(struct can_skb_priv), 831 799 msg->msg_flags & MSG_DONTWAIT, &err); 832 800 if (!skb) ··· 827 813 can_skb_prv(skb)->ifindex = dev->ifindex; 828 814 can_skb_prv(skb)->skbcnt = 0; 829 815 816 + /* fill the skb before testing for valid CAN frames */ 830 817 err = memcpy_from_msg(skb_put(skb, size), msg, size); 831 818 if (err < 0) 832 819 goto free_skb; 820 + 821 + err = -EINVAL; 822 + if (ro->xl_frames && can_is_canxl_dev_mtu(dev->mtu)) { 823 + /* CAN XL, CAN FD and Classical CAN */ 824 + if (!can_is_canxl_skb(skb) && !can_is_canfd_skb(skb) && 825 + !can_is_can_skb(skb)) 826 + goto free_skb; 827 + } else if (ro->fd_frames && dev->mtu == CANFD_MTU) { 828 + /* CAN FD and Classical CAN */ 829 + if (!can_is_canfd_skb(skb) && !can_is_can_skb(skb)) 830 + goto free_skb; 831 + } else { 832 + /* Classical CAN */ 833 + if (!can_is_can_skb(skb)) 834 + goto free_skb; 835 + } 833 836 834 837 sockcm_init(&sockc, sk); 835 838 if (msg->msg_controllen) {