22 Commits
Author SHA1 Message Date
Richard YoungandOliver Hartkopp eb66451df2 candump: Enable zero relative timestamps to be used in log files
The logfile format which is generated with '-l' and '-L' consists of an
absolute epoch timestamp. In some use cases (e.g. for documentation) a
zero relative timestamp can be useful which was only configurable with
the '-tz' option for the classic output.

'-tz' and '-ta' are now valid options for the logfile format.

Signed-off-by: Richard Young <code@richyoung.ca>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-12-08 20:52:54 +01:00
Oliver Hartkopp 682e01a40a isotpsend: add SF_BROADCAST support for functional addressing
When CAN_ISOTP_SF_BROADCAST is set in the CAN_ISOTP_OPTS flags the
CAN_ISOTP socket is switched into functional addressing mode, where
only single frame (SF) protocol data units can be send on the specified
CAN interface and the given tp.tx_id after bind().

In opposite to normal and extended addressing this socket does not
register a CAN-ID for reception which would be needed for a 1-to-1
ISOTP connection with a segmented bi-directional data transfer.

The new option '-S' sets the CAN_ISOTP_SF_BROADCAST to test the option
with different length settings, e.g. link layer data lengths.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-12-06 14:41:48 +01:00
Oliver Hartkopp 280ea436d4 isotp: add define for SF_BROADCAST support
When CAN_ISOTP_SF_BROADCAST is set in the CAN_ISOTP_OPTS flags the
CAN_ISOTP socket is switched into functional addressing mode, where
only single frame (SF) protocol data units can be send on the specified
CAN interface and the given tp.tx_id after bind().

Add the CAN_ISOTP_SF_BROADCAST define from Linux UAPI includes.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-12-06 14:17:36 +01:00
Marc Kleine-BuddeandGitHub 33de12680a Merge pull request #270 from marckleinebudde/candump-cleanups
Candump cleanups
2020-12-06 10:22:14 +01:00
Marc Kleine-Budde bfaa44fa91 candump: convert to kernel codeing style
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-12-06 10:09:36 +01:00
Marc Kleine-Budde 305b2e8b79 candump: fix indention
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-12-06 09:58:52 +01:00
Marc Kleine-Budde 15f3a2e385 candump: remove trailing whitespace
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-12-06 09:57:52 +01:00
Marc Kleine-BuddeandGitHub aa6411075f Merge pull request #264 from IDC-Dragon/master
candump: epoll_wait() instead of select() runs faster and better keeps packet order
2020-12-06 09:54:33 +01:00
Marc Kleine-BuddeandGitHub 51d675368d Merge pull request #269 from timgates42/bugfix_typo_caught
docs: fix simple typo, cought -> caught
2020-12-06 09:53:21 +01:00
Jörg HohensohnandJörg Hohensohn 639498bc80 candump: use epoll_wait() instead of select()
Using epoll_wait() instead of select() gives higher
performance for listening on multiple interfaces.
Additionally, the read order has a higher chance
to resemble the true temporal order.
select() gives implicit priority to the lower index socket.

Signed-off-by: Jörg Hohensohn <joerg.hohensohn@gmx.de>
2020-12-06 08:32:36 +01:00
Tim Gates 333e631286 docs: fix simple typo, cought -> caught
There is a small typo in canlogserver.c.

Should read `caught` rather than `cought`.
2020-12-06 17:31:33 +11:00
Oliver Hartkopp 6a14256323 cansniffer: fix snifftab CAN-ID query
Due to a wrong test to check for existing CAN-IDs in the snifftab
it was not possible to have the CAN-ID '0' in the list and displayed.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-12-02 13:26:42 +01:00
Oliver Hartkopp c3d9cc2027 cangw: support len8_dlc for Classical CAN frames
The can_dlc value that is passed to the kernel is not sanitized in cangw
therefore we only update the help text and some comments in gw.h.

In the case that the CAN interface supports len8_dlc by setting
CAN_CTRLMODE_CC_LEN8_DLC the can-gw module can modify the full DLC value
range (0 .. 15) for Classic CAN frames.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-11-22 19:57:27 +01:00
Oliver Hartkopp 972054446a can: rename CAN FD related can_len2dlc and can_dlc2len helpers
The helper functions can_len2dlc and can_dlc2len are only relevant for
CAN FD data length code (DLC) conversion.

Update to latest in-kernel naming scheme:

can_dlc2len -> can_fd_dlc2len to get the payload length from the DLC
can_len2dlc -> can_fd_len2dlc to get the DLC from the payload length

Suggested-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-11-22 19:54:58 +01:00
Oliver Hartkopp 6799180bd0 log asc converter: support len8_dlc for Classical CAN frames
The CANFD format in asc logfiles can be used to describe Classical CAN
frame content too. As this CANFD format has two different elements to
transport the payload length and the 'raw data length code' the new
len8_dlc option now allows to support the full qualified conversion.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-11-22 19:47:24 +01:00
Oliver Hartkopp 11edd1d05e candump: support len8_dlc for standard candump output
The display of Classical CAN raw DLC values is an expert feature which is
not enabled by default to not break toolchains that use the candump
standard output for further processing. (N.B. using the log file format and
the functions from lib.h/lib.c provide convenient CAN frame conversions)

After enabling the raw DLC for Classical CAN with the '-8' option the raw
DLC value is printed in 'unusual' curly braces {}.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-11-22 19:42:38 +01:00
Oliver Hartkopp a272fd2082 cansend: add support for Classic CAN raw DLC values
Update help text only as the new extended frame format is already
implemented in lib.h/lib.c

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-11-22 19:33:16 +01:00
Oliver Hartkopp 1ba0c576ae cangen: add support for Classic CAN raw DLC values
A new option '-8' has been added to generate Classical CAN frames with
DLC codes from 0 .. 15.

Fixed and random mode implemented by Oliver Hartkopp.
Incremental DLC mode 'cangen -8 -Li can0' implemented by Vincent Mailhol.

Signed-off-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-11-22 19:13:21 +01:00
Oliver Hartkopp b70d8c050f lib: add support for Classic CAN raw DLC values
ISO 11898-1 Chapter 8.4.2.3 defines a 4 bit data length code (DLC) table which
maps the DLC to the payload length of the CAN frame in bytes:

    DLC      ->  payload length
    0 .. 8   ->  0 .. 8
    9 .. 15  ->  8

To access the raw DLC values 9 .. 15 the len8_dlc element is introduced, which
is only valid when the payload length 'len' is 8 and the DLC is greater than 8.

The extension for len8_dlc has been implemented for the Classic CAN frame
representation in the log file format and for the standard output for
candump where the raw DLC value is printed in 'unusual' curly braces {}.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-11-22 18:59:53 +01:00
Oliver Hartkopp c398e56afb can: add optional DLC element to Classical CAN frame structure
ISO 11898-1 Chapter 8.4.2.3 defines a 4 bit data length code (DLC) table which
maps the DLC to the payload length of the CAN frame in bytes:

    DLC      ->  payload length
    0 .. 8   ->  0 .. 8
    9 .. 15  ->  8

Although the DLC values 8 .. 15 in Classical CAN always result in a payload
length of 8 bytes these DLC values are transparently transmitted on the CAN
bus. As the struct can_frame only provides a 'len' element (formerly 'can_dlc')
which contains the plain payload length ( 0 .. 8 ) of the CAN frame, the raw
DLC is not visible to the application programmer, e.g. for testing use-cases.

To access the raw DLC values 9 .. 15 the len8_dlc element is introduced, which
is only valid when the payload length 'len' is 8 and the DLC is greater than 8.

The len8_dlc element is filled by the CAN interface driver and used for CAN
frame creation by the CAN driver when the CAN_CTRLMODE_CC_LEN8_DLC flag is
supported by the driver and enabled via netlink configuration interface.

Reported-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-11-22 18:41:38 +01:00
Marc Kleine-BuddeandGitHub d0ad168953 Merge pull request #261 from neheb/patch-1
add missing time.h include
2020-11-18 08:22:31 +01:00
Rosen PenevandGitHub c3348ed51e add missing time.h include
Needed for musl.
2020-11-17 22:14:09 -08:00
16 changed files with 495 additions and 324 deletions
+10 -1
View File
@@ -270,7 +270,7 @@ void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps, int dplace
extra_info = " T\n";
/* don't trust ASCII content - sanitize data length */
if (dlen != can_dlc2len(can_len2dlc(dlen)))
if (dlen != can_fd_dlc2len(can_fd_len2dlc(dlen)))
return;
get_can_id(&cf, tmp1, 16);
@@ -327,6 +327,15 @@ void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps, int dplace
/* dlen is always 0 for classic CAN RTR frames
but the DLC value is valid in RTR cases */
cf.len = dlc;
/* sanitize payload length value */
if (dlc > CAN_MAX_DLEN)
cf.len = CAN_MAX_DLEN;
}
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
if ((cf.len == CAN_MAX_DLEN) && (dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC)) {
struct can_frame *ccf = (struct can_frame *)&cf;
ccf->len8_dlc = dlc;
}
}
+294 -259
View File
@@ -54,6 +54,7 @@
#include <unistd.h>
#include <net/if.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
@@ -72,9 +73,10 @@
#endif
/* from #include <linux/net_tstamp.h> - since Linux 2.6.30 */
#define SOF_TIMESTAMPING_SOFTWARE (1<<4)
#define SOF_TIMESTAMPING_RX_SOFTWARE (1<<3)
#define SOF_TIMESTAMPING_RAW_HARDWARE (1<<6)
#define SOF_TIMESTAMPING_SOFTWARE (1 << 4)
#define SOF_TIMESTAMPING_RX_SOFTWARE (1 << 3)
#define SOF_TIMESTAMPING_RAW_HARDWARE (1 << 6)
#define TIMESTAMPSZ 50 /* string 'absolute with date' requires max 49 bytes */
#define MAXSOCK 16 /* max. number of CAN interfaces given on the cmdline */
#define MAXIFNAMES 30 /* size of receive name index to omit ioctls */
@@ -85,36 +87,41 @@
#define SILENT_INI 42 /* detect user setting on commandline */
#define SILENT_OFF 0 /* no silent mode */
#define SILENT_ANI 1 /* silent mode with animation */
#define SILENT_ON 2 /* silent mode (completely silent) */
#define SILENT_ON 2 /* silent mode (completely silent) */
#define BOLD ATTBOLD
#define RED ATTBOLD FGRED
#define GREEN ATTBOLD FGGREEN
#define YELLOW ATTBOLD FGYELLOW
#define BLUE ATTBOLD FGBLUE
#define MAGENTA ATTBOLD FGMAGENTA
#define CYAN ATTBOLD FGCYAN
#define BOLD ATTBOLD
#define RED (ATTBOLD FGRED)
#define GREEN (ATTBOLD FGGREEN)
#define YELLOW (ATTBOLD FGYELLOW)
#define BLUE (ATTBOLD FGBLUE)
#define MAGENTA (ATTBOLD FGMAGENTA)
#define CYAN (ATTBOLD FGCYAN)
const char col_on [MAXCOL][19] = {BLUE, RED, GREEN, BOLD, MAGENTA, CYAN};
const char col_off [] = ATTRESET;
static const char col_on[MAXCOL][19] = { BLUE, RED, GREEN, BOLD, MAGENTA, CYAN };
static const char col_off[] = ATTRESET;
struct if_info { /* bundled information per open socket */
int s; /* socket */
char *cmdlinename;
__u32 dropcnt;
__u32 last_dropcnt;
};
static struct if_info sock_info[MAXSOCK];
static char *cmdlinename[MAXSOCK];
static __u32 dropcnt[MAXSOCK];
static __u32 last_dropcnt[MAXSOCK];
static char devname[MAXIFNAMES][IFNAMSIZ+1];
static int dindex[MAXIFNAMES];
static int max_devname_len; /* to prevent frazzled device name output */
const int canfd_on = 1;
static int dindex[MAXIFNAMES];
static int max_devname_len; /* to prevent frazzled device name output */
static const int canfd_on = 1;
#define MAXANI 4
const char anichar[MAXANI] = {'|', '/', '-', '\\'};
const char extra_m_info[4][4] = {"- -", "B -", "- E", "B E"};
static const char anichar[MAXANI] = { '|', '/', '-', '\\' };
static const char extra_m_info[4][4] = { "- -", "B -", "- E", "B E" };
extern int optind, opterr, optopt;
static volatile int running = 1;
void print_usage(char *prg)
static void print_usage(char *prg)
{
fprintf(stderr, "%s - dump CAN bus traffic.\n", prg);
fprintf(stderr, "\nUsage: %s [options] <CAN interface>+\n", prg);
@@ -134,6 +141,7 @@ void print_usage(char *prg)
fprintf(stderr, " -D (Don't exit if a \"detected\" can device goes down.\n");
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, " -T <msecs> (terminate after <msecs> without any reception)\n");
fprintf(stderr, "\n");
@@ -159,17 +167,18 @@ void print_usage(char *prg)
fprintf(stderr, "\n");
}
void sigterm(int signo)
static void sigterm(int signo)
{
running = 0;
}
int idx2dindex(int ifidx, int socket) {
static int idx2dindex(int ifidx, int socket)
{
int i;
struct ifreq ifr;
for (i=0; i < MAXIFNAMES; i++) {
for (i = 0; i < MAXIFNAMES; i++) {
if (dindex[i] == ifidx)
return i;
}
@@ -177,7 +186,7 @@ int idx2dindex(int ifidx, int socket) {
/* create new interface index cache entry */
/* remove index cache zombies first */
for (i=0; i < MAXIFNAMES; i++) {
for (i = 0; i < MAXIFNAMES; i++) {
if (dindex[i]) {
ifr.ifr_ifindex = dindex[i];
if (ioctl(socket, SIOCGIFNAME, &ifr) < 0)
@@ -185,13 +194,13 @@ int idx2dindex(int ifidx, int socket) {
}
}
for (i=0; i < MAXIFNAMES; i++)
for (i = 0; i < MAXIFNAMES; i++)
if (!dindex[i]) /* free entry */
break;
if (i == MAXIFNAMES) {
fprintf(stderr, "Interface index cache only supports %d interfaces.\n",
MAXIFNAMES);
MAXIFNAMES);
exit(1);
}
@@ -213,11 +222,69 @@ int idx2dindex(int ifidx, int socket) {
return i;
}
static inline void sprint_timestamp(const char timestamp, const struct timeval *tv,
struct timeval *const last_tv, char *ts_buffer)
{
switch (timestamp) {
case 'a': /* absolute with timestamp */
sprintf(ts_buffer, "(%010lu.%06lu) ", tv->tv_sec, tv->tv_usec);
break;
case 'A': /* absolute with date */
{
struct tm tm;
char timestring[25];
tm = *localtime(&tv->tv_sec);
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
sprintf(ts_buffer, "(%s.%06lu) ", timestring, tv->tv_usec);
}
break;
case 'd': /* delta */
case 'z': /* starting with zero */
{
struct timeval 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 (diff.tv_sec < 0)
diff.tv_sec = diff.tv_usec = 0;
sprintf(ts_buffer, "(%03lu.%06lu) ", diff.tv_sec, diff.tv_usec);
if (timestamp == 'd')
*last_tv = *tv; /* update for delta calculation */
}
break;
default: /* no timestamp output */
break;
}
}
static inline void print_timestamp(const char timestamp, const struct timeval *tv,
struct timeval *const last_tv)
{
static char buffer[TIMESTAMPSZ];
sprint_timestamp(timestamp, tv, last_tv, buffer);
printf("%s", buffer);
}
int main(int argc, char **argv)
{
fd_set rdfs;
int s[MAXSOCK];
int fd_epoll;
struct epoll_event events_pending[MAXSOCK];
struct epoll_event event_setup = {
.events = EPOLLIN, /* prepare the common part */
};
unsigned char timestamp = 0;
unsigned char logtimestamp = 'a';
unsigned char hwtimestamp = 0;
unsigned char down_causes_exit = 1;
unsigned char dropmonitor = 0;
@@ -230,12 +297,12 @@ int main(int argc, char **argv)
unsigned char logfrmt = 0;
int count = 0;
int rcvbuf_size = 0;
int opt, ret;
int opt, num_events;
int currmax, numfilter;
int join_filter;
char *ptr, *nptr;
struct sockaddr_can addr;
char ctrlmsg[CMSG_SPACE(sizeof(struct timeval) + 3*sizeof(struct timespec) + sizeof(__u32))];
char ctrlmsg[CMSG_SPACE(sizeof(struct timeval) + 3 * sizeof(struct timespec) + sizeof(__u32))];
struct iovec iov;
struct msghdr msg;
struct cmsghdr *cmsg;
@@ -245,26 +312,30 @@ int main(int argc, char **argv)
int nbytes, i, maxdlen;
struct ifreq ifr;
struct timeval tv, last_tv;
struct timeval timeout, timeout_config = { 0, 0 }, *timeout_current = NULL;
int timeout_ms = -1; /* default to no timeout */
FILE *logfile = NULL;
signal(SIGTERM, sigterm);
signal(SIGHUP, sigterm);
signal(SIGINT, sigterm);
last_tv.tv_sec = 0;
last_tv.tv_sec = 0;
last_tv.tv_usec = 0;
while ((opt = getopt(argc, argv, "t:HciaSs:lDdxLn:r:heT:?")) != -1) {
while ((opt = getopt(argc, argv, "t:HciaSs:lDdxLn:r:he8T:?")) != -1) {
switch (opt) {
case 't':
timestamp = optarg[0];
logtimestamp = optarg[0];
if ((timestamp != 'a') && (timestamp != 'A') &&
(timestamp != 'd') && (timestamp != 'z')) {
fprintf(stderr, "%s: unknown timestamp mode '%c' - ignored\n",
basename(argv[0]), optarg[0]);
basename(argv[0]), optarg[0]);
timestamp = 0;
}
if ((logtimestamp != 'a') && (logtimestamp != 'z')) {
logtimestamp = 'a';
}
break;
case 'H':
@@ -291,6 +362,10 @@ int main(int argc, char **argv)
view |= CANLIB_VIEW_ERROR;
break;
case '8':
view |= CANLIB_VIEW_LEN8_DLC;
break;
case 's':
silent = atoi(optarg);
if (silent > SILENT_ON) {
@@ -337,14 +412,11 @@ int main(int argc, char **argv)
case 'T':
errno = 0;
timeout_config.tv_usec = strtol(optarg, NULL, 0);
timeout_ms = strtol(optarg, NULL, 0);
if (errno != 0) {
print_usage(basename(argv[0]));
exit(1);
}
timeout_config.tv_sec = timeout_config.tv_usec / 1000;
timeout_config.tv_usec = (timeout_config.tv_usec % 1000) * 1000;
timeout_current = &timeout;
break;
default:
print_usage(basename(argv[0]));
@@ -357,9 +429,9 @@ int main(int argc, char **argv)
print_usage(basename(argv[0]));
exit(0);
}
if (logfrmt && view) {
fprintf(stderr, "Log file format selected: Please disable ASCII/BINARY/SWAP options!\n");
fprintf(stderr, "Log file format selected: Please disable ASCII/BINARY/SWAP/RAWDLC options!\n");
exit(0);
}
@@ -378,8 +450,14 @@ int main(int argc, char **argv)
return 1;
}
for (i=0; i < currmax; i++) {
fd_epoll = epoll_create(1);
if (fd_epoll < 0) {
perror("epoll_create");
return 1;
}
for (i = 0; i < currmax; i++) {
struct if_info* obj = &sock_info[i];
ptr = argv[optind+i];
nptr = strchr(ptr, ',');
@@ -387,13 +465,19 @@ int main(int argc, char **argv)
printf("open %d '%s'.\n", i, ptr);
#endif
s[i] = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (s[i] < 0) {
obj->s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (obj->s < 0) {
perror("socket");
return 1;
}
cmdlinename[i] = ptr; /* save pointer to cmdline name of this socket */
event_setup.data.ptr = obj; /* remember the instance as private data */
if (epoll_ctl(fd_epoll, EPOLL_CTL_ADD, obj->s, &event_setup)) {
perror("failed to add socket to epoll");
return 1;
}
obj->cmdlinename = ptr; /* save pointer to cmdline name of this socket */
if (nptr)
nbytes = nptr - ptr; /* interface name is up the first ',' */
@@ -418,7 +502,7 @@ int main(int argc, char **argv)
#endif
if (strcmp(ANYDEV, ifr.ifr_name) != 0) {
if (ioctl(s[i], SIOCGIFINDEX, &ifr) < 0) {
if (ioctl(obj->s, SIOCGIFINDEX, &ifr) < 0) {
perror("SIOCGIFINDEX");
exit(1);
}
@@ -451,44 +535,44 @@ int main(int argc, char **argv)
while (nptr) {
ptr = nptr+1; /* hop behind the ',' */
ptr = nptr + 1; /* hop behind the ',' */
nptr = strchr(ptr, ','); /* update exit condition */
if (sscanf(ptr, "%x:%x",
&rfilter[numfilter].can_id,
&rfilter[numfilter].can_id,
&rfilter[numfilter].can_mask) == 2) {
rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG;
if (*(ptr+8) == ':')
rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG;
if (*(ptr + 8) == ':')
rfilter[numfilter].can_id |= CAN_EFF_FLAG;
numfilter++;
} else if (sscanf(ptr, "%x~%x",
&rfilter[numfilter].can_id,
&rfilter[numfilter].can_id,
&rfilter[numfilter].can_mask) == 2) {
rfilter[numfilter].can_id |= CAN_INV_FILTER;
rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG;
if (*(ptr+8) == '~')
rfilter[numfilter].can_id |= CAN_INV_FILTER;
rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG;
if (*(ptr + 8) == '~')
rfilter[numfilter].can_id |= CAN_EFF_FLAG;
numfilter++;
} else if (*ptr == 'j' || *ptr == 'J') {
join_filter = 1;
} else if (sscanf(ptr, "#%x", &err_mask) != 1) {
} else if (sscanf(ptr, "#%x", &err_mask) != 1) {
fprintf(stderr, "Error in filter option parsing: '%s'\n", ptr);
return 1;
}
}
if (err_mask)
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
setsockopt(obj->s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
&err_mask, sizeof(err_mask));
if (join_filter && setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_JOIN_FILTERS,
if (join_filter && setsockopt(obj->s, SOL_CAN_RAW, CAN_RAW_JOIN_FILTERS,
&join_filter, sizeof(join_filter)) < 0) {
perror("setsockopt CAN_RAW_JOIN_FILTERS not supported by your Linux Kernel");
return 1;
}
if (numfilter)
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FILTER,
setsockopt(obj->s, SOL_CAN_RAW, CAN_RAW_FILTER,
rfilter, numfilter * sizeof(struct can_filter));
free(rfilter);
@@ -496,26 +580,25 @@ int main(int argc, char **argv)
} /* if (nptr) */
/* try to switch the socket into CAN FD mode */
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on));
setsockopt(obj->s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on));
if (rcvbuf_size) {
int curr_rcvbuf_size;
socklen_t curr_rcvbuf_size_len = sizeof(curr_rcvbuf_size);
/* try SO_RCVBUFFORCE first, if we run with CAP_NET_ADMIN */
if (setsockopt(s[i], SOL_SOCKET, SO_RCVBUFFORCE,
if (setsockopt(obj->s, SOL_SOCKET, SO_RCVBUFFORCE,
&rcvbuf_size, sizeof(rcvbuf_size)) < 0) {
#ifdef DEBUG
printf("SO_RCVBUFFORCE failed so try SO_RCVBUF ...\n");
#endif
if (setsockopt(s[i], SOL_SOCKET, SO_RCVBUF,
if (setsockopt(obj->s, SOL_SOCKET, SO_RCVBUF,
&rcvbuf_size, sizeof(rcvbuf_size)) < 0) {
perror("setsockopt SO_RCVBUF");
return 1;
}
if (getsockopt(s[i], SOL_SOCKET, SO_RCVBUF,
if (getsockopt(obj->s, SOL_SOCKET, SO_RCVBUF,
&curr_rcvbuf_size, &curr_rcvbuf_size_len) < 0) {
perror("getsockopt SO_RCVBUF");
return 1;
@@ -523,28 +606,27 @@ int main(int argc, char **argv)
/* Only print a warning the first time we detect the adjustment */
/* n.b.: The wanted size is doubled in Linux in net/sore/sock.c */
if (!i && curr_rcvbuf_size < rcvbuf_size*2)
if (!i && curr_rcvbuf_size < rcvbuf_size * 2)
fprintf(stderr, "The socket receive buffer size was "
"adjusted due to /proc/sys/net/core/rmem_max.\n");
}
}
if (timestamp || log || logfrmt) {
if (hwtimestamp) {
const int timestamping_flags = (SOF_TIMESTAMPING_SOFTWARE | \
SOF_TIMESTAMPING_RX_SOFTWARE | \
const int timestamping_flags = (SOF_TIMESTAMPING_SOFTWARE |
SOF_TIMESTAMPING_RX_SOFTWARE |
SOF_TIMESTAMPING_RAW_HARDWARE);
if (setsockopt(s[i], SOL_SOCKET, SO_TIMESTAMPING,
&timestamping_flags, sizeof(timestamping_flags)) < 0) {
if (setsockopt(obj->s, SOL_SOCKET, SO_TIMESTAMPING,
&timestamping_flags, sizeof(timestamping_flags)) < 0) {
perror("setsockopt SO_TIMESTAMPING is not supported by your Linux kernel");
return 1;
}
} else {
const int timestamp_on = 1;
if (setsockopt(s[i], SOL_SOCKET, SO_TIMESTAMP,
if (setsockopt(obj->s, SOL_SOCKET, SO_TIMESTAMP,
&timestamp_on, sizeof(timestamp_on)) < 0) {
perror("setsockopt SO_TIMESTAMP");
return 1;
@@ -553,17 +635,16 @@ int main(int argc, char **argv)
}
if (dropmonitor) {
const int dropmonitor_on = 1;
if (setsockopt(s[i], SOL_SOCKET, SO_RXQ_OVFL,
if (setsockopt(obj->s, SOL_SOCKET, SO_RXQ_OVFL,
&dropmonitor_on, sizeof(dropmonitor_on)) < 0) {
perror("setsockopt SO_RXQ_OVFL not supported by your Linux Kernel");
return 1;
}
}
if (bind(s[i], (struct sockaddr *)&addr, sizeof(addr)) < 0) {
if (bind(obj->s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind");
return 1;
}
@@ -610,205 +691,159 @@ int main(int argc, char **argv)
while (running) {
FD_ZERO(&rdfs);
for (i=0; i<currmax; i++)
FD_SET(s[i], &rdfs);
if (timeout_current)
*timeout_current = timeout_config;
if ((ret = select(s[currmax-1]+1, &rdfs, NULL, NULL, timeout_current)) <= 0) {
//perror("select");
if ((num_events = epoll_wait(fd_epoll, events_pending, currmax, timeout_ms)) <= 0) {
//perror("epoll_wait");
running = 0;
continue;
}
for (i=0; i<currmax; i++) { /* check all CAN RAW sockets */
for (i = 0; i < num_events; i++) { /* check waiting CAN RAW sockets */
struct if_info* obj = events_pending[i].data.ptr;
int idx;
char *extra_info = "";
if (FD_ISSET(s[i], &rdfs)) {
/* these settings may be modified by recvmsg() */
iov.iov_len = sizeof(frame);
msg.msg_namelen = sizeof(addr);
msg.msg_controllen = sizeof(ctrlmsg);
msg.msg_flags = 0;
int idx;
char *extra_info = "";
nbytes = recvmsg(obj->s, &msg, 0);
idx = idx2dindex(addr.can_ifindex, obj->s);
/* these settings may be modified by recvmsg() */
iov.iov_len = sizeof(frame);
msg.msg_namelen = sizeof(addr);
msg.msg_controllen = sizeof(ctrlmsg);
msg.msg_flags = 0;
nbytes = recvmsg(s[i], &msg, 0);
idx = idx2dindex(addr.can_ifindex, s[i]);
if (nbytes < 0) {
if ((errno == ENETDOWN) && !down_causes_exit) {
fprintf(stderr, "%s: interface down\n", devname[idx]);
continue;
}
perror("read");
return 1;
if (nbytes < 0) {
if ((errno == ENETDOWN) && !down_causes_exit) {
fprintf(stderr, "%s: interface down\n", devname[idx]);
continue;
}
if ((size_t)nbytes == CAN_MTU)
maxdlen = CAN_MAX_DLEN;
else if ((size_t)nbytes == CANFD_MTU)
maxdlen = CANFD_MAX_DLEN;
else {
fprintf(stderr, "read: incomplete CAN frame\n");
return 1;
}
if (count && (--count == 0))
running = 0;
for (cmsg = CMSG_FIRSTHDR(&msg);
cmsg && (cmsg->cmsg_level == SOL_SOCKET);
cmsg = CMSG_NXTHDR(&msg,cmsg)) {
if (cmsg->cmsg_type == SO_TIMESTAMP) {
memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
} else if (cmsg->cmsg_type == SO_TIMESTAMPING) {
struct timespec *stamp = (struct timespec *)CMSG_DATA(cmsg);
/*
* stamp[0] is the software timestamp
* stamp[1] is deprecated
* stamp[2] is the raw hardware timestamp
* 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;
} else if (cmsg->cmsg_type == SO_RXQ_OVFL)
memcpy(&dropcnt[i], CMSG_DATA(cmsg), sizeof(__u32));
}
/* check for (unlikely) dropped frames on this specific socket */
if (dropcnt[i] != last_dropcnt[i]) {
__u32 frames = dropcnt[i] - last_dropcnt[i];
if (silent != SILENT_ON)
printf("DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
frames, (frames > 1)?"s":"", devname[idx], dropcnt[i]);
if (log)
fprintf(logfile, "DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
frames, (frames > 1)?"s":"", devname[idx], dropcnt[i]);
last_dropcnt[i] = dropcnt[i];
}
/* once we detected a EFF frame indent SFF frames accordingly */
if (frame.can_id & CAN_EFF_FLAG)
view |= CANLIB_VIEW_INDENT_SFF;
if (extra_msg_info) {
if (msg.msg_flags & MSG_DONTROUTE)
extra_info = " T";
else
extra_info = " R";
}
if (log) {
char buf[CL_CFSZ]; /* max length */
/* log CAN frame with absolute timestamp & device */
sprint_canframe(buf, &frame, 0, maxdlen);
fprintf(logfile, "(%010lu.%06lu) %*s %s%s\n",
tv.tv_sec, tv.tv_usec,
max_devname_len, devname[idx], buf,
extra_info);
}
if ((logfrmt) && (silent == SILENT_OFF)){
char buf[CL_CFSZ]; /* max length */
/* print CAN frame in log file style to stdout */
sprint_canframe(buf, &frame, 0, maxdlen);
printf("(%010lu.%06lu) %*s %s%s\n",
tv.tv_sec, tv.tv_usec,
max_devname_len, devname[idx], buf,
extra_info);
goto out_fflush; /* no other output to stdout */
}
if (silent != SILENT_OFF){
if (silent == SILENT_ANI) {
printf("%c\b", anichar[silentani%=MAXANI]);
silentani++;
}
goto out_fflush; /* no other output to stdout */
}
printf(" %s", (color>2)?col_on[idx%MAXCOL]:"");
switch (timestamp) {
case 'a': /* absolute with timestamp */
printf("(%010lu.%06lu) ", tv.tv_sec, tv.tv_usec);
break;
case 'A': /* absolute with date */
{
struct tm tm;
char timestring[25];
tm = *localtime(&tv.tv_sec);
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
printf("(%s.%06lu) ", timestring, tv.tv_usec);
}
break;
case 'd': /* delta */
case 'z': /* starting with zero */
{
struct timeval 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 (diff.tv_sec < 0)
diff.tv_sec = diff.tv_usec = 0;
printf("(%03lu.%06lu) ", diff.tv_sec, diff.tv_usec);
if (timestamp == 'd')
last_tv = tv; /* update for delta calculation */
}
break;
default: /* no timestamp output */
break;
}
printf(" %s", (color && (color<3))?col_on[idx%MAXCOL]:"");
printf("%*s", max_devname_len, devname[idx]);
if (extra_msg_info) {
if (msg.msg_flags & MSG_DONTROUTE)
printf (" TX %s", extra_m_info[frame.flags & 3]);
else
printf (" RX %s", extra_m_info[frame.flags & 3]);
}
printf("%s ", (color==1)?col_off:"");
fprint_long_canframe(stdout, &frame, NULL, view, maxdlen);
printf("%s", (color>1)?col_off:"");
printf("\n");
perror("read");
return 1;
}
out_fflush:
if ((size_t)nbytes == CAN_MTU)
maxdlen = CAN_MAX_DLEN;
else if ((size_t)nbytes == CANFD_MTU)
maxdlen = CANFD_MAX_DLEN;
else {
fprintf(stderr, "read: incomplete CAN frame\n");
return 1;
}
if (count && (--count == 0))
running = 0;
for (cmsg = CMSG_FIRSTHDR(&msg);
cmsg && (cmsg->cmsg_level == SOL_SOCKET);
cmsg = CMSG_NXTHDR(&msg,cmsg)) {
if (cmsg->cmsg_type == SO_TIMESTAMP) {
memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
} else if (cmsg->cmsg_type == SO_TIMESTAMPING) {
struct timespec *stamp = (struct timespec *)CMSG_DATA(cmsg);
/*
* stamp[0] is the software timestamp
* stamp[1] is deprecated
* stamp[2] is the raw hardware timestamp
* 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;
} else if (cmsg->cmsg_type == SO_RXQ_OVFL)
memcpy(&obj->dropcnt, CMSG_DATA(cmsg), sizeof(__u32));
}
/* check for (unlikely) dropped frames on this specific socket */
if (obj->dropcnt != obj->last_dropcnt) {
__u32 frames = obj->dropcnt - obj->last_dropcnt;
if (silent != SILENT_ON)
printf("DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
frames, (frames > 1)?"s":"", devname[idx], obj->dropcnt);
if (log)
fprintf(logfile, "DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
frames, (frames > 1)?"s":"", devname[idx], obj->dropcnt);
obj->last_dropcnt = obj->dropcnt;
}
/* once we detected a EFF frame indent SFF frames accordingly */
if (frame.can_id & CAN_EFF_FLAG)
view |= CANLIB_VIEW_INDENT_SFF;
if (extra_msg_info) {
if (msg.msg_flags & MSG_DONTROUTE)
extra_info = " T";
else
extra_info = " R";
}
if (log) {
char buf[CL_CFSZ]; /* max length */
char ts_buf[TIMESTAMPSZ];
sprint_timestamp(logtimestamp, &tv, &last_tv, ts_buf);
/* log CAN frame with absolute timestamp & device */
sprint_canframe(buf, &frame, 0, maxdlen);
fprintf(logfile, "%s%*s %s%s\n", ts_buf,
max_devname_len, devname[idx], buf,
extra_info);
}
if ((logfrmt) && (silent == SILENT_OFF)){
char buf[CL_CFSZ]; /* max length */
/* print CAN frame in log file style to stdout */
sprint_canframe(buf, &frame, 0, maxdlen);
print_timestamp(logtimestamp, &tv, &last_tv);
printf("%*s %s%s\n",
max_devname_len, devname[idx], buf,
extra_info);
goto out_fflush; /* no other output to stdout */
}
if (silent != SILENT_OFF){
if (silent == SILENT_ANI) {
printf("%c\b", anichar[silentani %= MAXANI]);
silentani++;
}
goto out_fflush; /* no other output to stdout */
}
printf(" %s", (color > 2) ? col_on[idx % MAXCOL] : "");
print_timestamp(timestamp, &tv, &last_tv);
printf(" %s", (color && (color < 3)) ? col_on[idx % MAXCOL] : "");
printf("%*s", max_devname_len, devname[idx]);
if (extra_msg_info) {
if (msg.msg_flags & MSG_DONTROUTE)
printf (" TX %s", extra_m_info[frame.flags & 3]);
else
printf (" RX %s", extra_m_info[frame.flags & 3]);
}
printf("%s ", (color == 1) ? col_off : "");
fprint_long_canframe(stdout, &frame, NULL, view, maxdlen);
printf("%s", (color > 1) ? col_off : "");
printf("\n");
out_fflush:
fflush(stdout);
}
}
for (i=0; i<currmax; i++)
close(s[i]);
for (i = 0; i < currmax; i++)
close(sock_info[i].s);
close(fd_epoll);
if (log)
fclose(logfile);
+46 -15
View File
@@ -92,7 +92,8 @@ void print_usage(char *prg)
" with bitrate switch (BRS))\n");
fprintf(stderr, " -E (generate CAN FD CAN frames"
" with error state (ESI))\n");
fprintf(stderr, " -R (send RTR frame)\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 frames)\n");
fprintf(stderr, " -I <mode> (CAN ID"
" generation mode - see below)\n");
@@ -113,9 +114,9 @@ void print_usage(char *prg)
fprintf(stderr, " -v (increment verbose level for "
"printing sent CAN frames)\n\n");
fprintf(stderr, "Generation modes:\n");
fprintf(stderr, " 'r' => random values (default)\n");
fprintf(stderr, " 'i' => increment values\n");
fprintf(stderr, " <hexvalue> => fix value using <hexvalue>\n\n");
fprintf(stderr, " 'r' => random values (default)\n");
fprintf(stderr, " 'i' => increment values\n");
fprintf(stderr, " <value> => fixed value (in hexadecimal for -I and -D)\n\n");
fprintf(stderr, "When incrementing the CAN data the data length code "
"minimum is set to 1.\n");
fprintf(stderr, "CAN IDs and data content are given and expected in hexadecimal values.\n\n");
@@ -156,6 +157,7 @@ int main(int argc, char **argv)
unsigned char loopback_disable = 0;
unsigned char verbose = 0;
unsigned char rtr_frame = 0;
unsigned char len8_dlc = 0;
int count = 0;
unsigned long burst_sent_count = 0;
int mtu, maxdlen;
@@ -170,6 +172,7 @@ int main(int argc, char **argv)
struct sockaddr_can addr;
static struct canfd_frame frame;
struct can_frame *ccf = (struct can_frame *)&frame;
int nbytes;
int i;
struct ifreq ifr;
@@ -185,7 +188,7 @@ int main(int argc, char **argv)
signal(SIGHUP, sigterm);
signal(SIGINT, sigterm);
while ((opt = getopt(argc, argv, "ig:ebEfmI:L:D:xp:n:c:vRh?")) != -1) {
while ((opt = getopt(argc, argv, "ig:ebEfmI:L:D:xp:n:c:vR8h?")) != -1) {
switch (opt) {
case 'i':
@@ -271,6 +274,10 @@ int main(int argc, char **argv)
rtr_frame = 1;
break;
case '8':
len8_dlc = 1;
break;
case 'p':
polltimeout = strtoul(optarg, NULL, 10);
break;
@@ -360,11 +367,19 @@ int main(int argc, char **argv)
}
/* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */
frame.len = can_dlc2len(can_len2dlc(frame.len));
frame.len = can_fd_dlc2len(can_fd_len2dlc(frame.len));
} else {
/* sanitize CAN 2.0 frame length */
if (frame.len > 8)
frame.len = 8;
/* sanitize Classical CAN 2.0 frame length */
if (len8_dlc) {
if (frame.len > CAN_MAX_RAW_DLC)
frame.len = CAN_MAX_RAW_DLC;
if (frame.len > CAN_MAX_DLEN)
ccf->len8_dlc = frame.len;
}
if (frame.len > CAN_MAX_DLEN)
frame.len = CAN_MAX_DLEN;
}
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
@@ -410,11 +425,19 @@ int main(int argc, char **argv)
if (dlc_mode == MODE_RANDOM) {
if (canfd)
frame.len = can_dlc2len(random() & 0xF);
frame.len = can_fd_dlc2len(random() & 0xF);
else {
frame.len = random() & 0xF;
if (frame.len & 8)
if (frame.len > CAN_MAX_DLEN) {
/* generate Classic CAN len8 DLCs? */
if (len8_dlc)
ccf->len8_dlc = frame.len;
frame.len = 8; /* for about 50% of the frames */
} else {
ccf->len8_dlc = 0;
}
}
}
@@ -493,12 +516,20 @@ resend:
if (dlc_mode == MODE_INCREMENT) {
incdlc++;
incdlc %= CAN_MAX_RAW_DLC + 1;
if (canfd && !mix) {
incdlc &= 0xF;
frame.len = can_dlc2len(incdlc);
if (canfd && !mix)
frame.len = can_fd_dlc2len(incdlc);
else if (len8_dlc) {
if (incdlc > CAN_MAX_DLEN) {
frame.len = CAN_MAX_DLEN;
ccf->len8_dlc = incdlc;
} else {
frame.len = incdlc;
ccf->len8_dlc = 0;
}
} else {
incdlc %= 9;
incdlc %= CAN_MAX_DLEN + 1;
frame.len = incdlc;
}
}
+4 -4
View File
@@ -240,7 +240,7 @@ void print_usage(char *prg)
fprintf(stderr, " -u <uid> (user defined modification identifier)\n");
fprintf(stderr, " -l <hops> (limit the number of frame hops / routings)\n");
fprintf(stderr, " -f <filter> (set CAN filter)\n");
fprintf(stderr, " -m <mod> (set Classic CAN frame modifications)\n");
fprintf(stderr, " -m <mod> (set Classical CAN frame modifications)\n");
fprintf(stderr, " -M <MOD> (set CAN FD frame modifications)\n");
fprintf(stderr, " -x <from_idx>:<to_idx>:<result_idx>:<init_xor_val> (XOR checksum)\n");
fprintf(stderr, " -c <from>:<to>:<result>:<init_val>:<xor_val>:<crctab[256]> (CRC8 cs)\n");
@@ -251,12 +251,12 @@ void print_usage(char *prg)
fprintf(stderr, " <can_id>:<can_mask> (matches when <received_can_id> & mask == can_id & mask)\n");
fprintf(stderr, " <can_id>~<can_mask> (matches when <received_can_id> & mask != can_id & mask)\n");
fprintf(stderr, "\n");
fprintf(stderr, "<mod> is a CAN frame modification instruction consisting of\n");
fprintf(stderr, "<mod> is a Classical CAN frame modification instruction consisting of\n");
fprintf(stderr, "<instruction>:<can_frame-elements>:<can_id>.<can_dlc>.<can_data>\n");
fprintf(stderr, " <instruction> is one of 'AND' 'OR' 'XOR' 'SET'\n");
fprintf(stderr, " <can_frame-elements> is _one_ or _more_ of 'I'dentifier 'L'ength 'D'ata\n");
fprintf(stderr, " <can_id> is an u32 value containing the CAN Identifier\n");
fprintf(stderr, " <can_dlc> is an u8 value containing the data length code (0 .. 8)\n");
fprintf(stderr, " <can_dlc> is an u8 value containing the data length code in hex (0 .. F)\n");
fprintf(stderr, " <can_data> is always eight(!) u8 values containing the CAN frames data\n");
fprintf(stderr, "\n");
fprintf(stderr, "<MOD> is a CAN FD frame modification instruction consisting of\n");
@@ -265,7 +265,7 @@ void print_usage(char *prg)
fprintf(stderr, " <canfd_frame-elements> is _one_ or _more_ of 'I'd 'F'lags 'L'ength 'D'ata\n");
fprintf(stderr, " <can_id> is an u32 value containing the CAN FD Identifier\n");
fprintf(stderr, " <flags> is an u8 value containing CAN FD flags (CANFD_BRS, CANFD_ESI)\n");
fprintf(stderr, " <len> is an u8 value containing the data length (0 .. 64)\n");
fprintf(stderr, " <len> is an u8 value containing the data length in hex (0 .. 40)\n");
fprintf(stderr, " <can_data> is always 64(!) u8 values containing the CAN FD frames data\n");
fprintf(stderr, "The max. four modifications are performed in the order AND -> OR -> XOR -> SET\n");
fprintf(stderr, "\n");
+1 -1
View File
@@ -162,7 +162,7 @@ void childdied(int i)
}
/*
* This is a Signalhandler for a cought SIGTERM
* This is a Signalhandler for a caught SIGTERM
*/
void shutdown_gra(int i)
{
+8 -4
View File
@@ -61,8 +61,10 @@ void print_usage(char *prg)
fprintf(stderr, "%s - send CAN-frames via CAN_RAW sockets.\n", prg);
fprintf(stderr, "\nUsage: %s <device> <can_frame>.\n", prg);
fprintf(stderr, "\n<can_frame>:\n");
fprintf(stderr, " <can_id>#{data} for 'classic' CAN 2.0 data frames\n");
fprintf(stderr, " <can_id>#R{len} for 'classic' CAN 2.0 data frames\n");
fprintf(stderr, " <can_id>#{data} for Classical CAN 2.0 data frames\n");
fprintf(stderr, " <can_id>#R{len} for Classical CAN 2.0 data frames\n");
fprintf(stderr, " <can_id>#{data}_{dlc} for Classical CAN 2.0 data frames\n");
fprintf(stderr, " <can_id>#R{len}_{dlc} for Classical CAN 2.0 data frames\n");
fprintf(stderr, " <can_id>##<flags>{data} for CAN FD frames\n\n");
fprintf(stderr, "<can_id>:\n"
" 3 (SFF) or 8 (EFF) hex chars\n");
@@ -70,11 +72,13 @@ void print_usage(char *prg)
" 0..8 (0..64 CAN FD) ASCII hex-values (optionally separated by '.')\n");
fprintf(stderr, "{len}:\n"
" an optional 0..8 value as RTR frames can contain a valid dlc field\n");
fprintf(stderr, "_{dlc}:\n"
" an optional 9..F data length code value when payload length is 8\n");
fprintf(stderr, "<flags>:\n"
" a single ASCII Hex value (0 .. F) which defines canfd_frame.flags\n\n");
fprintf(stderr, "Examples:\n");
fprintf(stderr, " 5A1#11.2233.44556677.88 / 123#DEADBEEF / 5AA# / 123##1 / 213##311223344 /\n"
" 1F334455#1122334455667788 / 123#R / 00000123#R3\n\n");
" 1F334455#1122334455667788_B / 123#R / 00000123#R3 / 333#R8_E\n\n");
}
@@ -143,7 +147,7 @@ int main(int argc, char **argv)
}
/* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */
frame.len = can_dlc2len(can_len2dlc(frame.len));
frame.len = can_fd_dlc2len(can_fd_len2dlc(frame.len));
}
/* disable default receive filter on this RAW socket */
+1 -1
View File
@@ -844,7 +844,7 @@ int sniftab_index(canid_t id)
{
int i;
for (i = 0; i <= idx; i++)
for (i = 0; i < idx; i++)
if (id == sniftab[i].current.can_id)
return i;
+24 -14
View File
@@ -84,6 +84,7 @@ typedef __u32 can_err_mask_t;
/* CAN payload length and DLC definitions according to ISO 11898-1 */
#define CAN_MAX_DLC 8
#define CAN_MAX_RAW_DLC 15
#define CAN_MAX_DLEN 8
/* CAN FD payload length and DLC definitions according to ISO 11898-7 */
@@ -91,23 +92,32 @@ typedef __u32 can_err_mask_t;
#define CANFD_MAX_DLEN 64
/**
* struct can_frame - basic CAN frame structure
* @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
* @can_dlc: frame payload length in byte (0 .. 8) aka data length code
* N.B. the DLC field from ISO 11898-1 Chapter 8.4.2.3 has a 1:1
* mapping of the 'data length code' to the real payload length
* @__pad: padding
* @__res0: reserved / padding
* @__res1: reserved / padding
* @data: CAN frame payload (up to 8 byte)
* struct can_frame - Classical CAN frame structure (aka CAN 2.0B)
* @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
* @len: CAN frame payload length in byte (0 .. 8)
* @can_dlc: deprecated name for CAN frame payload length in byte (0 .. 8)
* @__pad: padding
* @__res0: reserved / padding
* @len8_dlc: optional DLC value (9 .. 15) at 8 byte payload length
* len8_dlc contains values from 9 .. 15 when the payload length is
* 8 bytes but the DLC value (see ISO 11898-1) is greater then 8.
* CAN_CTRLMODE_CC_LEN8_DLC flag has to be enabled in CAN driver.
* @data: CAN frame payload (up to 8 byte)
*/
struct can_frame {
canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
__u8 can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */
__u8 __pad; /* padding */
__u8 __res0; /* reserved / padding */
__u8 __res1; /* reserved / padding */
__u8 data[CAN_MAX_DLEN] __attribute__((aligned(8)));
union {
/* CAN frame payload length in byte (0 .. CAN_MAX_DLEN)
* was previously named can_dlc so we need to carry that
* name for legacy support
*/
__u8 len;
__u8 can_dlc; /* deprecated */
};
__u8 __pad; /* padding */
__u8 __res0; /* reserved / padding */
__u8 len8_dlc; /* optional DLC for 8 byte payload length (9 .. 15) */
__u8 data[CAN_MAX_DLEN] __attribute__((aligned(8)));
};
/*
+2 -2
View File
@@ -98,8 +98,8 @@ enum {
/* CAN frame elements that are affected by curr. 3 CAN frame modifications */
#define CGW_MOD_ID 0x01
#define CGW_MOD_DLC 0x02 /* contains the data length in bytes */
#define CGW_MOD_LEN CGW_MOD_DLC /* CAN FD length representation */
#define CGW_MOD_DLC 0x02 /* Classical CAN data length code */
#define CGW_MOD_LEN CGW_MOD_DLC /* CAN FD (plain) data length */
#define CGW_MOD_DATA 0x04
#define CGW_MOD_FLAGS 0x08 /* CAN FD flags */
+1 -1
View File
@@ -135,7 +135,7 @@ struct can_isotp_ll_options {
#define CAN_ISOTP_FORCE_RXSTMIN 0x100 /* ignore CFs depending on rx stmin */
#define CAN_ISOTP_RX_EXT_ADDR 0x200 /* different rx extended addressing */
#define CAN_ISOTP_WAIT_TX_DONE 0x400 /* wait for tx completion */
#define CAN_ISOTP_SF_BROADCAST 0x800 /* 1-to-N functional addressing */
/* default values */
+1
View File
@@ -100,6 +100,7 @@ struct can_ctrlmode {
#define CAN_CTRLMODE_FD 0x20 /* CAN FD mode */
#define CAN_CTRLMODE_PRESUME_ACK 0x40 /* Ignore missing CAN ACKs */
#define CAN_CTRLMODE_FD_NON_ISO 0x80 /* CAN FD in non-ISO mode */
#define CAN_CTRLMODE_CC_LEN8_DLC 0x100 /* Classic CAN DLC option */
/*
* CAN device statistics
+8 -2
View File
@@ -72,6 +72,7 @@ void print_usage(char *prg)
fprintf(stderr, " -f <time ns> (ignore FC and force local tx stmin value in nanosecs)\n");
fprintf(stderr, " -D <len> (send a fixed PDU with len bytes - no STDIN data)\n");
fprintf(stderr, " -b (block until the PDU transmission is completed)\n");
fprintf(stderr, " -S (SF broadcast mode for functional addressing)\n");
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
fprintf(stderr, "The pdu data is expected on STDIN in space separated ASCII hex values.\n");
@@ -94,7 +95,7 @@ int main(int argc, char **argv)
addr.can_addr.tp.tx_id = addr.can_addr.tp.rx_id = NO_CAN_ID;
while ((opt = getopt(argc, argv, "s:d:x:p:P:t:f:D:bL:?")) != -1) {
while ((opt = getopt(argc, argv, "s:d:x:p:P:t:f:D:bSL:?")) != -1) {
switch (opt) {
case 's':
addr.can_addr.tp.tx_id = strtoul(optarg, (char **)NULL, 16);
@@ -181,6 +182,10 @@ int main(int argc, char **argv)
opts.flags |= CAN_ISOTP_WAIT_TX_DONE;
break;
case 'S':
opts.flags |= CAN_ISOTP_SF_BROADCAST;
break;
case 'L':
if (sscanf(optarg, "%hhu:%hhu:%hhu",
&llopts.mtu,
@@ -207,7 +212,8 @@ int main(int argc, char **argv)
if ((argc - optind != 1) ||
(addr.can_addr.tp.tx_id == NO_CAN_ID) ||
(addr.can_addr.tp.rx_id == NO_CAN_ID)) {
((addr.can_addr.tp.rx_id == NO_CAN_ID) &&
(!(opts.flags & CAN_ISOTP_SF_BROADCAST)))) {
print_usage(basename(argv[0]));
exit(1);
}
+1
View File
@@ -13,6 +13,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <linux/errqueue.h>
+67 -9
View File
@@ -53,6 +53,7 @@
#include "lib.h"
#define CANID_DELIM '#'
#define CC_DLC_DELIM '_'
#define DATA_SEPERATOR '.'
const char hex_asc_upper[] = "0123456789ABCDEF";
@@ -83,10 +84,10 @@ static inline void _put_id(char *buf, int end_offset, canid_t id)
static const unsigned char dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
8, 12, 16, 20, 24, 32, 48, 64};
/* get data length from can_dlc with sanitized can_dlc */
unsigned char can_dlc2len(unsigned char can_dlc)
/* get data length from raw data length code (DLC) */
unsigned char can_fd_dlc2len(unsigned char dlc)
{
return dlc2len[can_dlc & 0x0F];
return dlc2len[dlc & 0x0F];
}
static const unsigned char len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
@@ -101,7 +102,7 @@ static const unsigned char len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
15, 15, 15, 15, 15, 15, 15, 15}; /* 57 - 64 */
/* map the sanitized data length to an appropriate data length code */
unsigned char can_len2dlc(unsigned char len)
unsigned char can_fd_len2dlc(unsigned char len)
{
if (len > 64)
return 0xF;
@@ -195,9 +196,19 @@ int parse_canframe(char *cs, struct canfd_frame *cf) {
cf->can_id |= CAN_RTR_FLAG;
/* check for optional DLC value for CAN 2.0B frames */
if(cs[++idx] && (tmp = asc2nibble(cs[idx])) <= CAN_MAX_DLC)
if(cs[++idx] && (tmp = asc2nibble(cs[idx++])) <= CAN_MAX_DLEN) {
cf->len = tmp;
/* check for optional raw DLC value for CAN 2.0B frames */
if ((tmp == CAN_MAX_DLEN) && (cs[idx++] == CC_DLC_DELIM)) {
tmp = asc2nibble(cs[idx]);
if ((tmp > CAN_MAX_DLEN) && (tmp <= CAN_MAX_RAW_DLC)) {
struct can_frame *ccf = (struct can_frame *)cf;
ccf->len8_dlc = tmp;
}
}
}
return ret;
}
@@ -232,6 +243,17 @@ int parse_canframe(char *cs, struct canfd_frame *cf) {
}
cf->len = dlen;
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
if ((maxdlen == CAN_MAX_DLEN) && (dlen == CAN_MAX_DLEN) && (cs[idx++] == CC_DLC_DELIM)) {
unsigned char dlc = asc2nibble(cs[idx]);
if ((dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC)) {
struct can_frame *ccf = (struct can_frame *)cf;
ccf->len8_dlc = dlc;
}
}
return ret;
}
@@ -270,9 +292,20 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen) {
if (maxdlen == CAN_MAX_DLEN && cf->can_id & CAN_RTR_FLAG) {
buf[offset++] = 'R';
/* print a given CAN 2.0B DLC if it's not zero */
if (cf->len && cf->len <= CAN_MAX_DLC)
if (cf->len && cf->len <= CAN_MAX_DLEN) {
buf[offset++] = hex_asc_upper_lo(cf->len);
/* check for optional raw DLC value for CAN 2.0B frames */
if (cf->len == CAN_MAX_DLEN) {
struct can_frame *ccf = (struct can_frame *)cf;
if ((ccf->len8_dlc > CAN_MAX_DLEN) && (ccf->len8_dlc <= CAN_MAX_RAW_DLC)) {
buf[offset++] = CC_DLC_DELIM;
buf[offset++] = hex_asc_upper_lo(ccf->len8_dlc);
}
}
}
buf[offset] = 0;
return;
}
@@ -292,6 +325,17 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen) {
buf[offset++] = '.';
}
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
if ((maxdlen == CAN_MAX_DLEN) && (len == CAN_MAX_DLEN)) {
struct can_frame *ccf = (struct can_frame *)cf;
unsigned char dlc = ccf->len8_dlc;
if ((dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC)) {
buf[offset++] = CC_DLC_DELIM;
buf[offset++] = hex_asc_upper_lo(dlc);
}
}
buf[offset] = 0;
}
@@ -337,9 +381,23 @@ void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxd
/* The len value is sanitized by maxdlen (see above) */
if (maxdlen == CAN_MAX_DLEN) {
buf[offset + 1] = '[';
buf[offset + 2] = len + '0';
buf[offset + 3] = ']';
if (view & CANLIB_VIEW_LEN8_DLC) {
struct can_frame *ccf = (struct can_frame *)cf;
unsigned char dlc = ccf->len8_dlc;
/* fall back to len if we don't have a valid DLC > 8 */
if (!((len == CAN_MAX_DLEN) && (dlc > CAN_MAX_DLEN) &&
(dlc <= CAN_MAX_RAW_DLC)))
dlc = len;
buf[offset + 1] = '{';
buf[offset + 2] = hex_asc_upper[dlc];
buf[offset + 3] = '}';
} else {
buf[offset + 1] = '[';
buf[offset + 2] = len + '0';
buf[offset + 3] = ']';
}
/* standard CAN frames may have RTR enabled */
if (cf->can_id & CAN_RTR_FLAG) {
+16 -10
View File
@@ -61,11 +61,11 @@
/* CAN DLC to real data length conversion helpers especially for CAN FD */
/* get data length from can_dlc with sanitized can_dlc */
unsigned char can_dlc2len(unsigned char can_dlc);
/* get data length from raw data length code (DLC) */
unsigned char can_fd_dlc2len(unsigned char dlc);
/* map the sanitized data length to an appropriate data length code */
unsigned char can_len2dlc(unsigned char len);
unsigned char can_fd_len2dlc(unsigned char len);
unsigned char asc2nibble(char c);
/*
@@ -99,10 +99,11 @@ int parse_canframe(char *cs, struct canfd_frame *cf);
/*
* Transfers a valid ASCII string describing a CAN frame into struct canfd_frame.
*
* CAN 2.0 frames
* - string layout <can_id>#{R{len}|data}
* CAN 2.0 frames (aka Classical CAN)
* - string layout <can_id>#{R{len}|data}{_len8_dlc}
* - {data} has 0 to 8 hex-values that can (optionally) be separated by '.'
* - {len} can take values from 0 to 8 and can be omitted if zero
* - {_len8_dlc} can take hex values from '_9' to '_F' when len is CAN_MAX_DLEN
* - return value on successful parsing: CAN_MTU
*
* CAN FD frames
@@ -124,10 +125,12 @@ int parse_canframe(char *cs, struct canfd_frame *cf);
* 123#R -> standard CAN-Id = 0x123, len = 0, RTR-frame
* 123#R0 -> standard CAN-Id = 0x123, len = 0, RTR-frame
* 123#R7 -> standard CAN-Id = 0x123, len = 7, RTR-frame
* 123#R8_9 -> standard CAN-Id = 0x123, len = 8, dlc = 9, RTR-frame
* 7A1#r -> standard CAN-Id = 0x7A1, len = 0, RTR-frame
*
* 123#00 -> standard CAN-Id = 0x123, len = 1, data[0] = 0x00
* 123#1122334455667788 -> standard CAN-Id = 0x123, len = 8
* 123#1122334455667788_E -> standard CAN-Id = 0x123, len = 8, dlc = 14
* 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, len = 8
* 123#11.2233.44556677.88 -> standard CAN-Id = 0x123, len = 8
* 32345678#112233 -> error frame with CAN_ERR_FLAG (0x2000000) set
@@ -155,10 +158,11 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen);
* The CAN data[] is separated by '.' when sep != 0.
*
* The type of the CAN frame (CAN 2.0 / CAN FD) is specified by maxdlen:
* maxdlen = 8 -> CAN2.0 frame
* maxdlen = 8 -> CAN2.0 frame (aka Classical CAN)
* maxdlen = 64 -> CAN FD frame
*
* 12345678#112233 -> extended CAN-Id = 0x12345678, len = 3, data, sep = 0
* 123#1122334455667788_E -> standard CAN-Id = 0x123, len = 8, dlc = 14, data, sep = 0
* 12345678#R -> extended CAN-Id = 0x12345678, RTR, len = 0
* 12345678#R5 -> extended CAN-Id = 0x12345678, RTR, len = 5
* 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, dlc = 8, sep = 1
@@ -178,6 +182,7 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen);
#define CANLIB_VIEW_SWAP 0x4
#define CANLIB_VIEW_ERROR 0x8
#define CANLIB_VIEW_INDENT_SFF 0x10
#define CANLIB_VIEW_LEN8_DLC 0x20
#define SWAP_DELIMITER '`'
@@ -187,14 +192,15 @@ void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxd
* Creates a CAN frame hexadecimal output in user readable format.
*
* The type of the CAN frame (CAN 2.0 / CAN FD) is specified by maxdlen:
* maxdlen = 8 -> CAN2.0 frame
* maxdlen = 8 -> CAN2.0 frame (aka Classical CAN)
* maxdlen = 64 -> CAN FD frame
*
* 12345678 [3] 11 22 33 -> extended CAN-Id = 0x12345678, dlc = 3, data
* 12345678 [3] 11 22 33 -> extended CAN-Id = 0x12345678, len = 3, data
* 12345678 [0] remote request -> extended CAN-Id = 0x12345678, RTR
* 14B0DC51 [8] 4A 94 E8 2A EC 58 55 62 'J..*.XUb' -> (with ASCII output)
* 321 {B} 11 22 33 44 55 66 77 88 -> Classical CAN with raw '{DLC}' value B
* 20001111 [7] C6 23 7B 32 69 98 3C ERRORFRAME -> (CAN_ERR_FLAG set)
* 12345678 [03] 11 22 33 -> CAN FD with extended CAN-Id = 0x12345678, dlc = 3
* 12345678 [03] 11 22 33 -> CAN FD with extended CAN-Id = 0x12345678, len = 3
*
* 123 [3] 11 22 33 -> CANLIB_VIEW_INDENT_SFF == 0
* 123 [3] 11 22 33 -> CANLIB_VIEW_INDENT_SFF == set
@@ -204,7 +210,7 @@ void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxd
* // CAN FD frame with eol to STDOUT
* fprint_long_canframe(stdout, &frame, "\n", 0, CANFD_MAX_DLEN);
*
* // CAN 2.0 frame without eol to STDERR
* // Classical CAN 2.0 frame without eol to STDERR
* fprint_long_canframe(stderr, &frame, NULL, 0, CAN_MAX_DLEN);
*
*/
+11 -1
View File
@@ -116,6 +116,7 @@ void canfd_asc(struct canfd_frame *cf, int devno, int mtu, char *extra_info, FIL
char *dir = "Rx";
unsigned int flags = 0;
unsigned int dlen = cf->len;
unsigned int dlc = can_fd_len2dlc(dlen);
/* relevant flags in Flags field */
#define ASC_F_RTR 0x00000010
@@ -137,7 +138,16 @@ void canfd_asc(struct canfd_frame *cf, int devno, int mtu, char *extra_info, FIL
fprintf(outfile, "%11s ", id);
fprintf(outfile, "%c ", (cf->flags & CANFD_BRS)?'1':'0');
fprintf(outfile, "%c ", (cf->flags & CANFD_ESI)?'1':'0');
fprintf(outfile, "%x ", can_len2dlc(dlen));
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
if ((mtu == CAN_MTU) && (dlen == CAN_MAX_DLEN)) {
struct can_frame *ccf = (struct can_frame *)cf;
if ((ccf->len8_dlc > CAN_MAX_DLEN) && (ccf->len8_dlc <= CAN_MAX_RAW_DLC))
dlc = ccf->len8_dlc;
}
fprintf(outfile, "%x ", dlc);
if (mtu == CAN_MTU) {
if (cf->can_id & CAN_RTR_FLAG) {