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. Signed-off-by: Oliver Hartkopp <socketcan@xxxxxxxxxxxx> --- include/uapi/linux/can/raw.h | 1 + net/can/raw.c | 27 ++++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/can/raw.h b/include/uapi/linux/can/raw.h index 3386aa81fdf2..ff12f525c37c 100644 --- a/include/uapi/linux/can/raw.h +++ b/include/uapi/linux/can/raw.h @@ -60,8 +60,9 @@ enum { CAN_RAW_ERR_FILTER, /* set filter for error frames */ CAN_RAW_LOOPBACK, /* local loopback (default:on) */ CAN_RAW_RECV_OWN_MSGS, /* receive my own msgs (default:off) */ CAN_RAW_FD_FRAMES, /* allow CAN FD frames (default:off) */ CAN_RAW_JOIN_FILTERS, /* all filters must match to trigger */ + CAN_RAW_XL_FRAMES, /* allow CAN XL frames (default:off) */ }; #endif /* !_UAPI_CAN_RAW_H */ diff --git a/net/can/raw.c b/net/can/raw.c index d1bd9cc51ebe..21f48190cdf9 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -85,10 +85,11 @@ struct raw_sock { int ifindex; struct list_head notifier; int loopback; int recv_own_msgs; int fd_frames; + int xl_frames; int join_filters; int count; /* number of active filters */ struct can_filter dfilter; /* default/single filter */ struct can_filter *filter; /* pointer to filter(s) */ can_err_mask_t err_mask; @@ -344,10 +345,11 @@ static int raw_init(struct sock *sk) /* set default loopback behaviour */ ro->loopback = 1; ro->recv_own_msgs = 0; ro->fd_frames = 0; + ro->xl_frames = 0; ro->join_filters = 0; /* alloc_percpu provides zero'ed memory */ ro->uniq = alloc_percpu(struct uniqframe); if (unlikely(!ro->uniq)) @@ -667,10 +669,19 @@ static int raw_setsockopt(struct socket *sock, int level, int optname, if (copy_from_sockptr(&ro->fd_frames, optval, optlen)) return -EFAULT; break; + case CAN_RAW_XL_FRAMES: + if (optlen != sizeof(ro->xl_frames)) + return -EINVAL; + + if (copy_from_sockptr(&ro->xl_frames, optval, optlen)) + return -EFAULT; + + break; + case CAN_RAW_JOIN_FILTERS: if (optlen != sizeof(ro->join_filters)) return -EINVAL; if (copy_from_sockptr(&ro->join_filters, optval, optlen)) @@ -749,10 +760,16 @@ static int raw_getsockopt(struct socket *sock, int level, int optname, if (len > sizeof(int)) len = sizeof(int); val = &ro->fd_frames; break; + case CAN_RAW_XL_FRAMES: + if (len > sizeof(int)) + len = sizeof(int); + val = &ro->xl_frames; + break; + case CAN_RAW_JOIN_FILTERS: if (len > sizeof(int)) len = sizeof(int); val = &ro->join_filters; break; @@ -795,14 +812,22 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) dev = dev_get_by_index(sock_net(sk), ifindex); if (!dev) return -ENXIO; err = -EINVAL; - if (ro->fd_frames && dev->mtu == CANFD_MTU) { + if (ro->xl_frames && dev->mtu == CANXL_MTU) { + /* CAN XL, CAN FD and Classical CAN */ + if (unlikely((size < CANXL_MINTU || size > CANXL_MTU) && + size != CANFD_MTU && + size != CAN_MTU)) + goto put_dev; + } else if (ro->fd_frames && dev->mtu == CANFD_MTU) { + /* CAN FD and Classical CAN */ if (unlikely(size != CANFD_MTU && size != CAN_MTU)) goto put_dev; } else { + /* Classical CAN */ if (unlikely(size != CAN_MTU)) goto put_dev; } skb = sock_alloc_send_skb(sk, size + sizeof(struct can_skb_priv), -- 2.30.2