linux-can-fixes-for-6.2-20230202
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEDs2BvajyNKlf9TJQvlAcSiqKBOgFAmPbg4YTHG1rbEBwZW5n dXRyb25peC5kZQAKCRC+UBxKKooE6AuHB/46pXdhKmIwJlyioOUM7L3TBOHN5WDR PqOo8l1VoiU2mjL934+QwrKd45WKyuzoMudaNzzzoB2hF+PTCzvoQS13n/iSEbxk DhEHrkVeBi7fuQObgcCyYXXDq/igiGawlPRtuIej9MUEtfzjO61BvMgo6HVaxNSi Q8uZxjDcUnkr3qBRQPPPgcdJmUbYzLUMoWg6lAlab5alHjFAuoQpYuiunEE+xFDU PN9gofkrdXDcy0aoFPPdLs1AIF7MlmGAFeh9DEkpBF4gHQVGulOW8yEcQFBLekNN hOz3chd2eTdDZvpIiIIHQursA25nWK0X9PqAarUENMz0jhG6WSJIyEDe =qIgG -----END PGP SIGNATURE----- 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: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
b0de13d307
@ -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;
|
||||
}
|
||||
|
@ -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,49 +879,39 @@ 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:
|
||||
/* don't handle timeouts in IDLE state */
|
||||
if (so->tx.state == ISOTP_IDLE)
|
||||
return HRTIMER_NORESTART;
|
||||
|
||||
/* 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;
|
||||
/* we did not get any flow control or echo frame in time */
|
||||
|
||||
/* push out the next consecutive frame */
|
||||
isotp_send_cframe(so);
|
||||
break;
|
||||
}
|
||||
/* report 'communication error on send' */
|
||||
sk->sk_err = ECOMM;
|
||||
if (!sock_flag(sk, SOCK_DEAD))
|
||||
sk_error_report(sk);
|
||||
|
||||
/* cfecho has not been cleared in isotp_rcv_echo() */
|
||||
pr_notice_once("can-isotp: cfecho %08X timeout\n", so->cfecho);
|
||||
fallthrough;
|
||||
/* reset tx state */
|
||||
so->tx.state = ISOTP_IDLE;
|
||||
wake_up_interruptible(&so->wait);
|
||||
|
||||
case ISOTP_WAIT_FC:
|
||||
case ISOTP_WAIT_FIRST_FC:
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
/* we did not get any flow control frame in time */
|
||||
static enum hrtimer_restart isotp_txfr_timer_handler(struct hrtimer *hrtimer)
|
||||
{
|
||||
struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
|
||||
txfrtimer);
|
||||
|
||||
/* report 'communication error on send' */
|
||||
sk->sk_err = ECOMM;
|
||||
if (!sock_flag(sk, SOCK_DEAD))
|
||||
sk_error_report(sk);
|
||||
/* start echo timeout handling and cover below protocol error */
|
||||
hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
|
||||
HRTIMER_MODE_REL_SOFT);
|
||||
|
||||
/* reset tx state */
|
||||
so->tx.state = ISOTP_IDLE;
|
||||
wake_up_interruptible(&so->wait);
|
||||
break;
|
||||
/* cfecho should be consumed by isotp_rcv_echo() here */
|
||||
if (so->tx.state == ISOTP_SENDING && !so->cfecho)
|
||||
isotp_send_cframe(so);
|
||||
|
||||
default:
|
||||
WARN_ONCE(1, "can-isotp: tx timer state %08X cfecho %08X\n",
|
||||
so->tx.state, so->cfecho);
|
||||
}
|
||||
|
||||
return restart;
|
||||
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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user