diff options
Diffstat (limited to 'net/can/raw.c')
| -rw-r--r-- | net/can/raw.c | 47 | 
1 files changed, 31 insertions, 16 deletions
| diff --git a/net/can/raw.c b/net/can/raw.c index 81071cdb0301..ba86782ba8bb 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -132,8 +132,8 @@ static void raw_rcv(struct sk_buff *oskb, void *data)  		return;  	/* make sure to not pass oversized frames to the socket */ -	if ((can_is_canfd_skb(oskb) && !ro->fd_frames && !ro->xl_frames) || -	    (can_is_canxl_skb(oskb) && !ro->xl_frames)) +	if ((!ro->fd_frames && can_is_canfd_skb(oskb)) || +	    (!ro->xl_frames && can_is_canxl_skb(oskb)))  		return;  	/* 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))  			return -EFAULT; +		/* Enabling CAN XL includes CAN FD */ +		if (ro->xl_frames && !ro->fd_frames) { +			ro->fd_frames = ro->xl_frames; +			return -EINVAL; +		}  		break;  	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))  			return -EFAULT; +		/* Enabling CAN XL includes CAN FD */ +		if (ro->xl_frames) +			ro->fd_frames = ro->xl_frames;  		break;  	case CAN_RAW_JOIN_FILTERS: @@ -786,6 +794,25 @@ static int raw_getsockopt(struct socket *sock, int level, int optname,  	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)  {  	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;  	err = -EINVAL; -	if (ro->xl_frames && can_is_canxl_dev_mtu(dev->mtu)) { -		/* CAN XL, CAN FD and Classical CAN */ -		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; -	} +	if (raw_bad_txframe(ro, skb, dev->mtu)) +		goto free_skb;  	sockcm_init(&sockc, sk);  	if (msg->msg_controllen) { |