Skip to content

state_raw: add CAN FD support (< fdframe > / < fdsend >) - #79

Draft
floroks wants to merge 4 commits into
linux-can:masterfrom
mercedes-benz:canfd-raw
Draft

floroks wants to merge 4 commits into
linux-can:masterfrom
mercedes-benz:canfd-raw

Conversation

@floroks

@floroks floroks commented Oct 30, 2026 •

Copy link
Copy Markdown

This adds CAN FD support to the raw mode, as a reworked version of the approach proposed in #33 (same message syntax), split into reviewable steps as requested in #33 (comment).

Protocol

Classic CAN frames are unchanged. CAN FD frames use two new raw mode messages:

< fdframe can_id flags seconds.useconds [data]* >    (server -> client)
< fdsend can_id flags len [data]* >                  (client -> server)
  • flags: hex value of the canfd_frame.flags bits CANFD_BRS (0x01) and CANFD_ESI (0x02)
  • len: 0..64 data bytes; lengths that are not a valid CAN FD data length are zero-padded to the next valid length
  • can_id: as for < frame > / < send > (8 hex digits = extended identifier)

Example:

< fdsend 18DAF110 01 3 22 f1 90 >
< fdframe 18DAF110 01 23.424242 000A62F19031323334353637 >

Classic frames keep using < frame > / < send >, also on CAN FD interfaces. So existing clients are not affected: they never receive more than 8 data bytes. Like any other unknown message, they can ignore < fdframe >. Carrying the flags explicitly lets clients request bit rate switching and see BRS/ESI of received frames. In contrast, #72 reuses < frame > / < send > with up to 64 bytes and cannot transport the flags.

Commits

  1. state_raw: use struct canfd_frame: no functional change. Also fixes the signed/unsigned comparison of the recvmsg() result: an error (-1) used to pass the ret < sizeof(struct can_frame) check.
  2. state_raw: relay received CAN FD frames as < fdframe >: enables CAN_RAW_FD_FRAMES if the interface MTU is >= CANFD_MTU (CAN FD and CAN XL capable interfaces). Classic interfaces are unchanged.
  3. state_raw: add < fdsend > command for CAN FD frames: validates flags, length, data and identifier range. Rejected (with an error log) if the bus does not support CAN FD.
  4. doc: document CAN FD frames in raw mode

Out of scope for this PR: BCM mode and socketcandcl. Both can follow separately if the raw mode protocol is accepted.

Testing

Ubuntu 24.04 (WSL2, kernel 6.18), built with gcc 13 and clang 18 using -Dlibconfig=true -Dlibsocketcan=true as in CI. No new warnings; the existing clang warnings in state_bcm.c are unchanged.

Functional tests with a scripted socketcand client and can-utils:

  • vcan with mtu 72:
    • < fdsend > checked with candump: BRS/ESI flags, standard and extended identifiers, 64 bytes, zero padding 10 -> 12 bytes
    • < send > still sends classic frames
    • invalid < fdsend > commands put nothing on the bus and do not stop the server: reserved flag bit, too few/too many data bytes, len > 64, identifier out of range, missing len
    • cansend FD frames (with/without BRS, with ESI, 64 bytes) are relayed as < fdframe >; classic and empty frames as < frame >
  • vcan with default MTU (CAN XL, 2060): CAN FD is enabled
  • vcan with mtu 16: < fdsend > is rejected with "CAN FD is not supported by bus ..."; < send > and < frame > work as before

End-to-end ISO-TP over CAN FD:

  • client side: a userspace ISO-TP client (tokio-socketcan-isotp) talking to socketcand in raw mode
  • ECU side: a kernel CAN_ISOTP socket on the same vcan (CAN FD link layer, tx_dl 64, BRS)
  • exchanged payloads of 2, 20 (single frame with SF_DL escape), 367, 5003 (32-bit FF_DL) and 63/64 bytes; all byte-identical
  • all 100 frames on the bus were CAN FD with BRS

Declaration:

The program was tested solely for our own use cases, which might differ from yours.

Florian Roks <florian.roks@mercedes-benz.com>, Mercedes-Benz Tech Innovation GmbH
Provider Information

Licensed under GPL-2.0-only or BSD-3-Clause licenses (same as project)

Prepare the raw mode for CAN FD by using struct canfd_frame as the frame buffer. For classic CAN frames the layout is identical (can_dlc and len share the same position), so there is no functional change: only CAN_MTU sized frames are read and written as long as CAN FD frames are not enabled on the socket.

Clear the frame before parsing a send command, as the buffer is shared with the receive path, and check the recvmsg() return value for the exact MTU sizes. This also fixes the signed/unsigned comparison which let a failing recvmsg() (-1) pass the old 'ret < sizeof(struct can_frame)' check.

Signed-off-by: Florian Roks <florian.roks@mercedes-benz.com>
Enable CAN_RAW_FD_FRAMES on the raw socket if the CAN interface supports CAN FD (MTU >= CANFD_MTU), so that CAN FD frames on the bus are received instead of being dropped. Classic CAN interfaces are not affected.

Received CAN FD frames are sent to the client as

    < fdframe can_id flags seconds.useconds [data]* >

where flags is the hex value of the CANFD_BRS/CANFD_ESI bits of canfd_frame.flags and data contains up to 64 bytes. Classic CAN frames are still sent as < frame >, so clients only supporting classic CAN never receive more than 8 data bytes and can ignore the new message (as for any other unknown message).

Signed-off-by: Florian Roks <florian.roks@mercedes-benz.com>
Add a command to send a single CAN FD frame in raw mode:

    < fdsend can_id flags len [data]* >

flags is the hex value of the canfd_frame.flags bits CANFD_BRS (0x01) and CANFD_ESI (0x02), len the number of data bytes (0..64) followed by the data bytes in hex. As for < send >, an 8 digit can_id selects an extended identifier. Payloads that are not a valid CAN FD data length are padded with zeros up to the next valid length.

The command is rejected if the bus does not support CAN FD. < send > stays limited to classic CAN frames.

Signed-off-by: Florian Roks <florian.roks@mercedes-benz.com>
Describe the < fdframe > and < fdsend > messages of the raw mode and the CAN FD interface requirement.

Signed-off-by: Florian Roks <florian.roks@mercedes-benz.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant