Compare commits

..

10 Commits

Author SHA1 Message Date
Ben Gardiner cb19c9d24b
Merge 63500f8dd0 into 374fecde09 2025-12-04 00:51:46 -08:00
Oliver Hartkopp 374fecde09 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 <socketcan@hartkopp.net>
2025-12-03 16:09:12 +01:00
Oliver Hartkopp bfbf0c851f 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 <mailhol@kernel.org>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2025-12-03 16:09:12 +01:00
Oliver Hartkopp ed7822c9a2 candump: print CAN XL specific flags as extra message infos
The extra message infos BRS and ESI have been printed when enabled with
the '-x' option. Since CAN XL has similar flags (SEC and RRS) those flags
have been wrongly printed as CAN FD flags.

This patch introduces separate flags for the CAN XL frames and prints them
when a CAN XL frame is processed.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2025-11-26 19:04:50 +01:00
Marc Kleine-Budde e9ea9d1168
Merge pull request #607 from marckleinebudde/cansend-fix-typo
cansend: fix typo in CANFD_FDF flag name
2025-11-07 12:55:39 +01:00
Marc Kleine-Budde 2d793d38d2 cansend: fix typo in CANFD_FDF flag name
Closes: https://github.com/linux-can/can-utils/issues/606
Fixes: 3e0e6ae3a4 ("cansend: print canfd_frame.flags in help text")
2025-11-07 12:51:19 +01:00
Marc Kleine-Budde 340a3b8c92
Merge pull request #605 from marckleinebudde/lib_h-selfcontained
lib.h: include linux/can.h
2025-11-07 12:34:08 +01:00
Marc Kleine-Budde 8838ce80fc
Merge pull request #604 from marckleinebudde/cansend-canfd-flags
cansend: print canfd_frame.flags in help text
2025-11-07 12:33:02 +01:00
Marc Kleine-Budde d6c57240ed lib.h: include linux/can.h
Make lib.h self contained, so that language servers can parse it without
errors.
2025-11-07 12:30:15 +01:00
Marc Kleine-Budde 3e0e6ae3a4 cansend: print canfd_frame.flags in help text 2025-11-07 12:05:04 +01:00
4 changed files with 130 additions and 62 deletions

View File

@ -113,7 +113,8 @@ static const int canfx_on = 1;
#define MAXANI 4 #define MAXANI 4
static const char anichar[MAXANI] = { '|', '/', '-', '\\' }; static const char anichar[MAXANI] = { '|', '/', '-', '\\' };
static const char extra_m_info[4][4] = { "- -", "B -", "- E", "B E" }; static const char extra_fd_info[4][4] = { "- -", "B -", "- E", "B E" };
static const char extra_xl_info[4][4] = { "- -", "S -", "- R", "S R" };
extern int optind, opterr, optopt; extern int optind, opterr, optopt;
@ -143,7 +144,7 @@ static void print_usage(void)
fprintf(stderr, " -d (monitor dropped CAN frames)\n"); fprintf(stderr, " -d (monitor dropped CAN frames)\n");
fprintf(stderr, " -e (dump CAN error frames in human-readable format)\n"); fprintf(stderr, " -e (dump CAN error frames in human-readable format)\n");
fprintf(stderr, " -8 (display raw DLC values in {} for Classical CAN)\n"); fprintf(stderr, " -8 (display raw DLC values in {} for Classical CAN)\n");
fprintf(stderr, " -x (print extra message infos, rx/tx brs esi)\n"); fprintf(stderr, " -x (print extra message infos, rx/tx [brs esi|sec rrs])\n");
fprintf(stderr, " -T <msecs> (terminate after <msecs> if no frames were received)\n"); fprintf(stderr, " -T <msecs> (terminate after <msecs> if no frames were received)\n");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
fprintf(stderr, "Up to %d CAN interfaces with optional filter sets can be specified\n", MAXSOCK); fprintf(stderr, "Up to %d CAN interfaces with optional filter sets can be specified\n", MAXSOCK);
@ -892,11 +893,16 @@ int main(int argc, char **argv)
if (extra_msg_info) { if (extra_msg_info) {
if (msg.msg_flags & MSG_DONTROUTE) if (msg.msg_flags & MSG_DONTROUTE)
alen += sprintf(afrbuf + alen, " TX %s", alen += sprintf(afrbuf + alen, " TX");
extra_m_info[cu.fd.flags & 3]);
else else
alen += sprintf(afrbuf + alen, " RX %s", alen += sprintf(afrbuf + alen, " RX");
extra_m_info[cu.fd.flags & 3]);
if (cu.xl.flags & CANXL_XLF)
alen += sprintf(afrbuf + alen, " %s",
extra_xl_info[cu.xl.flags & 3]);
else
alen += sprintf(afrbuf + alen, " %s",
extra_fd_info[cu.fd.flags & 3]);
} }
alen += sprintf(afrbuf + alen, "%s ", (color == 1) ? col_off : ""); alen += sprintf(afrbuf + alen, "%s ", (color == 1) ? col_off : "");

110
cangen.c
View File

@ -180,7 +180,7 @@ static void print_usage(char *prg)
fprintf(stderr, " -X (generate CAN XL CAN frames)\n"); fprintf(stderr, " -X (generate CAN XL CAN frames)\n");
fprintf(stderr, " -R (generate RTR 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, " -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 <mode> (CAN ID generation mode - see below)\n"); fprintf(stderr, " -I <mode> (CAN ID generation mode - see below)\n");
fprintf(stderr, " -L <mode> (CAN data length code (dlc) generation mode - see below)\n"); fprintf(stderr, " -L <mode> (CAN data length code (dlc) generation mode - see below)\n");
fprintf(stderr, " -D <mode> (CAN data (payload) generation mode - see below)\n"); fprintf(stderr, " -D <mode> (CAN data (payload) generation mode - see below)\n");
@ -339,10 +339,9 @@ resend:
nbytes = sendmsg(fd, &msg, 0); nbytes = sendmsg(fd, &msg, 0);
if (nbytes < 0) { if (nbytes < 0) {
ret = -errno; ret = -errno;
if (ret != -ENOBUFS) { if (ret != -ENOBUFS)
perror("write");
return ret; return ret;
}
if (!ignore_enobufs && !timeout) { if (!ignore_enobufs && !timeout) {
perror("write"); perror("write");
return ret; return ret;
@ -455,6 +454,9 @@ int main(int argc, char **argv)
unsigned char extended = 0; unsigned char extended = 0;
unsigned char canfd = 0; unsigned char canfd = 0;
unsigned char canxl = 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 brs = 0;
unsigned char esi = 0; unsigned char esi = 0;
unsigned char mix = 0; unsigned char mix = 0;
@ -574,7 +576,6 @@ int main(int argc, char **argv)
case 'm': case 'm':
mix = 1; mix = 1;
canfd = 1; /* to switch the socket into CAN FD mode */
view |= CANLIB_VIEW_INDENT_SFF; view |= CANLIB_VIEW_INDENT_SFF;
break; break;
@ -777,34 +778,32 @@ int main(int argc, char **argv)
&loopback, sizeof(loopback)); &loopback, sizeof(loopback));
} }
if (canfd || canxl) { /* get CAN netdevice MTU for frame type capabilities */
/* check if the frame fits into the CAN netdevice */
if (ioctl(s, SIOCGIFMTU, &ifr) < 0) { if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
perror("SIOCGIFMTU"); perror("SIOCGIFMTU");
return 1; return 1;
} }
if (canfd) { /* check CAN XL support */
/* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */ if (ifr.ifr_mtu < (int)CANXL_MIN_MTU) {
cu.fd.len = can_fd_dlc2len(can_fd_len2dlc(cu.fd.len)); mixxl = 0;
} else { if (canxl) {
/* limit fixed CAN XL data length to 64 */
if (cu.fd.len > CANFD_MAX_DLEN)
cu.fd.len = CANFD_MAX_DLEN;
}
if (canxl && (ifr.ifr_mtu < (int)CANXL_MIN_MTU)) {
printf("CAN interface not CAN XL capable - sorry.\n"); printf("CAN interface not CAN XL capable - sorry.\n");
return 1; return 1;
} }
}
if (canfd && (ifr.ifr_mtu < (int)CANFD_MTU)) { /* check CAN FD support */
if (ifr.ifr_mtu < (int)CANFD_MTU) {
mixfd = 0;
if (canfd) {
printf("CAN interface not CAN FD capable - sorry.\n"); printf("CAN interface not CAN FD capable - sorry.\n");
return 1; return 1;
} }
}
if (ifr.ifr_mtu == (int)CANFD_MTU) { /* enable CAN FD on the socket */
if (mixfd) {
/* interface is ok - try to switch the socket into CAN FD mode */ /* interface is ok - try to switch the socket into CAN FD mode */
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES,
&enable_canfx, sizeof(enable_canfx))){ &enable_canfx, sizeof(enable_canfx))){
@ -813,7 +812,8 @@ int main(int argc, char **argv)
} }
} }
if (ifr.ifr_mtu >= (int)CANXL_MIN_MTU) { /* enable CAN XL on the socket */
if (mixxl) {
/* interface is ok - try to switch the socket into CAN XL mode */ /* interface is ok - try to switch the socket into CAN XL mode */
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_FRAMES, if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_FRAMES,
&enable_canfx, sizeof(enable_canfx))){ &enable_canfx, sizeof(enable_canfx))){
@ -828,6 +828,16 @@ int main(int argc, char **argv)
} }
} }
/* 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 { } else {
/* sanitize Classical CAN 2.0 frame length */ /* sanitize Classical CAN 2.0 frame length */
if (len8_dlc) { if (len8_dlc) {
@ -1040,8 +1050,31 @@ int main(int argc, char **argv)
} }
ret = do_send_one(s, &cu, mtu, polltimeout); 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; 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) if (burst_sent_count >= burst_count)
burst_sent_count = 0; burst_sent_count = 0;
@ -1082,18 +1115,41 @@ int main(int argc, char **argv)
} }
if (mix) { if (mix) {
canfd = 0;
canxl = 0;
i = random(); i = random();
extended = i & 1; extended = i & 1;
if (mixfd) {
canfd = i & 2; canfd = i & 2;
if (canfd) { if (canfd) {
brs = i & 4; brs = i & 4;
esi = i & 8; esi = i & 8;
} }
/* generate CAN XL traffic if the interface is capable */ }
if (ifr.ifr_mtu >= (int)CANXL_MIN_MTU) if (mixxl) {
canxl = ((i & 96) == 96); if (mixfd)
canxl = ((i & 96) == 96); /* 1/4 */
rtr_frame = ((i & 24) == 24); /* reduce RTR frames to 1/4 */ else
canxl = ((i & 32) == 32); /* 1/2 */
}
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;
}
}
}
} }
} }

View File

@ -80,7 +80,10 @@ static void print_usage(char *prg)
"_{dlc}:\n" "_{dlc}:\n"
" an optional 9..F data length code value when payload length is 8\n" " an optional 9..F data length code value when payload length is 8\n"
"<flags>:\n" "<flags>:\n"
" a single ASCII Hex value (0 .. F) which defines canfd_frame.flags\n" " a single ASCII Hex value (0 .. F) which defines canfd_frame.flags:\n"
" %x CANFD_BRS\n"
" %x CANFD_ESI\n"
" %x CANFD_FDF\n"
"\n" "\n"
"<vcid>:\n" "<vcid>:\n"
" 2 hex chars - virtual CAN network identifier (00 .. FF)\n" " 2 hex chars - virtual CAN network identifier (00 .. FF)\n"
@ -100,7 +103,8 @@ static void print_usage(char *prg)
" 1F334455#1122334455667788_B / 123#R / 00000123#R3 / 333#R8_E /\n" " 1F334455#1122334455667788_B / 123#R / 00000123#R3 / 333#R8_E /\n"
" 45123#81:00:12345678#11223344.556677 / 00242#81:07:40000123#112233\n" " 45123#81:00:12345678#11223344.556677 / 00242#81:07:40000123#112233\n"
"\n", "\n",
prg, prg); prg, prg,
CANFD_BRS, CANFD_ESI, CANFD_FDF);
} }
int main(int argc, char **argv) int main(int argc, char **argv)

2
lib.h
View File

@ -49,6 +49,8 @@
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <linux/can.h>
#ifdef DEBUG #ifdef DEBUG
#define pr_debug(fmt, args...) printf(fmt, ##args) #define pr_debug(fmt, args...) printf(fmt, ##args)
#else #else