Skip to content

Commit 4f027cb

Browse files
hartkoppmarckleinebudde
authored andcommitted
can: isotp: split tx timer into transmission and timeout
The timer for the transmission of isotp PDUs formerly had two functions: 1. send two consecutive frames with a given time gap 2. monitor the timeouts for flow control frames and the echo frames This led to larger txstate checks and potentially to a problem discovered by syzbot which enabled the panic_on_warn feature while testing. The former 'txtimer' function is split into 'txfrtimer' and 'txtimer' to handle the two above functionalities with separate timer callbacks. The two simplified timers now run in one-shot mode and make the state transitions (especially with isotp_rcv_echo) better understandable. Fixes: 8663378 ("can: isotp: fix tx state handling for echo tx processing") Reported-by: syzbot+5aed6c3aaba661f5b917@syzkaller.appspotmail.com Cc: stable@vger.kernel.org # >= v6.0 Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net> Link: https://lore.kernel.org/all/20230104145701.2422-1-socketcan@hartkopp.net Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
1 parent 823b2e4 commit 4f027cb

File tree

1 file changed

+29
-36
lines changed

1 file changed

+29
-36
lines changed

net/can/isotp.c

Lines changed: 29 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ struct isotp_sock {
140140
canid_t rxid;
141141
ktime_t tx_gap;
142142
ktime_t lastrxcf_tstamp;
143-
struct hrtimer rxtimer, txtimer;
143+
struct hrtimer rxtimer, txtimer, txfrtimer;
144144
struct can_isotp_options opt;
145145
struct can_isotp_fc_options rxfc, txfc;
146146
struct can_isotp_ll_options ll;
@@ -871,57 +871,47 @@ static void isotp_rcv_echo(struct sk_buff *skb, void *data)
871871
}
872872

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

877877
static enum hrtimer_restart isotp_tx_timer_handler(struct hrtimer *hrtimer)
878878
{
879879
struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
880880
txtimer);
881881
struct sock *sk = &so->sk;
882-
enum hrtimer_restart restart = HRTIMER_NORESTART;
883882

884-
switch (so->tx.state) {
885-
case ISOTP_SENDING:
883+
/* don't handle timeouts in IDLE state */
884+
if (so->tx.state == ISOTP_IDLE)
885+
return HRTIMER_NORESTART;
886886

887-
/* cfecho should be consumed by isotp_rcv_echo() here */
888-
if (!so->cfecho) {
889-
/* start timeout for unlikely lost echo skb */
890-
hrtimer_set_expires(&so->txtimer,
891-
ktime_add(ktime_get(),
892-
ktime_set(ISOTP_ECHO_TIMEOUT, 0)));
893-
restart = HRTIMER_RESTART;
887+
/* we did not get any flow control or echo frame in time */
894888

895-
/* push out the next consecutive frame */
896-
isotp_send_cframe(so);
897-
break;
898-
}
899-
900-
/* cfecho has not been cleared in isotp_rcv_echo() */
901-
pr_notice_once("can-isotp: cfecho %08X timeout\n", so->cfecho);
902-
fallthrough;
889+
/* report 'communication error on send' */
890+
sk->sk_err = ECOMM;
891+
if (!sock_flag(sk, SOCK_DEAD))
892+
sk_error_report(sk);
903893

904-
case ISOTP_WAIT_FC:
905-
case ISOTP_WAIT_FIRST_FC:
894+
/* reset tx state */
895+
so->tx.state = ISOTP_IDLE;
896+
wake_up_interruptible(&so->wait);
906897

907-
/* we did not get any flow control frame in time */
898+
return HRTIMER_NORESTART;
899+
}
908900

909-
/* report 'communication error on send' */
910-
sk->sk_err = ECOMM;
911-
if (!sock_flag(sk, SOCK_DEAD))
912-
sk_error_report(sk);
901+
static enum hrtimer_restart isotp_txfr_timer_handler(struct hrtimer *hrtimer)
902+
{
903+
struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
904+
txfrtimer);
913905

914-
/* reset tx state */
915-
so->tx.state = ISOTP_IDLE;
916-
wake_up_interruptible(&so->wait);
917-
break;
906+
/* start echo timeout handling and cover below protocol error */
907+
hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
908+
HRTIMER_MODE_REL_SOFT);
918909

919-
default:
920-
WARN_ONCE(1, "can-isotp: tx timer state %08X cfecho %08X\n",
921-
so->tx.state, so->cfecho);
922-
}
910+
/* cfecho should be consumed by isotp_rcv_echo() here */
911+
if (so->tx.state == ISOTP_SENDING && !so->cfecho)
912+
isotp_send_cframe(so);
923913

924-
return restart;
914+
return HRTIMER_NORESTART;
925915
}
926916

927917
static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
@@ -1198,6 +1188,7 @@ static int isotp_release(struct socket *sock)
11981188
}
11991189
}
12001190

1191+
hrtimer_cancel(&so->txfrtimer);
12011192
hrtimer_cancel(&so->txtimer);
12021193
hrtimer_cancel(&so->rxtimer);
12031194

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

16051598
init_waitqueue_head(&so->wait);
16061599
spin_lock_init(&so->rx_lock);

0 commit comments

Comments
 (0)