Linux CAN drivers development
 help / color / mirror / Atom feed
From: Oliver Hartkopp <socketcan@hartkopp.net>
To: Vincent Mailhol <mailhol@kernel.org>
Cc: linux-can@vger.kernel.org
Subject: Re: [RFC PATCH v3 1/2] can: skb: enforce CANFD_FDF check in can_is_canfd_skb()
Date: Tue, 9 Sep 2025 10:35:45 +0200	[thread overview]
Message-ID: <7cbf8085-2df2-4a3e-8e20-73f588dad590@hartkopp.net> (raw)
In-Reply-To: <CAMZ6RqKiwmFzuFxxYvbLYr4-5AkDG7+W2zigqR8uvqSWv952JQ@mail.gmail.com>



On 09.09.25 08:25, Vincent Mailhol wrote:
> On Tue. 9 Sep. 2025 at 03:45, Oliver Hartkopp <socketcan@hartkopp.net> wrote:
>> The check in can_is_canfd_skb() is about a length check of skb->len and
>> the CAN FD data length. As a skb length of CANFD_MTU can potentially be
>> created with a CAN XL frame with a data length of 60, the length check of
>> the CAN FD data length is used to detect CAN XL frames via its CANXL_XLF
>> flag which exceeds valid CAN FD data length values.
>>
>> To make sure the CANFD_FDF flag can be safely used as a marker for CAN FD
>> frame skbs the bit was set in can_send() and is now also set in
>> raw_check_txframe() to re-use the indroduced can_is_canfd_skb_set_fdf()
>> function. In the RX path alloc_canfd_skb() sets the CANFD_FDF flag.
>>
>> The enforced CANFD_FDF check in can_is_canfd_skb() clears up the potential
>> uncertainty when using the skb->len check with the CANFD_MTU.
>>
>> Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
>> ---
>>   include/linux/can/skb.h | 25 +++++++++++++++++++++++--
>>   net/can/af_can.c        |  7 +------
>>   net/can/raw.c           |  2 +-
>>   3 files changed, 25 insertions(+), 9 deletions(-)
>>
>> diff --git a/include/linux/can/skb.h b/include/linux/can/skb.h
>> index 1abc25a8d144..38d036b43280 100644
>> --- a/include/linux/can/skb.h
>> +++ b/include/linux/can/skb.h
>> @@ -111,12 +111,33 @@ static inline bool can_is_can_skb(const struct sk_buff *skb)
>>
>>   static inline bool can_is_canfd_skb(const struct sk_buff *skb)
>>   {
>>          struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
>>
>> -       /* the CAN specific type of skb is identified by its data length */
>> -       return (skb->len == CANFD_MTU && cfd->len <= CANFD_MAX_DLEN);
>> +       if (skb->len != CANFD_MTU || cfd->len > CANFD_MAX_DLEN)
>> +               return false;
>> +
>> +       return cfd->flags & CANFD_FDF;
>> +}
>> +
>> +static inline bool can_is_canfd_skb_set_fdf(const struct sk_buff *skb)
>> +{
>> +       struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
>> +
>> +       /* The CAN specific type of skb is identified by its data length.
>> +        * A CAN XL frame skb might have a skb->len of CANFD_MTU but the
>> +        * skb would have the CANXL_XLF bit set (0x80 = 128) in the
>> +        * cfd->len field position which would intentionally break the
>> +        * CAN FD length check here. So we can surely tag it as CAN FD.
>> +        */
>> +       if (skb->len == CANFD_MTU && cfd->len <= CANFD_MAX_DLEN) {
>> +               /* set CAN FD flag for CAN FD frames by default */
>> +               cfd->flags |= CANFD_FDF;
>> +               return true;
>> +       }
>> +
>> +       return false;
>>   }
>>
>>   static inline bool can_is_canxl_skb(const struct sk_buff *skb)
>>   {
>>          const struct canxl_frame *cxl = (struct canxl_frame *)skb->data;
>> diff --git a/net/can/af_can.c b/net/can/af_can.c
>> index b2387a46794a..0caf75a9e27f 100644
>> --- a/net/can/af_can.c
>> +++ b/net/can/af_can.c
>> @@ -207,17 +207,12 @@ int can_send(struct sk_buff *skb, int loop)
>>
>>          if (can_is_canxl_skb(skb)) {
>>                  skb->protocol = htons(ETH_P_CANXL);
>>          } else if (can_is_can_skb(skb)) {
>>                  skb->protocol = htons(ETH_P_CAN);
>> -       } else if (can_is_canfd_skb(skb)) {
>> -               struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
>> -
>> +       } else if (can_is_canfd_skb_set_fdf(skb)) {
>>                  skb->protocol = htons(ETH_P_CANFD);
>> -
>> -               /* set CAN FD flag for CAN FD frames by default */
>> -               cfd->flags |= CANFD_FDF;
>>          } else {
>>                  goto inval_skb;
>>          }
>>
>>          /* Make sure the CAN frame can pass the selected CAN netdevice. */
>> diff --git a/net/can/raw.c b/net/can/raw.c
>> index 76b867d21def..f48b1f3fd6e8 100644
>> --- a/net/can/raw.c
>> +++ b/net/can/raw.c
>> @@ -886,11 +886,11 @@ static unsigned int raw_check_txframe(struct raw_sock *ro, struct sk_buff *skb,
> 
> With this change, raw_check_txframe() now has a side effect. It will
> set the CANFD_FDF under some conditions. This is weird for a function
> named "check". When I read the code, I expected a check function to
> not have such side effects.
> 
> I would suggest to set the flag in raw_sendmsg(), something like that:
> 
>           txmtu = raw_check_txframe(ro, skb, dev->mtu);
>           if (!txmtu)
>                   goto free_skb;
> 
> +        /* set CAN FD flag for CAN FD frames by default */
> +        if (txmtu == CANFD_MTU) {
> +                struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
> +
> +                cfd->flags |= CANFD_FDF;
> +        }
> +

Right. I've seen this remark to late for my v4.
Will propose a better solution.

Best regards,
Oliver

>           /* only CANXL: clear/forward/set VCID value */
>           if (txmtu == CANXL_MTU)
>                   raw_put_canxl_vcid(ro, skb);
> 
>>          /* Classical CAN -> no checks for flags and device capabilities */
>>          if (can_is_can_skb(skb))
>>                  return CAN_MTU;
>>
>>          /* CAN FD -> needs to be enabled and a CAN FD or CAN XL device */
>> -       if (ro->fd_frames && can_is_canfd_skb(skb) &&
>> +       if (ro->fd_frames && can_is_canfd_skb_set_fdf(skb) &&
>>              (mtu == CANFD_MTU || can_is_canxl_dev_mtu(mtu)))
>>                  return CANFD_MTU;
>>
>>          /* CAN XL -> needs to be enabled and a CAN XL device */
>>          if (ro->xl_frames && can_is_canxl_skb(skb) &&


      reply	other threads:[~2025-09-09  8:35 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-08 18:45 [RFC PATCH v3 1/2] can: skb: enforce CANFD_FDF check in can_is_canfd_skb() Oliver Hartkopp
2025-09-08 18:45 ` [RFC PATCH v3 2/2] can: support XL only content on real CAN XL interfaces Oliver Hartkopp
2025-09-09  6:31   ` Vincent Mailhol
2025-09-09  8:40     ` Oliver Hartkopp
2025-09-09  6:25 ` [RFC PATCH v3 1/2] can: skb: enforce CANFD_FDF check in can_is_canfd_skb() Vincent Mailhol
2025-09-09  8:35   ` Oliver Hartkopp [this message]

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=7cbf8085-2df2-4a3e-8e20-73f588dad590@hartkopp.net \
    --to=socketcan@hartkopp.net \
    --cc=linux-can@vger.kernel.org \
    --cc=mailhol@kernel.org \
    /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