Commit b0de13d3 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge tag 'linux-can-fixes-for-6.2-20230202' of...

Merge tag 'linux-can-fixes-for-6.2-20230202' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can

Marc Kleine-Budde says:

====================
can 2023-02-02

The first patch is by Ziyang Xuan and removes a errant WARN_ON_ONCE()
in the CAN J1939 protocol.

The next 3 patches are by Oliver Hartkopp. The first 2 target the CAN
ISO-TP protocol and fix the state machine with respect to signals and
a regression found by the syzbot.

The last patch is by me an missing assignment during the ethtool ring
configuration callback.

* tag 'linux-can-fixes-for-6.2-20230202' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can:
  can: mcp251xfd: mcp251xfd_ring_set_ringparam(): assign missing tx_obj_num_coalesce_irq
  can: isotp: split tx timer into transmission and timeout
  can: isotp: handle wait_event_interruptible() return values
  can: raw: fix CAN FD frame transmissions over CAN XL devices
  can: j1939: fix errant WARN_ON_ONCE in j1939_session_deactivate
====================

Link: https://lore.kernel.org/r/20230202094135.2293939-1-mkl@pengutronix.de


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 4b6e135e 1613fff7
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ mcp251xfd_ring_set_ringparam(struct net_device *ndev,
	priv->rx_obj_num = layout.cur_rx;
	priv->rx_obj_num_coalesce_irq = layout.rx_coalesce;
	priv->tx->obj_num = layout.cur_tx;
	priv->tx_obj_num_coalesce_irq = layout.tx_coalesce;

	return 0;
}
+33 −36
Original line number Diff line number Diff line
@@ -140,7 +140,7 @@ struct isotp_sock {
	canid_t rxid;
	ktime_t tx_gap;
	ktime_t lastrxcf_tstamp;
	struct hrtimer rxtimer, txtimer;
	struct hrtimer rxtimer, txtimer, txfrtimer;
	struct can_isotp_options opt;
	struct can_isotp_fc_options rxfc, txfc;
	struct can_isotp_ll_options ll;
@@ -871,7 +871,7 @@ static void isotp_rcv_echo(struct sk_buff *skb, void *data)
	}

	/* start timer to send next consecutive frame with correct delay */
	hrtimer_start(&so->txtimer, so->tx_gap, HRTIMER_MODE_REL_SOFT);
	hrtimer_start(&so->txfrtimer, so->tx_gap, HRTIMER_MODE_REL_SOFT);
}

static enum hrtimer_restart isotp_tx_timer_handler(struct hrtimer *hrtimer)
@@ -879,32 +879,12 @@ static enum hrtimer_restart isotp_tx_timer_handler(struct hrtimer *hrtimer)
	struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
					     txtimer);
	struct sock *sk = &so->sk;
	enum hrtimer_restart restart = HRTIMER_NORESTART;

	switch (so->tx.state) {
	case ISOTP_SENDING:

		/* cfecho should be consumed by isotp_rcv_echo() here */
		if (!so->cfecho) {
			/* start timeout for unlikely lost echo skb */
			hrtimer_set_expires(&so->txtimer,
					    ktime_add(ktime_get(),
						      ktime_set(ISOTP_ECHO_TIMEOUT, 0)));
			restart = HRTIMER_RESTART;

			/* push out the next consecutive frame */
			isotp_send_cframe(so);
			break;
		}

		/* cfecho has not been cleared in isotp_rcv_echo() */
		pr_notice_once("can-isotp: cfecho %08X timeout\n", so->cfecho);
		fallthrough;

	case ISOTP_WAIT_FC:
	case ISOTP_WAIT_FIRST_FC:
	/* don't handle timeouts in IDLE state */
	if (so->tx.state == ISOTP_IDLE)
		return HRTIMER_NORESTART;

		/* we did not get any flow control frame in time */
	/* we did not get any flow control or echo frame in time */

	/* report 'communication error on send' */
	sk->sk_err = ECOMM;
@@ -914,14 +894,24 @@ static enum hrtimer_restart isotp_tx_timer_handler(struct hrtimer *hrtimer)
	/* reset tx state */
	so->tx.state = ISOTP_IDLE;
	wake_up_interruptible(&so->wait);
		break;

	default:
		WARN_ONCE(1, "can-isotp: tx timer state %08X cfecho %08X\n",
			  so->tx.state, so->cfecho);
	return HRTIMER_NORESTART;
}

	return restart;
static enum hrtimer_restart isotp_txfr_timer_handler(struct hrtimer *hrtimer)
{
	struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
					     txfrtimer);

	/* start echo timeout handling and cover below protocol error */
	hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
		      HRTIMER_MODE_REL_SOFT);

	/* cfecho should be consumed by isotp_rcv_echo() here */
	if (so->tx.state == ISOTP_SENDING && !so->cfecho)
		isotp_send_cframe(so);

	return HRTIMER_NORESTART;
}

static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
@@ -1162,6 +1152,10 @@ static int isotp_release(struct socket *sock)
	/* wait for complete transmission of current pdu */
	wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);

	/* force state machines to be idle also when a signal occurred */
	so->tx.state = ISOTP_IDLE;
	so->rx.state = ISOTP_IDLE;

	spin_lock(&isotp_notifier_lock);
	while (isotp_busy_notifier == so) {
		spin_unlock(&isotp_notifier_lock);
@@ -1194,6 +1188,7 @@ static int isotp_release(struct socket *sock)
		}
	}

	hrtimer_cancel(&so->txfrtimer);
	hrtimer_cancel(&so->txtimer);
	hrtimer_cancel(&so->rxtimer);

@@ -1597,6 +1592,8 @@ static int isotp_init(struct sock *sk)
	so->rxtimer.function = isotp_rx_timer_handler;
	hrtimer_init(&so->txtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
	so->txtimer.function = isotp_tx_timer_handler;
	hrtimer_init(&so->txfrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
	so->txfrtimer.function = isotp_txfr_timer_handler;

	init_waitqueue_head(&so->wait);
	spin_lock_init(&so->rx_lock);
+0 −4
Original line number Diff line number Diff line
@@ -1092,10 +1092,6 @@ static bool j1939_session_deactivate(struct j1939_session *session)
	bool active;

	j1939_session_list_lock(priv);
	/* This function should be called with a session ref-count of at
	 * least 2.
	 */
	WARN_ON_ONCE(kref_read(&session->kref) < 2);
	active = j1939_session_deactivate_locked(session);
	j1939_session_list_unlock(priv);

+31 −16
Original line number Diff line number Diff line
@@ -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))
	if (raw_bad_txframe(ro, skb, dev->mtu))
		goto free_skb;
	} else {
		/* Classical CAN */
		if (!can_is_can_skb(skb))
			goto free_skb;
	}

	sockcm_init(&sockc, sk);
	if (msg->msg_controllen) {