From 0ab71827813258bce881dbcaa698b3d03eebd189 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Mon, 8 Sep 2025 13:21:26 +0200 Subject: [PATCH 1/2] cangen: auto enable FD/XL content in mixed mode Automatically create FD/XL content in mixed mode when the CAN interface is capable to deal with it. Suggested-by: Vincent Mailhol Signed-off-by: Oliver Hartkopp --- cangen.c | 110 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 63 insertions(+), 47 deletions(-) diff --git a/cangen.c b/cangen.c index 95ac32df..4787fb9d 100644 --- a/cangen.c +++ b/cangen.c @@ -180,7 +180,7 @@ static void print_usage(char *prg) fprintf(stderr, " -X (generate CAN XL CAN frames)\n"); fprintf(stderr, " -R (generate RTR frames)\n"); fprintf(stderr, " -8 (allow DLC values greater then 8 for Classic CAN frames)\n"); - fprintf(stderr, " -m (mix -e -f -b -E -R -X frames)\n"); + fprintf(stderr, " -m (mix CC [-e -R] FD [-f -b -E] XL [-X] on capable devices)\n"); fprintf(stderr, " -I (CAN ID generation mode - see below)\n"); fprintf(stderr, " -L (CAN data length code (dlc) generation mode - see below)\n"); fprintf(stderr, " -D (CAN data (payload) generation mode - see below)\n"); @@ -455,6 +455,9 @@ int main(int argc, char **argv) unsigned char extended = 0; unsigned char canfd = 0; unsigned char canxl = 0; + unsigned char mixcc = 1; /* mix default */ + unsigned char mixfd = 1; /* mix default */ + unsigned char mixxl = 1; /* mix default */ unsigned char brs = 0; unsigned char esi = 0; unsigned char mix = 0; @@ -574,7 +577,6 @@ int main(int argc, char **argv) case 'm': mix = 1; - canfd = 1; /* to switch the socket into CAN FD mode */ view |= CANLIB_VIEW_INDENT_SFF; break; @@ -777,57 +779,66 @@ int main(int argc, char **argv) &loopback, sizeof(loopback)); } - if (canfd || canxl) { + /* get CAN netdevice MTU for frame type capabilities */ + if (ioctl(s, SIOCGIFMTU, &ifr) < 0) { + perror("SIOCGIFMTU"); + return 1; + } - /* check if the frame fits into the CAN netdevice */ - if (ioctl(s, SIOCGIFMTU, &ifr) < 0) { - perror("SIOCGIFMTU"); + /* check CAN XL support */ + if (ifr.ifr_mtu < (int)CANXL_MIN_MTU) { + mixxl = 0; + if (canxl) { + printf("CAN interface not CAN XL capable - sorry.\n"); return 1; } + } + /* check CAN FD support */ + if (ifr.ifr_mtu < (int)CANFD_MTU) { + mixfd = 0; if (canfd) { - /* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */ - cu.fd.len = can_fd_dlc2len(can_fd_len2dlc(cu.fd.len)); - } else { - /* limit fixed CAN XL data length to 64 */ - if (cu.fd.len > CANFD_MAX_DLEN) - cu.fd.len = CANFD_MAX_DLEN; + printf("CAN interface not CAN FD capable - sorry.\n"); + return 1; } + } - if (canxl && (ifr.ifr_mtu < (int)CANXL_MIN_MTU)) { - printf("CAN interface not CAN XL capable - sorry.\n"); + /* enable CAN FD on the socket */ + if (mixfd) { + /* interface is ok - try to switch the socket into CAN FD mode */ + if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, + &enable_canfx, sizeof(enable_canfx))){ + printf("error when enabling CAN FD support\n"); return 1; } + } - if (canfd && (ifr.ifr_mtu < (int)CANFD_MTU)) { - printf("CAN interface not CAN FD capable - sorry.\n"); + /* enable CAN XL on the socket */ + if (mixxl) { + /* interface is ok - try to switch the socket into CAN XL mode */ + if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_FRAMES, + &enable_canfx, sizeof(enable_canfx))){ + printf("error when enabling CAN XL support\n"); return 1; } - - if (ifr.ifr_mtu == (int)CANFD_MTU) { - /* interface is ok - try to switch the socket into CAN FD mode */ - if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, - &enable_canfx, sizeof(enable_canfx))){ - printf("error when enabling CAN FD support\n"); - return 1; - } + /* try to enable the CAN XL VCID pass through mode */ + if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_VCID_OPTS, + &vcid_opts, sizeof(vcid_opts))) { + printf("error when enabling CAN XL VCID pass through\n"); + return 1; } + } - if (ifr.ifr_mtu >= (int)CANXL_MIN_MTU) { - /* interface is ok - try to switch the socket into CAN XL mode */ - if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_FRAMES, - &enable_canfx, sizeof(enable_canfx))){ - printf("error when enabling CAN XL support\n"); - return 1; - } - /* try to enable the CAN XL VCID pass through mode */ - if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_VCID_OPTS, - &vcid_opts, sizeof(vcid_opts))) { - printf("error when enabling CAN XL VCID pass through\n"); - return 1; - } + /* sanitize given values */ + if (canfd || canxl) { + if (canfd) { + /* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */ + cu.fd.len = can_fd_dlc2len(can_fd_len2dlc(cu.fd.len)); + } else { + /* limit fixed CAN XL data length to 64 */ + if (cu.fd.len > CANFD_MAX_DLEN) + cu.fd.len = CANFD_MAX_DLEN; } - } else { /* sanitize Classical CAN 2.0 frame length */ if (len8_dlc) { @@ -1084,16 +1095,21 @@ int main(int argc, char **argv) if (mix) { i = random(); extended = i & 1; - canfd = i & 2; - if (canfd) { - brs = i & 4; - esi = i & 8; + if (mixfd) { + canfd = i & 2; + if (canfd) { + brs = i & 4; + esi = i & 8; + } } - /* generate CAN XL traffic if the interface is capable */ - if (ifr.ifr_mtu >= (int)CANXL_MIN_MTU) - canxl = ((i & 96) == 96); - - rtr_frame = ((i & 24) == 24); /* reduce RTR frames to 1/4 */ + if (mixxl) { + if (mixfd) + canxl = ((i & 96) == 96); /* 1/4 */ + else + canxl = ((i & 32) == 32); /* 1/2 */ + } + if (mixcc) + rtr_frame = ((i & 24) == 24); /* reduce RTR to 1/4 */ } } From af328b864ca3f9b21f1b39d868501abefda29385 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Thu, 27 Nov 2025 16:49:34 +0100 Subject: [PATCH 2/2] cangen: disable generation of unsupported CAN frame types in mixed mode The mixed mode is able to automatically detect the potential supported CAN frame types CAN CC/FD/XL by checking the CAN device MTU at startup. Usually the MTU shows which CAN frame types can be sent but in the case of CAN XL in CANXL-only mode CC and FD frames can not be sent on the CAN_RAW socket. Since this patch [1] the CAN_RAW socket rejects unsupported CAN frames and returns -EINVAL as error code. With this change in cangen the CC and FD frame generation can be disabled in mixed mode at runtime. [1] https://lore.kernel.org/linux-can/20251125123859.3924-17-socketcan@hartkopp.net/T/#u Signed-off-by: Oliver Hartkopp --- cangen.c | 50 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/cangen.c b/cangen.c index 4787fb9d..97cc2656 100644 --- a/cangen.c +++ b/cangen.c @@ -339,10 +339,9 @@ static int do_send_one(int fd, cu_t *cu, size_t len, int timeout) nbytes = sendmsg(fd, &msg, 0); if (nbytes < 0) { ret = -errno; - if (ret != -ENOBUFS) { - perror("write"); + if (ret != -ENOBUFS) return ret; - } + if (!ignore_enobufs && !timeout) { perror("write"); return ret; @@ -1051,8 +1050,31 @@ int main(int argc, char **argv) } ret = do_send_one(s, &cu, mtu, polltimeout); - if (ret) + if ((ret == -EINVAL) && mix) { + /* mix mode: disable unsupported CAN frame type */ + switch (mtu) { + case CAN_MTU: + mixcc = 0; + break; + case CANFD_MTU: + mixfd = 0; + break; + case CANXL_MTU: + mixxl = 0; + break; + default: + printf ("mix mode: unknown MTU"); + return 1; + } + if (!mixcc && !mixfd && !mixxl) { + printf ("mix mode: no valid CAN frame types\n"); + return 1; + } + } else if (ret) { + /* other error than -ENOBUFS and -EINVAL */ + perror("write"); return 1; + } if (burst_sent_count >= burst_count) burst_sent_count = 0; @@ -1093,6 +1115,8 @@ int main(int argc, char **argv) } if (mix) { + canfd = 0; + canxl = 0; i = random(); extended = i & 1; if (mixfd) { @@ -1108,8 +1132,24 @@ int main(int argc, char **argv) else canxl = ((i & 32) == 32); /* 1/2 */ } - if (mixcc) + if (mixcc) { rtr_frame = ((i & 24) == 24); /* reduce RTR to 1/4 */ + } else { + /* no CC frames allowed - CAN XL-only mode? */ + if (!canxl && !canfd) { + /* force XL or FD frames */ + if (mixxl) + canxl = 1; + else if (mixfd) { + canfd = 1; + brs = i & 4; + esi = i & 8; + } else { + printf ("mix mode: no valid CAN frame types\n"); + return 1; + } + } + } } }