Compare commits

...

8 Commits

Author SHA1 Message Date
Mathew 887b93c31b
Merge 0cfff2e5da into 7939678070 2025-12-13 10:11:53 -08:00
Oliver Hartkopp 7939678070 can-utils: unify indention
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2025-12-13 10:38:15 +01:00
Marc Kleine-Budde 88a0417a6b
Merge pull request #609 from dphipps-qnx/fix_cmsg_types
candump: Use SCM_* consts instead of SO_* for cmsg_type
2025-12-05 16:26:30 +01:00
Darcy Phipps 65e715d56d candump: Use SCM_* consts instead of SO_* for cmsg_type
There are explicit #defines for SCM_TIMESTAMP and SCM_TIMESTAMPING. They
currently happen to have the same value as SO_TIMESTAMP and
SO_TIMESTAMPING but the former should be used when checking cmsg_type in
case one day they do not.
2025-12-05 09:35:50 -05: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
Mateusz Juzwiak 0cfff2e5da isotpsniffer: change -q to -i parameter, const buffer size 2024-09-26 14:31:06 +02:00
Mateusz Juzwiak 1e2c8fea4c isotpsniffer: option for no quitting on invalid message received 2024-07-19 05:37:53 -04:00
16 changed files with 827 additions and 752 deletions

View File

@ -72,6 +72,9 @@
#ifndef SO_TIMESTAMPING #ifndef SO_TIMESTAMPING
#define SO_TIMESTAMPING 37 #define SO_TIMESTAMPING 37
#endif #endif
#ifndef SCM_TIMESTAMPING
#define SCM_TIMESTAMPING SO_TIMESTAMPING
#endif
#define TIMESTAMPSZ 50 /* string 'absolute with date' requires max 49 bytes */ #define TIMESTAMPSZ 50 /* string 'absolute with date' requires max 49 bytes */
@ -807,13 +810,13 @@ int main(int argc, char **argv)
for (cmsg = CMSG_FIRSTHDR(&msg); for (cmsg = CMSG_FIRSTHDR(&msg);
cmsg && (cmsg->cmsg_level == SOL_SOCKET); cmsg && (cmsg->cmsg_level == SOL_SOCKET);
cmsg = CMSG_NXTHDR(&msg,cmsg)) { cmsg = CMSG_NXTHDR(&msg,cmsg)) {
if (cmsg->cmsg_type == SO_TIMESTAMP) { if (cmsg->cmsg_type == SCM_TIMESTAMP) {
struct timeval tv; struct timeval tv;
memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv)); memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
ts.tv_sec = tv.tv_sec; ts.tv_sec = tv.tv_sec;
ts.tv_nsec = tv.tv_usec; ts.tv_nsec = tv.tv_usec;
ts.tv_nsec *= 1000; ts.tv_nsec *= 1000;
} else if (cmsg->cmsg_type == SO_TIMESTAMPING) { } else if (cmsg->cmsg_type == SCM_TIMESTAMPING) {
struct timespec *stamp = (struct timespec *)CMSG_DATA(cmsg); struct timespec *stamp = (struct timespec *)CMSG_DATA(cmsg);
/* /*

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

@ -59,6 +59,7 @@
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/isotp.h> #include <linux/can/isotp.h>
#include <linux/sockios.h> #include <linux/sockios.h>
#include <errno.h>
#define NO_CAN_ID 0xFFFFFFFFU #define NO_CAN_ID 0xFFFFFFFFU
@ -66,6 +67,8 @@
#define FORMAT_ASCII 2 #define FORMAT_ASCII 2
#define FORMAT_DEFAULT (FORMAT_ASCII | FORMAT_HEX) #define FORMAT_DEFAULT (FORMAT_ASCII | FORMAT_HEX)
#define PDU_BUF_SIZE 4096
void print_usage(char *prg) void print_usage(char *prg)
{ {
fprintf(stderr, "\nUsage: %s [options] <CAN interface>\n", prg); fprintf(stderr, "\nUsage: %s [options] <CAN interface>\n", prg);
@ -79,6 +82,7 @@ void print_usage(char *prg)
fprintf(stderr, " -f <format> (1 = HEX, 2 = ASCII, 3 = HEX & ASCII - default: %d)\n", FORMAT_DEFAULT); fprintf(stderr, " -f <format> (1 = HEX, 2 = ASCII, 3 = HEX & ASCII - default: %d)\n", FORMAT_DEFAULT);
fprintf(stderr, " -L (set link layer options for CAN FD)\n"); fprintf(stderr, " -L (set link layer options for CAN FD)\n");
fprintf(stderr, " -h <len> (head: print only first <len> bytes)\n"); fprintf(stderr, " -h <len> (head: print only first <len> bytes)\n");
fprintf(stderr, " -i (ignore syscall errors to receive malformed PDUs)\n");
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n"); fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
@ -189,15 +193,16 @@ int main(int argc, char **argv)
int head = 0; int head = 0;
int timestamp = 0; int timestamp = 0;
int format = FORMAT_DEFAULT; int format = FORMAT_DEFAULT;
int ignore_errors = 0;
canid_t src = NO_CAN_ID; canid_t src = NO_CAN_ID;
canid_t dst = NO_CAN_ID; canid_t dst = NO_CAN_ID;
extern int optind, opterr, optopt; extern int optind, opterr, optopt;
static struct timeval tv, last_tv; static struct timeval tv, last_tv;
unsigned char buffer[4096]; unsigned char buffer[PDU_BUF_SIZE];
int nbytes; int nbytes;
while ((opt = getopt(argc, argv, "s:d:x:X:h:ct:f:L?")) != -1) { while ((opt = getopt(argc, argv, "s:d:x:X:h:ct:f:L?i")) != -1) {
switch (opt) { switch (opt) {
case 's': case 's':
src = strtoul(optarg, NULL, 16); src = strtoul(optarg, NULL, 16);
@ -249,6 +254,10 @@ int main(int argc, char **argv)
} }
break; break;
case 'i':
ignore_errors = 1;
break;
case '?': case '?':
print_usage(basename(argv[0])); print_usage(basename(argv[0]));
goto out; goto out;
@ -367,31 +376,37 @@ int main(int argc, char **argv)
} }
if (FD_ISSET(s, &rdfs)) { if (FD_ISSET(s, &rdfs)) {
nbytes = read(s, buffer, 4096); nbytes = read(s, buffer, PDU_BUF_SIZE);
if (nbytes < 0) { if (nbytes < 0) {
perror("read socket s"); perror("read socket s");
r = 1; r = 1;
if(!ignore_errors)
goto out; goto out;
} }
if (nbytes > 4095) { if (nbytes > (PDU_BUF_SIZE - 1)) {
r = 1; r = 1;
fprintf(stderr, "PDU length %d longer than PDU buffer: %s\n", nbytes, strerror(errno));
goto out; goto out;
} }
if(nbytes > 0)
printbuf(buffer, nbytes, color?2:0, timestamp, format, printbuf(buffer, nbytes, color?2:0, timestamp, format,
&tv, &last_tv, dst, s, if_name, head); &tv, &last_tv, dst, s, if_name, head);
} }
if (FD_ISSET(t, &rdfs)) { if (FD_ISSET(t, &rdfs)) {
nbytes = read(t, buffer, 4096); nbytes = read(t, buffer, PDU_BUF_SIZE);
if (nbytes < 0) { if (nbytes < 0) {
perror("read socket t"); perror("read socket t");
r = 1; r = 1;
if(!ignore_errors)
goto out; goto out;
} }
if (nbytes > 4095) { if (nbytes > (PDU_BUF_SIZE - 1)) {
r = 1; r = 1;
fprintf(stderr, "PDU length %d longer than PDU buffer: %s\n", nbytes, strerror(errno));
goto out; goto out;
} }
if(nbytes > 0)
printbuf(buffer, nbytes, color?1:0, timestamp, format, printbuf(buffer, nbytes, color?1:0, timestamp, format,
&tv, &last_tv, src, t, if_name, head); &tv, &last_tv, src, t, if_name, head);
} }

View File

@ -112,10 +112,10 @@ static struct {
int sig_alrm; int sig_alrm;
int sig_usr1; int sig_usr1;
int state; int state;
#define STATE_INITIAL 0 #define STATE_INITIAL 0
#define STATE_REQ_SENT 1 #define STATE_REQ_SENT 1
#define STATE_REQ_PENDING 2 /* wait 1250 msec for first claim */ #define STATE_REQ_PENDING 2 /* wait 1250 msec for first claim */
#define STATE_OPERATIONAL 3 #define STATE_OPERATIONAL 3
} s = { } s = {
.intf = default_intf, .intf = default_intf,
.ranges = default_range, .ranges = default_range,
@ -126,8 +126,8 @@ static struct {
struct { struct {
uint64_t name; uint64_t name;
int flags; int flags;
#define F_USE 0x01 #define F_USE 0x01
#define F_SEEN 0x02 #define F_SEEN 0x02
} addr[J1939_IDLE_ADDR /* =254 */]; } addr[J1939_IDLE_ADDR /* =254 */];
/* lookup by name */ /* lookup by name */

View File

@ -68,9 +68,9 @@ static struct {
int pkt_len; int pkt_len;
int priority; int priority;
int defined; int defined;
#define DEF_SRC 1 #define DEF_SRC 1
#define DEF_DST 2 #define DEF_DST 2
#define DEF_PRIO 4 #define DEF_PRIO 4
struct sockaddr_can src, dst; struct sockaddr_can src, dst;
} s = { } s = {
.priority = 6, .priority = 6,

7
lib.c
View File

@ -83,8 +83,8 @@ static inline void _put_id(char *buf, int end_offset, canid_t id)
/* CAN DLC to real data length conversion helpers */ /* CAN DLC to real data length conversion helpers */
static const unsigned char dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7, static const unsigned char dlc2len[] = {
8, 12, 16, 20, 24, 32, 48, 64}; 0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64};
/* get data length from raw data length code (DLC) */ /* get data length from raw data length code (DLC) */
unsigned char can_fd_dlc2len(unsigned char dlc) unsigned char can_fd_dlc2len(unsigned char dlc)
@ -92,7 +92,8 @@ unsigned char can_fd_dlc2len(unsigned char dlc)
return dlc2len[dlc & 0x0F]; return dlc2len[dlc & 0x0F];
} }
static const unsigned char len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */ static const unsigned char len2dlc[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
9, 9, 9, 9, /* 9 - 12 */ 9, 9, 9, 9, /* 9 - 12 */
10, 10, 10, 10, /* 13 - 16 */ 10, 10, 10, 10, /* 13 - 16 */
11, 11, 11, 11, /* 17 - 20 */ 11, 11, 11, 11, /* 17 - 20 */