can: raw: fix CAN FD frame transmissions over CAN XL devices
A CAN XL device is always capable to process CAN FD frames. The former check when sending CAN FD frames relied on the existence of a CAN FD device and did not check for a CAN XL device that would be correct too. With this patch the CAN FD feature is enabled automatically when CAN XL is switched on - and CAN FD cannot be switch off while CAN XL is enabled. This precondition also leads to a clean up and reduction of checks in the hot path in raw_rcv() and raw_sendmsg(). Some conditions are reordered to handle simple checks first. changes since v1: https://lore.kernel.org/all/20230131091012.50553-1-socketcan@hartkopp.net - fixed typo: devive -> device changes since v2: https://lore.kernel.org/all/20230131091824.51026-1-socketcan@hartkopp.net/ - reorder checks in if statements to handle simple checks first Fixes: 626332696d75 ("can: raw: add CAN XL support") Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net> Link: https://lore.kernel.org/all/20230131105613.55228-1-socketcan@hartkopp.net Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
This commit is contained in:
parent
d0553680f9
commit
3793301cba
@ -132,8 +132,8 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/* make sure to not pass oversized frames to the socket */
|
/* make sure to not pass oversized frames to the socket */
|
||||||
if ((can_is_canfd_skb(oskb) && !ro->fd_frames && !ro->xl_frames) ||
|
if ((!ro->fd_frames && can_is_canfd_skb(oskb)) ||
|
||||||
(can_is_canxl_skb(oskb) && !ro->xl_frames))
|
(!ro->xl_frames && can_is_canxl_skb(oskb)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* eliminate multiple filter matches for the same skb */
|
/* eliminate multiple filter matches for the same skb */
|
||||||
@ -670,6 +670,11 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
|
|||||||
if (copy_from_sockptr(&ro->fd_frames, optval, optlen))
|
if (copy_from_sockptr(&ro->fd_frames, optval, optlen))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
|
/* Enabling CAN XL includes CAN FD */
|
||||||
|
if (ro->xl_frames && !ro->fd_frames) {
|
||||||
|
ro->fd_frames = ro->xl_frames;
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAN_RAW_XL_FRAMES:
|
case CAN_RAW_XL_FRAMES:
|
||||||
@ -679,6 +684,9 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
|
|||||||
if (copy_from_sockptr(&ro->xl_frames, optval, optlen))
|
if (copy_from_sockptr(&ro->xl_frames, optval, optlen))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
|
/* Enabling CAN XL includes CAN FD */
|
||||||
|
if (ro->xl_frames)
|
||||||
|
ro->fd_frames = ro->xl_frames;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAN_RAW_JOIN_FILTERS:
|
case CAN_RAW_JOIN_FILTERS:
|
||||||
@ -786,6 +794,25 @@ static int raw_getsockopt(struct socket *sock, int level, int optname,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool raw_bad_txframe(struct raw_sock *ro, struct sk_buff *skb, int mtu)
|
||||||
|
{
|
||||||
|
/* Classical CAN -> no checks for flags and device capabilities */
|
||||||
|
if (can_is_can_skb(skb))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* CAN FD -> needs to be enabled and a CAN FD or CAN XL device */
|
||||||
|
if (ro->fd_frames && can_is_canfd_skb(skb) &&
|
||||||
|
(mtu == CANFD_MTU || can_is_canxl_dev_mtu(mtu)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* CAN XL -> needs to be enabled and a CAN XL device */
|
||||||
|
if (ro->xl_frames && can_is_canxl_skb(skb) &&
|
||||||
|
can_is_canxl_dev_mtu(mtu))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
|
static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
|
||||||
{
|
{
|
||||||
struct sock *sk = sock->sk;
|
struct sock *sk = sock->sk;
|
||||||
@ -833,20 +860,8 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
|
|||||||
goto free_skb;
|
goto free_skb;
|
||||||
|
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
if (ro->xl_frames && can_is_canxl_dev_mtu(dev->mtu)) {
|
if (raw_bad_txframe(ro, skb, dev->mtu))
|
||||||
/* CAN XL, CAN FD and Classical CAN */
|
goto free_skb;
|
||||||
if (!can_is_canxl_skb(skb) && !can_is_canfd_skb(skb) &&
|
|
||||||
!can_is_can_skb(skb))
|
|
||||||
goto free_skb;
|
|
||||||
} else if (ro->fd_frames && dev->mtu == CANFD_MTU) {
|
|
||||||
/* CAN FD and Classical CAN */
|
|
||||||
if (!can_is_canfd_skb(skb) && !can_is_can_skb(skb))
|
|
||||||
goto free_skb;
|
|
||||||
} else {
|
|
||||||
/* Classical CAN */
|
|
||||||
if (!can_is_can_skb(skb))
|
|
||||||
goto free_skb;
|
|
||||||
}
|
|
||||||
|
|
||||||
sockcm_init(&sockc, sk);
|
sockcm_init(&sockc, sk);
|
||||||
if (msg->msg_controllen) {
|
if (msg->msg_controllen) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user