Compare commits

...

13 Commits

Author SHA1 Message Date
Mathew dacd9da569
Merge 0cfff2e5da into ed7822c9a2 2025-11-27 18:24:41 +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
Oliver Hartkopp 8bf5f8873f Fix optional nanosecond timestamp
The extension of the timestamp size is missing in log2asc.c and canplayer.c

Fixes: 987bc8aac2 ("Optional nanosecond timestamp logging")
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2025-09-03 12:55:26 +02:00
Rikus Wessels 0094905376 Fix possible sscanf buffer overflow 2025-09-03 12:42:51 +02:00
Rikus Wessels 987bc8aac2
Optional nanosecond timestamp logging (#592)
* Optional nanosecond timestamp logging

* Removed limited string reading
2025-09-03 11:11:47 +02: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
7 changed files with 144 additions and 66 deletions

104
candump.c
View File

@ -113,7 +113,8 @@ static const int canfx_on = 1;
#define MAXANI 4
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;
@ -128,6 +129,7 @@ static void print_usage(void)
fprintf(stderr, "Options:\n");
fprintf(stderr, " -t <type> (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\n");
fprintf(stderr, " -H (read hardware timestamps instead of system timestamps)\n");
fprintf(stderr, " -N (log nanosecond timestamps instead of microseconds)\n");
fprintf(stderr, " -c (increment color mode level)\n");
fprintf(stderr, " -i (binary output - may exceed 80 chars/line)\n");
fprintf(stderr, " -a (enable additional ASCII output)\n");
@ -142,7 +144,7 @@ static void print_usage(void)
fprintf(stderr, " -d (monitor dropped CAN frames)\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, " -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, "\n");
fprintf(stderr, "Up to %d CAN interfaces with optional filter sets can be specified\n", MAXSOCK);
@ -220,16 +222,22 @@ static int idx2dindex(int ifidx, int socket)
return i;
}
static int sprint_timestamp(char *ts_buffer, const char timestamp,
const struct timeval *tv, struct timeval *const last_tv)
static int sprint_timestamp(char *ts_buffer, const char timestamp, const char use_ns,
const struct timespec *ts, struct timespec *const last_ts)
{
int numchars = 0;
switch (timestamp) {
case 'a': /* absolute with timestamp */
numchars = sprintf(ts_buffer, "(%010llu.%06llu) ",
(unsigned long long)tv->tv_sec,
(unsigned long long)tv->tv_usec);
if (use_ns) {
numchars = sprintf(ts_buffer, "(%010llu.%09llu) ",
(unsigned long long)ts->tv_sec,
(unsigned long long)ts->tv_nsec);
} else {
numchars = sprintf(ts_buffer, "(%010llu.%06llu) ",
(unsigned long long)ts->tv_sec,
(unsigned long long)ts->tv_nsec / 1000);
}
break;
case 'A': /* absolute with date */
@ -237,32 +245,43 @@ static int sprint_timestamp(char *ts_buffer, const char timestamp,
struct tm tm;
char timestring[25];
tm = *localtime(&tv->tv_sec);
tm = *localtime(&ts->tv_sec);
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
numchars = sprintf(ts_buffer, "(%s.%06llu) ", timestring,
(unsigned long long)tv->tv_usec);
if (use_ns) {
numchars = sprintf(ts_buffer, "(%s.%09llu) ", timestring,
(unsigned long long)ts->tv_nsec);
} else {
numchars = sprintf(ts_buffer, "(%s.%06llu) ", timestring,
(unsigned long long)ts->tv_nsec / 1000);
}
}
break;
case 'd': /* delta */
case 'z': /* starting with zero */
{
struct timeval diff;
struct timespec diff;
if (last_tv->tv_sec == 0) /* first init */
*last_tv = *tv;
diff.tv_sec = tv->tv_sec - last_tv->tv_sec;
diff.tv_usec = tv->tv_usec - last_tv->tv_usec;
if (diff.tv_usec < 0)
diff.tv_sec--, diff.tv_usec += 1000000;
if (last_ts->tv_sec == 0) /* first init */
*last_ts = *ts;
diff.tv_sec = ts->tv_sec - last_ts->tv_sec;
diff.tv_nsec = ts->tv_nsec - last_ts->tv_nsec;
if (diff.tv_nsec < 0)
diff.tv_sec--, diff.tv_nsec += 1000000000;
if (diff.tv_sec < 0)
diff.tv_sec = diff.tv_usec = 0;
numchars = sprintf(ts_buffer, "(%03llu.%06llu) ",
(unsigned long long)diff.tv_sec,
(unsigned long long)diff.tv_usec);
diff.tv_sec = diff.tv_nsec = 0;
if (use_ns) {
numchars = sprintf(ts_buffer, "(%03llu.%09llu) ",
(unsigned long long)diff.tv_sec,
(unsigned long long)diff.tv_nsec);
} else {
numchars = sprintf(ts_buffer, "(%03llu.%06llu) ",
(unsigned long long)diff.tv_sec,
(unsigned long long)diff.tv_nsec / 1000);
}
if (timestamp == 'd')
*last_tv = *tv; /* update for delta calculation */
*last_ts = *ts; /* update for delta calculation */
}
break;
@ -288,6 +307,7 @@ int main(int argc, char **argv)
unsigned char timestamp = 0;
unsigned char logtimestamp = 'a';
unsigned char hwtimestamp = 0;
unsigned char use_ns = 0;
unsigned char down_causes_exit = 1;
unsigned char dropmonitor = 0;
unsigned char extra_msg_info = 0;
@ -322,7 +342,7 @@ int main(int argc, char **argv)
static cu_t cu; /* union for CAN CC/FD/XL frames */
int nbytes, i;
struct ifreq ifr;
struct timeval tv, last_tv;
struct timespec ts, last_ts;
int timeout_ms = -1; /* default to no timeout */
FILE *logfile = NULL;
char fname[83]; /* suggested by -Wformat-overflow= */
@ -334,12 +354,12 @@ int main(int argc, char **argv)
signal(SIGHUP, sigterm);
signal(SIGINT, sigterm);
last_tv.tv_sec = 0;
last_tv.tv_usec = 0;
last_ts.tv_sec = 0;
last_ts.tv_nsec = 0;
progname = basename(argv[0]);
while ((opt = getopt(argc, argv, "t:HciaSs:lf:Ln:r:Dde8xT:h?")) != -1) {
while ((opt = getopt(argc, argv, "t:HNciaSs:lf:Ln:r:Dde8xT:h?")) != -1) {
switch (opt) {
case 't':
timestamp = optarg[0];
@ -359,6 +379,10 @@ int main(int argc, char **argv)
hwtimestamp = 1;
break;
case 'N':
use_ns = 1;
break;
case 'c':
color++;
break;
@ -784,7 +808,11 @@ int main(int argc, char **argv)
cmsg && (cmsg->cmsg_level == SOL_SOCKET);
cmsg = CMSG_NXTHDR(&msg,cmsg)) {
if (cmsg->cmsg_type == SO_TIMESTAMP) {
struct timeval tv;
memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
ts.tv_sec = tv.tv_sec;
ts.tv_nsec = tv.tv_usec;
ts.tv_nsec *= 1000;
} else if (cmsg->cmsg_type == SO_TIMESTAMPING) {
struct timespec *stamp = (struct timespec *)CMSG_DATA(cmsg);
@ -795,8 +823,7 @@ int main(int argc, char **argv)
* See chapter 2.1.2 Receive timestamps in
* linux/Documentation/networking/timestamping.txt
*/
tv.tv_sec = stamp[2].tv_sec;
tv.tv_usec = stamp[2].tv_nsec / 1000;
ts = stamp[2];
} else if (cmsg->cmsg_type == SO_RXQ_OVFL) {
memcpy(&obj->dropcnt, CMSG_DATA(cmsg), sizeof(__u32));
}
@ -831,11 +858,9 @@ int main(int argc, char **argv)
/* build common log format output */
if ((log) || ((logfrmt) && (silent == SILENT_OFF))) {
alen = sprint_timestamp(afrbuf, logtimestamp,
&tv, &last_tv);
alen = sprint_timestamp(afrbuf, logtimestamp, use_ns, &ts, &last_ts);
alen += sprintf(afrbuf + alen, "%*s ",
max_devname_len, devname[idx]);
alen += sprintf(afrbuf + alen, "%*s ", max_devname_len, devname[idx]);
alen += snprintf_canframe(afrbuf + alen, sizeof(afrbuf) - alen, &cu, 0);
}
@ -861,18 +886,23 @@ int main(int argc, char **argv)
/* print (colored) long CAN frame style to stdout */
alen = sprintf(afrbuf, " %s", (color > 2) ? col_on[idx % MAXCOL] : "");
alen += sprint_timestamp(afrbuf + alen, timestamp, &tv, &last_tv);
alen += sprint_timestamp(afrbuf + alen, timestamp, use_ns, &ts, &last_ts);
alen += sprintf(afrbuf + alen, " %s%*s",
(color && (color < 3)) ? col_on[idx % MAXCOL] : "",
max_devname_len, devname[idx]);
if (extra_msg_info) {
if (msg.msg_flags & MSG_DONTROUTE)
alen += sprintf(afrbuf + alen, " TX %s",
extra_m_info[cu.fd.flags & 3]);
alen += sprintf(afrbuf + alen, " TX");
else
alen += sprintf(afrbuf + alen, " RX %s",
extra_m_info[cu.fd.flags & 3]);
alen += sprintf(afrbuf + alen, " RX");
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 : "");

View File

@ -68,7 +68,7 @@
#endif
#define DEVSZ 22 /* IFNAMSZ + 6 */
#define TIMESZ sizeof("(1345212884.318850) ")
#define TIMESZ sizeof("(1345212884.318850123) ")
#define BUFSZ (TIMESZ + DEVSZ + AFRSZ)
/* adapt sscanf() functions below on error */
@ -452,14 +452,20 @@ int main(int argc, char **argv)
return 1;
}
log_tv.tv_sec = sec;
log_tv.tv_usec = usec;
/*
* ensure the fractions of seconds are 6 decimal places long to catch
* ensure the fractions of seconds are 6 or 9 decimal places long to catch
* 3rd party or handcrafted logfiles that treat the timestamp as float
*/
if (strchr(buf, ')') - strchr(buf, '.') != 7) {
fprintf(stderr, "timestamp format in logfile requires 6 decimal places\n");
switch (strchr(buf, ')') - strchr(buf, '.')) {
case 7: //6
log_tv.tv_usec = usec;
break;
case 10: //9
log_tv.tv_usec = usec / 1000;
break;
default:
fprintf(stderr, "timestamp format in logfile requires 6 or 9 decimal places\n");
return 1;
}
@ -541,19 +547,25 @@ int main(int argc, char **argv)
break;
}
if (sscanf(buf, "(%llu.%llu) %s %s", &sec, &usec, device, afrbuf) != 4) {
if (sscanf(buf, "(%llu.%llu) %21s %6299s", &sec, &usec, device, afrbuf) != 4) {
fprintf(stderr, "incorrect line format in logfile\n");
return 1;
}
log_tv.tv_sec = sec;
log_tv.tv_usec = usec;
/*
* ensure the fractions of seconds are 6 decimal places long to catch
* ensure the fractions of seconds are 6 or 9 decimal places long to catch
* 3rd party or handcrafted logfiles that treat the timestamp as float
*/
if (strchr(buf, ')') - strchr(buf, '.') != 7) {
fprintf(stderr, "timestamp format in logfile requires 6 decimal places\n");
switch (strchr(buf, ')') - strchr(buf, '.')) {
case 7: //6
log_tv.tv_usec = usec;
break;
case 10: //9
log_tv.tv_usec = usec / 1000;
break;
default:
fprintf(stderr, "timestamp format in logfile requires 6 or 9 decimal places\n");
return 1;
}

View File

@ -80,7 +80,10 @@ static void print_usage(char *prg)
"_{dlc}:\n"
" an optional 9..F data length code value when payload length is 8\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"
"<vcid>:\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"
" 45123#81:00:12345678#11223344.556677 / 00242#81:07:40000123#112233\n"
"\n",
prg, prg);
prg, prg,
CANFD_BRS, CANFD_ESI, CANFD_FDF);
}
int main(int argc, char **argv)

View File

@ -59,6 +59,7 @@
#include <linux/can.h>
#include <linux/can/isotp.h>
#include <linux/sockios.h>
#include <errno.h>
#define NO_CAN_ID 0xFFFFFFFFU
@ -66,6 +67,8 @@
#define FORMAT_ASCII 2
#define FORMAT_DEFAULT (FORMAT_ASCII | FORMAT_HEX)
#define PDU_BUF_SIZE 4096
void print_usage(char *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, " -L (set link layer options for CAN FD)\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, "\n");
}
@ -189,15 +193,16 @@ int main(int argc, char **argv)
int head = 0;
int timestamp = 0;
int format = FORMAT_DEFAULT;
int ignore_errors = 0;
canid_t src = NO_CAN_ID;
canid_t dst = NO_CAN_ID;
extern int optind, opterr, optopt;
static struct timeval tv, last_tv;
unsigned char buffer[4096];
unsigned char buffer[PDU_BUF_SIZE];
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) {
case 's':
src = strtoul(optarg, NULL, 16);
@ -249,6 +254,10 @@ int main(int argc, char **argv)
}
break;
case 'i':
ignore_errors = 1;
break;
case '?':
print_usage(basename(argv[0]));
goto out;
@ -367,33 +376,39 @@ int main(int argc, char **argv)
}
if (FD_ISSET(s, &rdfs)) {
nbytes = read(s, buffer, 4096);
nbytes = read(s, buffer, PDU_BUF_SIZE);
if (nbytes < 0) {
perror("read socket s");
r = 1;
goto out;
if(!ignore_errors)
goto out;
}
if (nbytes > 4095) {
if (nbytes > (PDU_BUF_SIZE - 1)) {
r = 1;
fprintf(stderr, "PDU length %d longer than PDU buffer: %s\n", nbytes, strerror(errno));
goto out;
}
printbuf(buffer, nbytes, color?2:0, timestamp, format,
&tv, &last_tv, dst, s, if_name, head);
if(nbytes > 0)
printbuf(buffer, nbytes, color?2:0, timestamp, format,
&tv, &last_tv, dst, s, if_name, head);
}
if (FD_ISSET(t, &rdfs)) {
nbytes = read(t, buffer, 4096);
nbytes = read(t, buffer, PDU_BUF_SIZE);
if (nbytes < 0) {
perror("read socket t");
r = 1;
goto out;
if(!ignore_errors)
goto out;
}
if (nbytes > 4095) {
if (nbytes > (PDU_BUF_SIZE - 1)) {
r = 1;
fprintf(stderr, "PDU length %d longer than PDU buffer: %s\n", nbytes, strerror(errno));
goto out;
}
printbuf(buffer, nbytes, color?1:0, timestamp, format,
&tv, &last_tv, src, t, if_name, head);
if(nbytes > 0)
printbuf(buffer, nbytes, color?1:0, timestamp, format,
&tv, &last_tv, src, t, if_name, head);
}
}

2
lib.h
View File

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

View File

@ -296,7 +296,7 @@ static void canxl_asc(cu_t *cu, int devno, int mtu,
#define DEVSZ 22
#define EXTRASZ 20
#define TIMESZ sizeof("(1345212884.318850) ")
#define TIMESZ sizeof("(1345212884.318850123) ")
#define BUFSZ (DEVSZ + AFRSZ + EXTRASZ + TIMESZ)
/* adapt sscanf() functions below on error */
@ -407,7 +407,22 @@ int main(int argc, char **argv)
}
}
tv.tv_sec = sec;
tv.tv_usec = usec;
/*
* ensure the fractions of seconds are 6 or 9 decimal places long to catch
* 3rd party or handcrafted logfiles that treat the timestamp as float
*/
switch (strchr(buf, ')') - strchr(buf, '.')) {
case 7: //6
tv.tv_usec = usec;
break;
case 10: //9
tv.tv_usec = usec / 1000;
break;
default:
fprintf(stderr, "timestamp format in logfile requires 6 or 9 decimal places\n");
return 1;
}
if (print_banner) { /* print banner */
print_banner = 0;

View File

@ -51,7 +51,7 @@
#include "lib.h"
#define DEVSZ 22
#define TIMESZ 22 /* sizeof("(1345212884.318850) ") */
#define TIMESZ 25 /* sizeof("(1345212884.318850123) ") */
#define BUFSZ (DEVSZ + AFRSZ + TIMESZ)
/* adapt sscanf() functions below on error */
@ -61,7 +61,7 @@
#if (DEVSZ != 22)
#error "DEVSZ value does not fit sscanf restrictions!"
#endif
#if (TIMESZ != 22)
#if (TIMESZ != 25)
#error "TIMESZ value does not fit sscanf restrictions!"
#endif
@ -78,7 +78,7 @@ int main(void)
return 1;
}
if (sscanf(buf, "%21s %21s %6299s", timestamp, device, afrbuf) != 3)
if (sscanf(buf, "%24s %21s %6299s", timestamp, device, afrbuf) != 3)
return 1;
mtu = parse_canframe(afrbuf, &cu);