From: Oliver Hartkopp <socketcan@hartkopp.net>
To: yewentian395 <yewentian395@gmail.com>,
Marc Kleine-Budde <mkl@pengutronix.de>
Cc: linux-can@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH] qcan: isotp: implement N_Ar timeout handling for FC transmission
Date: Mon, 24 Aug 2026 20:03:19 +0200 [thread overview]
Message-ID: <eb5e9618-3dbf-42cb-a635-752ff9fbcb99@hartkopp.net> (raw)
In-Reply-To: <20260824125343.2700828-1-yewentian395@gmail.com>
On 24.08.26 14:53, yewentian395 wrote:
> Add N_Ar (ISO 15765-2) timeout logic to detect FC frame transmission
> failures on the receiver side. Previously, isotp_send_fc() fired the
> FC and immediately started the N_Cr timer (rxtimer) without confirming
> that the FC was actually transmitted onto the CAN bus.
>
> Introduce ISOTP_WAIT_FC_TX_CONFIRM state and fc_artimer to implement
> a two-phase approach:
>
> 1. N_Ar phase: after can_send(FC), wait for local echo confirmation
> 2. N_Cr phase: after echo arrives, start rxtimer to wait for next CF
The kernel ISO 15765-2 implementation uses a simplified approach for As
and Ar: You can specify the frame transmission time (N_As/N_Ar) in
can_isotp_options::frame_txtime which covers the calculated time of the
CAN frame on the bus (on the "wire"), e.g. for the tx path:
/* add transmission time for CAN frame N_As */
so->tx_gap = ktime_add_ns(so->tx_gap, so->frame_txtime);
In fact I don't know any active users of so->frame_txtime since the
Linux ISO 15765-2 implementation went online in April 2014. It only had
some value for testing.
Nobody cares about so->frame_txtime and therefore I will not add any
extra complexity to check for Ar/As timeouts which have no real world
effect.
> - /* start rx timeout watchdog */
> - hrtimer_start(&so->rxtimer, ktime_set(ISOTP_FC_TIMEOUT, 0),
> - HRTIMER_MODE_REL_SOFT);
Btw. while double-checking the code I have seen, that I was missing the
addition of so->frame_txtime when starting the rxtimer above.
Although this proves again that checking for Ar/As timeouts has no real
world effect, I will create a patch that adds so->frame_txtime here to
comply with the documentation in isotp.h:
__u32 frame_txtime; /* frame transmission time (N_As/N_Ar) */
/* __u32 value : time in nano secs */
I'll mention you with a Reported-by tag then.
> + if (flowstatus == ISOTP_FC_CTS) {
> + /* cancel rxtimer before entering N_Ar phase */
> + hrtimer_cancel(&so->rxtimer);
> +
> + /* enter N_Ar confirmation phase */
> + so->rx.state = ISOTP_WAIT_FC_TX_CONFIRM;
> + hrtimer_start(&so->fc_artimer,
> + ktime_set(ISOTP_FC_AR_TIMEOUT, 0),
> + HRTIMER_MODE_REL_SOFT);
> + }
> +
> + can_send_ret = can_send(nskb, 1);
> + if (can_send_ret) {
> + pr_notice_once("can-isotp: %s: can_send_ret %pe\n",
> + __func__, ERR_PTR(can_send_ret));
> + if (flowstatus == ISOTP_FC_CTS) {
> + hrtimer_cancel(&so->fc_artimer);
> + so->rx.state = ISOTP_IDLE;
> + so->rx.len = 0;
> + }
> + dev_put(dev);
> + return 1;
> + }
> +
> + dev_put(dev);
> return 0;
> }
>
> @@ -447,6 +483,9 @@ static int isotp_rcv_sf(struct sock *sk, struct canfd_frame *cf, int pcilen,
> struct isotp_sock *so = isotp_sk(sk);
> struct sk_buff *nskb;
>
> + if (so->rx.state == ISOTP_WAIT_FC_TX_CONFIRM)
> + hrtimer_cancel(&so->fc_artimer);
> +
> hrtimer_cancel(&so->rxtimer);
> so->rx.state = ISOTP_IDLE;
>
> @@ -481,6 +520,9 @@ static int isotp_rcv_ff(struct sock *sk, struct canfd_frame *cf, int ae)
> int off;
> int ff_pci_sz;
>
> + if (so->rx.state == ISOTP_WAIT_FC_TX_CONFIRM)
> + hrtimer_cancel(&so->fc_artimer);
> +
> hrtimer_cancel(&so->rxtimer);
> so->rx.state = ISOTP_IDLE;
>
> @@ -554,6 +596,13 @@ static int isotp_rcv_cf(struct sock *sk, struct canfd_frame *cf, int ae,
> struct sk_buff *nskb;
> int i;
>
> + if (so->rx.state == ISOTP_WAIT_FC_TX_CONFIRM) {
> + hrtimer_cancel(&so->fc_artimer);
> + so->rx.state = ISOTP_WAIT_DATA;
> + hrtimer_start(&so->rxtimer, ktime_set(ISOTP_FC_TIMEOUT, 0),
> + HRTIMER_MODE_REL_SOFT);
> + }
> +
> if (so->rx.state != ISOTP_WAIT_DATA)
> return 0;
>
> @@ -855,9 +904,22 @@ static void isotp_rcv_echo(struct sk_buff *skb, void *data)
> struct sock *sk = (struct sock *)data;
> struct isotp_sock *so = isotp_sk(sk);
> struct canfd_frame *cf = (struct canfd_frame *)skb->data;
> + int ae = (so->opt.flags & CAN_ISOTP_EXTEND_ADDR) ? 1 : 0;
>
> - /* only handle my own local echo CF/SF skb's (no FF!) */
> - if (skb->sk != sk || so->cfecho != *(u32 *)cf->data)
Please also note that your patch would not apply on the latest upstream
isotp code, which does not contain "*(u32 *)cf->data" anymore.
Best regards,
Oliver
> + if (skb->sk != sk)
> + return;
> +
> + /* FC echo handling: confirm FC was transmitted (N_Ar) */
> + if (so->rx.state == ISOTP_WAIT_FC_TX_CONFIRM &&
> + (cf->data[ae] & 0xF0) == N_PCI_FC) {
> + hrtimer_cancel(&so->fc_artimer);
> + so->rx.state = ISOTP_WAIT_DATA;
> + hrtimer_start(&so->rxtimer, ktime_set(ISOTP_FC_TIMEOUT, 0),
> + HRTIMER_MODE_REL_SOFT);
> + return;
> + }
> +
> + if (so->cfecho != *(u32 *)cf->data)
> return;
>
> /* cancel local echo timeout */
> @@ -1225,6 +1287,7 @@ static int isotp_release(struct socket *sock)
> hrtimer_cancel(&so->txfrtimer);
> hrtimer_cancel(&so->txtimer);
> hrtimer_cancel(&so->rxtimer);
> + hrtimer_cancel(&so->fc_artimer);
>
> so->ifindex = 0;
> so->bound = 0;
> @@ -1563,6 +1626,8 @@ static void isotp_notify(struct isotp_sock *so, unsigned long msg,
> isotp_rcv_echo, sk);
> }
>
> + hrtimer_cancel(&so->fc_artimer);
> + so->rx.state = ISOTP_IDLE;
> so->ifindex = 0;
> so->bound = 0;
> release_sock(sk);
> @@ -1639,6 +1704,8 @@ static int isotp_init(struct sock *sk)
> hrtimer_setup(&so->txtimer, isotp_tx_timer_handler, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
> hrtimer_setup(&so->txfrtimer, isotp_txfr_timer_handler, CLOCK_MONOTONIC,
> HRTIMER_MODE_REL_SOFT);
> + hrtimer_setup(&so->fc_artimer, isotp_fc_ar_timer_handler, CLOCK_MONOTONIC,
> + HRTIMER_MODE_REL_SOFT);
>
> init_waitqueue_head(&so->wait);
> spin_lock_init(&so->rx_lock);
next prev parent reply other threads:[~2026-08-24 18:06 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-24 12:53 yewentian395
2026-08-24 18:03 ` Oliver Hartkopp [this message]
2026-08-26 6:42 ` [PATCH] can: " yewentian395
2026-09-03 9:38 ` yewentian395
2026-09-03 10:09 ` Oliver Hartkopp
2026-09-07 3:05 ` yewentian395
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=eb5e9618-3dbf-42cb-a635-752ff9fbcb99@hartkopp.net \
--to=socketcan@hartkopp.net \
--cc=linux-can@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mkl@pengutronix.de \
--cc=yewentian395@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®