129 Commits
Author SHA1 Message Date
Oliver HartkoppandGitHub 8027b498cf Merge pull request #191 from hartkopp/candump-remove-bridging
candump: remove bridging functionality
2020-02-01 09:55:23 +01:00
Oliver Hartkopp a9985c7652 candump: remove bridging functionality
The tool 'candump' is used to dump CAN traffic to stdout or logfile.
In early days where the in-kernel CAN gateway (can-gw) with the cangw tool was
not yet implemented the bridging functionality allowed to send received (and
filtered) CAN frames to another outgoing CAN interface.

As we now have can-gw and sending CAN frames from a 'reading tool' seems wrong
especially from the Unix philosophy "Write programs that do one thing and do
it well." this patch removes the obsolete functionality from candump.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-01-04 14:11:34 +01:00
Marc Kleine-BuddeandGitHub 665d8699eb Merge pull request #172 from jluebbe/jluebbe-actions
add github actions
2019-12-06 13:55:33 +01:00
Marc Kleine-BuddeandGitHub 4e36059f6a Merge pull request #175 from olerem/testj1938
sync testj1939 with latest kernel UAPI
2019-12-06 11:41:10 +01:00
Marc Kleine-BuddeandGitHub 6831eeeb62 Merge pull request #180 from olerem/jacd
jacd: remove SO_BINDTODEVICE setsockopt call
2019-12-06 11:31:53 +01:00
Oleksij Rempel a8456276df jacd: remove SO_BINDTODEVICE setsockopt call
This was used in the non mainline stack version.
Removing this call allows to use jacd without root permissions.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2019-12-06 11:24:44 +01:00
Marc Kleine-BuddeandGitHub 6eeedb0e66 Merge pull request #177 from marckleinebudde/fix-error-handling
isotpsniffer: fix error handling, "0" is a valid filedescriptor
2019-12-02 19:16:55 +01:00
Marc Kleine-Budde b6a44803fd isotpsniffer: fix error handling, "0" is a valid filedescriptor
Fixes: b04108c615 ("isotpsniffer: Fix error handling")
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2019-12-02 11:20:03 +01:00
Oleksij Rempel 153501c0ab can-j1939-kickstart: remove "Use source address" example
This example do not really demonstrate UAPI or testj1939 functionality.
So, remove it.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2019-12-02 08:29:45 +01:00
Oleksij Rempel 8cf6353039 can-j1939-kickstart: update documentation for testj1939
testj1939 need to use -B (broadcast) flag to be able to send or receive
broadcast packages.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2019-11-29 14:16:04 +01:00
Oleksij Rempel 5d3f8073b2 testj1939: add optional promiscuous mode and boradcast support
Upstream version of J1939 stack has different UAPI. To make documented
testj1939 examples work again we need at least boradcast flag.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2019-11-29 13:53:55 +01:00
Jan Luebbe d75122f649 add github actions 2019-11-25 15:29:47 +01:00
Oliver HartkoppandGitHub 9ae877ce32 Merge pull request #169 from rumpelsepp/isotpsniffer
isotpsniffer: add llopts support, use isprint() instead of open coded check and clean up error paths.
2019-11-14 13:54:05 +01:00
Stefan Tatschner da33f96edf isotpsniffer: Add support for llopts 2019-11-14 13:10:49 +01:00
Stefan Tatschner b04108c615 isotpsniffer: Fix error handling 2019-11-14 13:00:21 +01:00
Stefan Tatschner ecf80e8f91 isotpsniffer: Use isprint() instead of manual check 2019-11-14 07:23:28 +01:00
Yegor YefremovandGitHub bf30a4bc01 Merge pull request #167 from yegorich/err-handling
libj1939: fix missing include and syntax
2019-11-12 10:05:48 +01:00
Yegor Yefremov 63d9a3d87b libj1939: fix missing include and syntax
Include err.h and remove the unneeded parameter errno and
its header include.

Fixes: 791b6de ("treewide: Fix compilation on libmusl, replace error() by err()")

Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2019-11-12 10:04:24 +01:00
Yegor YefremovandGitHub c0dba0a454 Merge pull request #166 from yegorich/sync-headers
include: import header files from kernel v5.4-rc7
2019-11-12 10:02:20 +01:00
Yegor YefremovandGitHub a67bf7aa89 Merge pull request #168 from yegorich/typo
jacd: fix typo in a comment
2019-11-12 10:01:57 +01:00
Yegor Yefremov 276077de00 jacd: fix typo in a comment
s/ourselve/ourselves

Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2019-11-12 09:06:17 +01:00
Yegor Yefremov ffd60c9b74 include: import header files from kernel v5.4-rc7
Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2019-11-12 08:59:58 +01:00
Yegor YefremovandGitHub 8426d63ecf Merge pull request #165 from yegorich/spelling
Fix spelling in various files
2019-11-11 14:40:26 +01:00
Yegor Yefremov 14ccc06eba Fix spelling in various files
codespell parameters:

codespell -q 3 --skip="*.in,*.sh,*.m4,config,configure,autom4te.cache"

Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2019-11-11 14:21:49 +01:00
Marc Kleine-BuddeandGitHub 35b2ef691c Merge pull request #163 from marckleinebudde/libmusl-fix
treewide: Fix compilation on libmusl, replace error() by err()
2019-10-31 08:57:29 +01:00
Marc Kleine-BuddeandGitHub a08b61621d Merge pull request #162 from josemic/patch-1
Update can-j1939-kickstart.md
2019-10-31 08:52:13 +01:00
josemicandGitHub 275f606a1f Update can-j1939-kickstart.md
Added the padding to the candump output.
2019-10-30 19:22:23 +01:00
Marc Kleine-Budde 791b6de786 treewide: Fix compilation on libmusl, replace error() by err()
Reported-by: Brandon Ros <brandonros1@gmail.com>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2019-10-30 11:59:49 +01:00
Oliver HartkoppandGitHub 7e9bc7719b Merge pull request #155 from yegorich/reuse-fixes
Reuse fixes
2019-09-26 20:14:40 +02:00
Yegor Yefremov 0b93e9836f libj1939.h: add missing license and copyright header
Acked-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2019-09-26 15:46:20 +02:00
Yegor Yefremov d66295ee75 Add license texts as files
Add license texts mentioned by REUSE tool.

Acked-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2019-09-26 15:45:43 +02:00
Oliver HartkoppandGitHub 26ae1fffa8 Merge pull request #154 from yegorich/readme-fix
README: update the list of CAN over IP tools
2019-09-19 19:17:15 +02:00
Yegor Yefremov de8bb5fd8f README: update the list of CAN over IP tools
Fix socketcand URL and add cannelloni.

Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2019-09-19 14:14:36 +02:00
Marc Kleine-BuddeandGitHub a8d4827d0f Merge pull request #151 from olerem/recvown 2019-08-26 14:16:05 +02:00
Oleksij Rempel 7337cb12de j1939: drop SO_J1939_RECV_OWN support
SO_J1939_RECV_OWN is no longer supported by the kernel. So, sync the
headers and rework jacd.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2019-08-26 11:03:36 +02:00
Oleksij Rempel d5ba0e2d23 can/j1939.h: sync with latest kernel state
Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2019-08-26 11:03:36 +02:00
Oliver Hartkopp 226d6393b8 slcan tools: fix stringop-truncation warnings
Rework string handling for ioctl() syscalls for netdev name operations.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2019-08-25 18:25:35 +02:00
Oliver Hartkopp 1331c56393 isotptun: fix stringop-truncation warnings
Rework string handling for ioctl() syscalls for netdev name operations.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2019-08-25 18:20:37 +02:00
Oliver Hartkopp 319bd5de45 candump: silence format-overflow warning
When -Wformat-overflow= is enabled the gcc notes ...
"‘sprintf’ output between 30 and 82 bytes into a destination of size xx"
Increasing the buffer for the file name to 83 bytes removes the warning.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2019-08-23 19:57:06 +02:00
Oliver Hartkopp 83a1210b75 candump: preserve silent mode with enabled log file output format
As seen in https://github.com/linux-can/can-utils/issues/150 the logfile
format switch ignores the silent mode switch.

Fix this by checking the silent mode when using logfile format on stdout.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2019-08-23 19:40:27 +02:00
Oliver Hartkopp 818dacd78f candump: fix formatting of status messages regarding standard output
As remarked by Victor in https://github.com/linux-can/can-utils/issues/150
the output in the case of silent mode has puzzled line feeds.

Reported-by: Victor Cushman <VictorSCushman@gmail.com>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2019-08-23 19:34:10 +02:00
Oliver Hartkopp d45f3f46bd cangw: add CAN FD support
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2019-08-16 15:32:16 +02:00
Oliver Hartkopp 07054c06f5 cangw: remove sanity checks that are better handled in the kernel
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2019-08-16 15:26:58 +02:00
Oliver Hartkopp 24923df749 cangw: add new command line option '-X' to handle CAN FD rules
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2019-08-16 15:26:50 +02:00
Oliver Hartkopp 0669215a4b cangw: update include files for CAN FD support
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2019-08-16 15:26:41 +02:00
jogo-andOliver Hartkopp 9aa993df4c isotpdump: fix service 0x23 naming according to UDS specification
Fix Service 0x23 naming according to the standard
"ReadDataByMemory" -> "ReadMemoryByAddress"

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2019-07-30 22:09:50 +02:00
Marc Kleine-BuddeandGitHub c10c049ce7 Merge pull request #147 from ffontaine/master
fix include to find SIOCGSTAMP with latest kernel
2019-07-15 08:34:00 +02:00
Fabrice Fontaine e9590b1ca7 fix include to find SIOCGSTAMP with latest kernel
In linux kernel commit 0768e17073dc527ccd18ed5f96ce85f9985e9115
the asm-generic/sockios.h header no longer defines SIOCGSTAMP.
Instead it provides only SIOCGSTAMP_OLD.

The linux/sockios.h header now defines SIOCGSTAMP using either
SIOCGSTAMP_OLD or SIOCGSTAMP_NEW as appropriate. This linux only
header file is not pulled so we get a build failure.

canlogserver.c: In function 'main':
canlogserver.c:404:21: error: 'SIOCGSTAMP' undeclared (first use in this function); did you mean 'SIOCGRARP'?
     if (ioctl(s[i], SIOCGSTAMP, &tv) < 0)
                     ^~~~~~~~~~
                     SIOCGRARP
canlogserver.c:404:21: note: each undeclared identifier is reported only once for each function it appears in

Fixes:
 - http://autobuild.buildroot.org/results/363de7d9bf433be8bc47ba4ee52ae0bb80fa9021

Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
2019-07-14 22:14:10 +02:00
Yegor YefremovandGitHub 9ffb16495c Merge pull request #146 from yegorich/gpl-2-only
Relicense GPL-2.0-or-later files to GPL-2.0-only
2019-07-10 22:47:11 +02:00
Yegor Yefremov 59f92965b9 Relicense GPL-2.0-or-later files to GPL-2.0-only
This way all licenses in the project will be homogenised.

Acked-by: Marc Kleine-Budde <mkl@pengutronix.de>
Acked-by: Oliver Hartkopp <socketcan@hartkopp.net>
Acked-by: Sven Schmitt <sven.schmitt@gmx.net>
Acked-by: Oleksij Rempel <ore@pengutronix.de>
Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Acked-by: Brennan Ashton <bashton@brennanashton.com>
Acked-By: IOhannes m zmölnig <zmoelnig@iem.at>
Acked-by: Frank Theile <ftheile@grundfos.com>
Acked-by: Wolfgang Grandegger <wg@grandegger.com>
Acked-by: Jeremiah Mahler <jmmahler@gmail.com>
Acked-by: Jonathan Challinger <mr.challinger@gmail.com>
Acked-by: Cheng-Lung Lee <chenglung@gmail.com>
Acked-by: Ramesh Shanmugasundaram <rashanmu@gmail.com>
Acked-by: Mans Rullgard <mans@mansr.com>
Acked-by: Søren Holm <sgh@sgh.dk>
Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2019-07-10 14:01:23 +02:00
Yegor YefremovandGitHub 9d0c08d8cb Merge pull request #143 from yegorich/spdx
Add SPDX identifiers
2019-07-10 13:42:21 +02:00
Marc Kleine-BuddeandGitHub bb2cc1140f Merge pull request #144 from olerem/errq-2019.05.25
queue status
2019-06-27 12:05:52 +02:00
Oleksij Rempel c4e68aff78 jcat: get status for all queued messages
Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2019-06-25 07:36:36 +02:00
Oleksij Rempel 0e542c8dba jcat: make sure we can use decimal numbers for repeat parameter
Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2019-06-24 13:53:31 +02:00
Yegor Yefremov 7b7331976a Add SPDX identifiers
Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2019-06-19 12:24:24 +02:00
Marc Kleine-BuddeandGitHub a965086356 Merge pull request #140 from marckleinebudde/isotpdump
isotpdump: fix compiler warning
2019-06-03 20:26:11 +02:00
Marc Kleine-Budde 8ada533538 isotpdump: fix compiler warning
| isotpdump.c: In function ‘print_uds_message’:
| isotpdump.c:94:29: warning: suggest parentheses around ‘&&’ within ‘||’ [-Wparentheses]
|   } else if (service >= 0x10 && service <= 0x3E ||
|              ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
| isotpdump.c:96:22: warning: suggest parentheses around ‘&&’ within ‘||’ [-Wparentheses]
|       service >= 0xBA && service <= 0xBE)
|       ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2019-06-03 19:56:27 +02:00
Oliver HartkoppandGitHub f185160bfb Merge pull request #139 from buecheko/uds-dump
Add UDS output functionality to isotpdump
2019-05-30 20:37:42 +02:00
tr1core 0d8b0a8837 Add uds output functionality 2019-05-29 10:49:42 +02:00
Marc Kleine-BuddeandGitHub 045f75ad64 Merge pull request #135 from olerem/errq-2019.05.09.1
Provide error queue support
2019-05-09 14:50:29 +02:00
Oleksij RempelandMarc Kleine-Budde 25025d05ae jcat: add repeat support
Add option to resend same data without closing the socket.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2019-05-09 14:40:16 +02:00
Oleksij RempelandMarc Kleine-Budde edcce70373 jcat: provide errqueue support
The J1939 errqueue is a feedback interface to notify userspace
applications about actual transfer status. For now we can get
information about amount of data already send to the peer and errors
if session was aborted.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2019-05-09 14:40:16 +02:00
Oleksij RempelandMarc Kleine-Budde 05368ef1ae jcat: rework poller
Make poller to be a main part of the send loop. It should make
application more understandable.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2019-05-09 14:40:16 +02:00
Oleksij RempelandMarc Kleine-Budde 05a66d63fa jcat: enable polling by default
and set more or less meaningful default value.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2019-05-09 14:40:16 +02:00
Marc Kleine-Budde 6260263ef3 buildsystem: add SCM_TIMESTAMPING_OPT_STATS if not already defined 2019-05-09 14:40:16 +02:00
Oleksij RempelandMarc Kleine-Budde 9ff370ea82 include: add errqueue.h, net_tstamp.h, netlink.h
this headers are take from kernel v5.0 and needed for
error queue support.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2019-05-09 14:36:53 +02:00
Marc Kleine-BuddeandGitHub e92806db21 Merge pull request #136 from olerem/namefix
libj1939: fix name parsing
2019-05-09 12:29:58 +02:00
Oleksij Rempel 5e342e3c50 libj1939: fix name parsing
name is 8 byte long.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2019-05-09 12:09:11 +02:00
Oleksij Rempel 38fa644069 include: import header files from linux-5.0 (including new j1939 filter struct)
Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2019-05-08 10:53:00 +02:00
Marc Kleine-BuddeandGitHub afb88e9019 Merge pull request #134 from marckleinebudde/uapi
j1939: port j1939 tools to new UAPI
2019-04-04 11:00:53 +02:00
Oleksij RempelandMarc Kleine-Budde 19d41bec45 jcat: allow to re-send rest of the buffer if we was interrupted
latest version of UAPI allows to continue sending on some signals.

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
2019-04-04 10:53:17 +02:00
Oleksij RempelandMarc Kleine-Budde 48a4a4bef4 jcat: user recv() instead of recvfrom()
No information from recvfrom() is currently used. So, it is enough to
use plain recv().

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2019-04-04 10:45:33 +02:00
Oleksij RempelandMarc Kleine-Budde b931fb514c jcat: add missing close of outfile and j1939 socket
Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2019-04-04 10:45:33 +02:00
Oleksij RempelandMarc Kleine-Budde 7192b0b9d7 jacd: set SO_BROADCAST
with latest UAPI version we should set this flag to be allowed to send
broadcast frames with broadcast destination address. Even if on CAN
every thing is a broadcast...

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2019-04-04 10:37:52 +02:00
Oleksij RempelandMarc Kleine-Budde b8a2fa319a jacd: use sendto instead of send
Accordint to the new UAPI version, bind() with PGN set, should not be used
for destination PGN.

This change should work with new and old version of UAPI.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2019-04-04 10:37:49 +02:00
Oleksij RempelandMarc Kleine-Budde 314f8a92ae j1939: use defines instead of magic values
for now cover most of PGN values.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2019-04-04 10:37:39 +02:00
Marc Kleine-Budde 06d3beb08c include: import header files from linux-5.0 (including new j1939 patches)
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2019-04-04 10:19:11 +02:00
Marc Kleine-BuddeandGitHub 83667e822c Merge pull request #130 from marckleinebudde/testj1939
testj1939: use %zu to as format string to print sizeof()
2019-03-12 12:52:13 +01:00
Marc Kleine-Budde 9f60ed6fa0 testj1939: use %zu to as format string to print sizeof()
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2019-03-12 12:37:27 +01:00
Marc Kleine-BuddeandGitHub e1d5ee9907 Merge pull request #129 from marckleinebudde/cleanup
This pull request cleans up the Makefile by sorting things alphabetically and adding a missing newline to the GNUmakefile.am.
2019-03-12 12:34:42 +01:00
Marc Kleine-Budde c59dff1bb1 NUmakefile.am: EXTRA_DIST: add missing \
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2019-03-12 12:02:44 +01:00
Marc Kleine-Budde 4a1818aa55 Makefile: cleanup
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2019-03-12 10:14:27 +01:00
Oliver Hartkopp b6cb9a04e5 cansend: enhance help text to point out SFF/EFF identifiers
As suggested by https://github.com/jogo- an example was added that points
out how to send a CAN frame with CAN ID 123 as SFF (11 bit) and EFF (29 bit).

Reference: https://github.com/linux-can/can-utils/issues/126

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2019-02-14 09:47:46 +01:00
Oliver Hartkopp 46d620b27c cansend: enhance help text for length info in RTR frames
In 'classic' CAN 2.0 the RTR frames contain a length information in the
can_dlc field of a CAN frame control section. This length can be passed
to 'cansend' which has not been documented in the help text so far.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2019-02-13 14:55:47 +01:00
Marc Kleine-BuddeandGitHub 2328c6cfa0 Merge pull request #119 from twasilczyk/master
Don't build libj1939 for Android
2019-01-14 14:48:48 +01:00
Marc Kleine-BuddeandGitHub e0277cc960 Merge pull request #122 from olerem/test
testj1939: split output string in to 8 byte strings
2019-01-14 10:03:42 +01:00
Marc Kleine-BuddeandGitHub 7b70a433cf Merge pull request #121 from olerem/size
testj1939: fail if we use unsupported size
2019-01-14 10:03:34 +01:00
Oleksij Rempel 5551de5e56 testj1939: split output string in to 8 byte strings
Currently if we send lots of bytes, test1939 output will get unreadable.
Make it easier to read by splitting output dump.
New format will looks as following example:
root@DistroKit:~ testj1939 can0:0x90 -r
80 12300: 01 23 45 67 89 ab cd ef
00008     01 23 45 67 89 ab cd ef
00010     01 23 45 67 89 ab cd ef
00018     01 23 45 67 89 ab cd ef
00020     01 23 45 67 89 ab cd ef
00028     01 23 45 67 89 ab cd ef
00030     01 23 45 67 89 ab cd ef
00038     01 23 45 67 89 ab cd ef
00040     01 23 45 67 89 ab cd ef
00048     01 23 45 67 89 ab cd ef
00050     01 23 45 67 89 ab cd ef
00058     01 23 45 67 89 ab cd ef
00060     01 23 45 67 89 ab cd ef
00068     01 23 45 67 89 ab cd ef
00070     01 23 45 67 89 ab cd ef
00078     01 23 45 67 89 ab cd ef

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2019-01-14 09:19:51 +01:00
Oleksij Rempel ed5b495da6 testj1939: fail if we use unsupported size
Currently if we set size which is more then 128 byte
will silently ignore provided value and send only maximal
supported size.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2019-01-14 09:16:05 +01:00
Tomasz Wasilczyk 4da344b2aa Don't build j1939 for Android
This library uses if_nameindex symbol, not available at this system.
2019-01-10 12:03:06 -08:00
Oliver HartkoppandGitHub 8991b5c47d Merge pull request #118 from twasilczyk/master
Silence false positive unaligned pointer access warning
2019-01-10 19:28:12 +01:00
Tomasz Wasilczyk f6e07960d3 Silence false positive unaligned pointer access warning
This is a warning coming up on Android (ARM) platform.
Clang 4.x creates a false positive here: the can_id is the first
(and aligned) value in the packed struct modattr, so it's always
aligned if the struct itself is aligned.
2019-01-10 10:04:37 -08:00
Marc Kleine-BuddeandGitHub 02b87eb120 Merge pull request #117 from olerem/jcat-fixup
jcat: inverse if logic
2019-01-04 14:43:25 +01:00
Oleksij Rempel 5b68a2cef1 jcat: inverse if logic
it was if(offset != NULL), so it should be if(offset)

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2019-01-04 14:40:07 +01:00
Marc Kleine-BuddeandGitHub 0083a3762b Merge pull request #114 from olerem/jcat-2018.12.14
add jcat
2019-01-04 13:56:12 +01:00
Oleksij Rempel 23e5e227ac add jcat
jcat is kind of netcat for j1939
for example:
jcat can0:0x90 -r > /tmp/some_file

jcat -i some_file_to_send can0:0x80 :0x90,0x12300

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2019-01-04 13:01:11 +01:00
Oleksij Rempel e649b6ee2a libj1939: add libj1939_parse_canaddr and reuse it by testj1939
this function will be needed jcat

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2019-01-04 13:00:33 +01:00
Oliver Hartkopp c45a17e96b candump: try to switch bridge socket into CAN FD mode
When using the -b/-B option to send received CAN frames to the brigde interface
the sending failed when processing CAN FD frames. This patch enables CAN FD on
the socket for the bridging interface.

https://github.com/linux-can/can-utils/issues/104

Reported-by: https://github.com/jm3lee
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2018-10-24 09:36:55 +02:00
Oliver Hartkopp 8681e57230 candump: fix EFF CAN ID representation in CAN filter parameter
The documentation stated that the CAN ID is assumed to be an extended CAN
identifier (29 bit ID / EFF) when "can_id and can_mask are both 8 digits".
The check for the CAN ID length to be 8 is common in other CAN utils
(e.g. cansend) but it has never been implemented in candump.

This patch adds that check for EFF CAN IDs and clarifies the documentation.

Thanks to Nick for pointing out this inconsistency!

Reported-by: Nick Elmschig <nick@ikerobotics.com>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2018-10-23 21:22:11 +02:00
Marc Kleine-BuddeandGitHub 3f2bc6e1ea Merge pull request #108 from nick-ike/candump-usage-typo
Fix CAN ID typo in candump usage, to 12345678
2018-10-09 00:02:58 +02:00
Nick Elmschig 371d8e6da4 Fix CAN ID in candump usage, should be 12345678 2018-10-08 13:26:15 -07:00
Marc Kleine-BuddeandGitHub 12664efa9f Merge pull request #105 from marckleinebudde/cmake-cleanup
Cmake cleanup
2018-10-05 00:08:24 +02:00
Marc Kleine-Budde 04c171c285 CMakeLists.txt: build proper static libraries
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2018-10-04 23:55:54 +02:00
Marc Kleine-Budde 572a66fb94 CMakeLists.txt: clean up a bit
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2018-10-04 23:55:54 +02:00
Marc Kleine-Budde a6954bdaae CMakeLists.txt: Add missing N_SLCAN define 2018-10-04 23:55:54 +02:00
Marc Kleine-BuddeandGitHub 1c81f7fb2d Merge pull request #100 from yegorich/fix-return-value-checks
Add missing return value checks
2018-09-27 12:57:16 +02:00
Marc Kleine-BuddeandGitHub 5b8145f63d Merge pull request #99 from olerem/canfdtest-2018.09.18
Extend canfdtest to test proper RX and TX-ECHO order
2018-09-21 12:04:05 +02:00
Marc Kleine-BuddeandGitHub 3e4d589fec Merge pull request #101 from olerem/testj1938
add bind related options to testj1939
2018-09-21 11:44:49 +02:00
Bastian StenderandOleksij Rempel 54ff81cc40 testj1939: add omit bind option
This option is needed for j1939 socket functionality test.
Connects wihout bind should not work.

Signed-off-by: Bastian Stender <bst@pengutronix.de>
Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2018-09-21 11:31:22 +02:00
Bastian StenderandOleksij Rempel 1ba9b86451 testj1939: add re-bind support
This option is needed for j1939 socket functionality test.
Binding to a socket and rebinding to the socket with e.g. a different SA
should work.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Bastian Stender <bst@pengutronix.de>
2018-09-21 11:31:04 +02:00
Yegor Yefremov 1ce4dc7b39 Add missing return value checks
Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2018-09-18 13:43:29 +02:00
Oleksij RempelandOleksij Rempel ba603c59ae canfdtest: test if TX and RX msg are properly ordered
In some cases we can get local TX echo after remote response
for same TXed message was already received.

For applications which relay on proper order of TXed and RXed
message this will be fatal.

With this patch the package generating side will test if TX and RX are
properly ordered.
Currently with following commands, this issue can be easily
reproducible:
canfdtest -g can0 &
while(true); do chrt 40 dd if=/dev/zero of=/dev/null count=10000; done

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
2018-09-18 11:57:33 +02:00
Oleksij RempelandOleksij Rempel 18834410ac canfdtest: don't remap SIG to 0
Scripts can be configured to handle different SIGnals and
return codes in different ways. In this case it is better
to forward received signal, instead of converting it to return 0.

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
2018-09-18 11:57:33 +02:00
Marc Kleine-BuddeandGitHub 0ff988eeef Merge pull request #97 from yegorich/travis-warnings
CI: treat gcc warnings as errors
2018-09-18 11:48:23 +02:00
Yegor Yefremov 55b0ba8308 CI: treat gcc warning as errors
For now exclude unused-result warnings in order not to
affect current builds.

Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2018-09-13 10:38:19 +02:00
Marc Kleine-BuddeandGitHub 7a4dd732af Merge pull request #92 from marckleinebudde/improve-readme
Improve readme
2018-08-17 10:08:46 +02:00
Marc Kleine-Budde db7261d403 README: properly annotate codeblocks 2018-08-17 10:02:02 +02:00
Marc Kleine-Budde 6cedc8a5c6 README: remove stray bullet point 2018-08-17 10:02:02 +02:00
Marc Kleine-Budde d0c855c558 README: replace /home/joel by ~/ 2018-08-17 10:02:02 +02:00
Joel WinarskeandMarc Kleine-Budde 8a3e0453aa CMake first pass (#90)
* CMake first pass

* canbusload dep fix

* Add Eclipse Debug, and Android Studio generation examples

* travis additions

* Update .travis.yml

CMAKE_BUILT_TYPE typo fix

* add android ndk variants(less mips)
2018-08-17 09:50:30 +02:00
Oliver Hartkopp 47f2e7a180 slcand: move setting of loop variable back into code context
With commit 33a9249571 ("slcand: daemonise only once setup is complete")
the daemonize syscall is moved behind serial tty setup.

This patch moves the missing assignment of the loop variable slcand_running
to get it into the code context of the while() loop.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2018-04-29 19:02:55 +02:00
Marc Kleine-BuddeandGitHub 872b73766c Merge pull request #81 from mansr/master
slcand: daemonise only once setup is complete
2018-04-25 16:34:36 +02:00
Mans Rullgard 33a9249571 slcand: daemonise only once setup is complete
Delay the daemon() call until the interface has been configured. This
simplifies scripts that wish to use the new interface immediately.

Signed-off-by: Mans Rullgard <mans@mansr.com>
2018-04-20 13:46:15 +01:00
Marc Kleine-BuddeandGitHub 01041fddd6 Merge pull request #79 from ftheile/consistent-sizeof
Consistent arguments to sizeof().
2018-04-03 14:22:33 +02:00
Frank Theile f51c897d68 Consistent arguments to sizeof().
In calls to functions taking a pointer 'p' and a length 'l':
if a struct variable v is passed in for p, then also pass sizeof(v) for
l.
2018-04-03 11:56:28 +02:00
Oliver HartkoppandGitHub 9d52f81058 Merge pull request #78 from ftheile/patch-1
bzero() is deprecated
2018-03-30 19:03:02 +02:00
Frank TheileandGitHub 6ca4ce8ac9 bzero() is deprecated
Use memset() instead of bzero().
2018-03-30 19:00:05 +02:00
Oliver HartkoppandGitHub 8389744f79 Merge pull request #77 from Shmink/master
valgrind no longer reports uninitialised byte(s) from bind call.
2018-03-24 20:56:57 +01:00
Tom Nicklin b00cb24f12 valgrind no longer reports uninitialised byte(s) from bind call. 2018-03-24 19:53:13 +00:00
61 changed files with 2731 additions and 469 deletions
+19
View File
@@ -0,0 +1,19 @@
name: C with autotools
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: autogen
run: ./autogen.sh
- name: configure
run: ./configure
- name: make
run: make
- name: make distcheck
run: make distcheck
+1
View File
@@ -41,6 +41,7 @@ GNUmakefile.in
/isotpsniffer
/isotptun
/jacd
/jcat
/jspy
/jsr
/log2asc
+77 -2
View File
@@ -12,13 +12,86 @@ matrix:
os: linux
dist: trusty
compiler: gcc
script: ./autogen.sh && ./configure && make distcheck
script: ./autogen.sh && ./configure CFLAGS="-Werror -Wno-unused-result" && make distcheck
- env: test="x64 5.0 (autotools)"
os: linux
dist: trusty
compiler: clang
script: ./autogen.sh && ./configure && make distcheck
script: ./autogen.sh && ./configure CFLAGS="-Werror -Wno-unused-result" && make distcheck
- env: test="x64 4.8.4 (CMake gcc)"
os: linux
dist: trusty
compiler: gcc
before_script:
- mkdir gcc_rel && cd gcc_rel
- cmake ..
script: make
- env: test="x64 5.0 (CMake clang)"
os: linux
dist: trusty
compiler: clang
before_script:
- mkdir clang_rel && cd clang_rel
- cmake ..
script: make
- env: test="x64 5.0 (CMake clang - Ninja) Debug"
os: linux
dist: trusty
compiler: clang
before_script:
- mkdir clang_ninja_dbg && cd clang_ninja_dbg
- cmake .. -GNinja -DCMAKE_BUILD_TYPE=Debug
script: ninja
- env: test="Android NDK (CMake)"
os: linux
language: android
android:
components:
- build-tools-25.0.2
install:
- echo y | sdkmanager "ndk-bundle"
- echo y | sdkmanager "cmake;3.6.4111459"
before_script:
- export ANDROID_NDK_HOME=$ANDROID_HOME/ndk-bundle
- export ANDROID_CMAKE=$ANDROID_HOME/cmake/3.6.4111459/bin/cmake
- export ANDROID_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake
script:
- pushd . && mkdir android15_armeabiv7a_rel && cd android15_armeabiv7a_rel
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-15 -DANDROID_ABI=armeabi-v7a -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
- make && popd
- pushd . && mkdir android15_x86_rel && cd android15_x86_rel
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-15 -DANDROID_ABI=x86 -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
- make && popd
- pushd . && mkdir android21_arm64-v8a_rel && cd android21_arm64-v8a_rel
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-21 -DANDROID_ABI=arm64-v8a -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
- make && popd
- pushd . && mkdir android21_x86_64_rel && cd android21_x86_64_rel
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-21 -DANDROID_ABI=x86_64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
- make && popd
- pushd . && mkdir android15_armeabiv7a_dbg && cd android15_armeabiv7a_dbg
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-15 -DANDROID_ABI=armeabi-v7a -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
- make && popd
- pushd . && mkdir android15_x86_dbg && cd android15_x86_dbg
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-15 -DANDROID_ABI=x86 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
- make && popd
- pushd . && mkdir android21_arm64-v8a_dbg && cd android21_arm64-v8a_dbg
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-21 -DANDROID_ABI=arm64-v8a -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
- make && popd
- pushd . && mkdir android21_x86_64_dbg && cd android21_x86_64_dbg
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-21 -DANDROID_ABI=x86_64 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
- make && popd
addons:
apt:
@@ -27,5 +100,7 @@ addons:
- automake
- libtool
- m4
- cmake
- ninja-build
sources:
- ubuntu-toolchain-r-test
+95
View File
@@ -0,0 +1,95 @@
cmake_minimum_required(VERSION 3.3)
project(can-utils LANGUAGES C)
include (GNUInstallDirs)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
add_definitions(-D_GNU_SOURCE)
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-parentheses")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSO_RXQ_OVFL=40")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPF_CAN=29")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DAF_CAN=PF_CAN")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DN_SLCAN=17")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSCM_TIMESTAMPING_OPT_STATS=54")
include_directories (.)
include_directories (./include)
set(PROGRAMS_CANLIB
asc2log
canbusload
candump
cangen
canlogserver
canplayer
cansend
log2asc
log2long
)
set(PROGRAMS_J1939
jacd
jcat
jspy
jsr
testj1939
)
set(PROGRAMS
${PROGRAMS_CANLIB}
bcmserver
can-calc-bit-timing
canfdtest
cangw
cansniffer
isotpdump
isotpperf
isotprecv
isotpsend
isotpserver
isotpsniffer
isotptun
slcan_attach
slcand
slcanpty
)
if(NOT ANDROID)
list(APPEND PROGRAMS ${PROGRAMS_J1939})
add_library(j1939 STATIC
libj1939.c
)
endif()
add_library(can STATIC
lib.c
canframelen.c
)
foreach(name ${PROGRAMS})
add_executable(${name} ${name}.c)
if("${name}" IN_LIST PROGRAMS_J1939)
target_link_libraries(${name}
PRIVATE j1939
)
elseif("${name}" IN_LIST PROGRAMS_CANLIB)
target_link_libraries(${name}
PRIVATE can
)
endif()
install(TARGETS ${name} DESTINATION ${CMAKE_INSTALL_BINDIR})
endforeach()
ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_SOURCE_DIR}/cmake/make_uninstall.cmake")
+8 -4
View File
@@ -14,16 +14,18 @@ noinst_HEADERS = \
lib.h \
libj1939.h \
terminal.h \
include/linux/can.h \
include/linux/can/bcm.h \
include/linux/can/error.h \
include/linux/can/gw.h \
include/linux/can.h \
include/linux/can/isotp.h \
include/linux/can/j1939.h \
include/linux/can/netlink.h \
include/linux/can/raw.h \
include/linux/can/vxcan.h
include/linux/can/vxcan.h \
include/linux/errqueue.h \
include/linux/net_tstamp.h \
include/linux/netlink.h
noinst_LTLIBRARIES = \
libcan.la \
@@ -57,6 +59,7 @@ bin_PROGRAMS = \
isotpsniffer \
isotptun \
jacd \
jcat \
jspy \
jsr \
log2asc \
@@ -67,6 +70,7 @@ bin_PROGRAMS = \
testj1939
jacd_LDADD = libj1939.la
jcat_LDADD = libj1939.la
jspy_LDADD = libj1939.la
jsr_LDADD = libj1939.la
testj1939_LDADD = libj1939.la
@@ -76,7 +80,7 @@ EXTRA_DIST = \
Android.mk \
README.md \
autogen.sh \
can-j1939-kickstart.md
can-j1939-kickstart.md \
can-j1939.md
MAINTAINERCLEANFILES = \
+27
View File
@@ -0,0 +1,27 @@
Copyright (c) <year> <owner> . All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
+340
View File
@@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
+12
View File
@@ -0,0 +1,12 @@
NOTE! This copyright does *not* cover user programs that use kernel
services by normal system calls - this is merely considered normal use
of the kernel, and does *not* fall under the heading of "derived work".
Also note that the GPL below is copyrighted by the Free Software
Foundation, but the instance of code that it refers to (the Linux
kernel) is copyrighted by me and others who actually wrote it.
Also note that the only valid version of the GPL as far as the kernel
is concerned is _this_ particular version of the license (ie v2, not
v2.2 or v3.x or whatever), unless explicitly otherwise stated.
Linus Torvalds
+70 -36
View File
@@ -41,29 +41,61 @@
DESTDIR ?=
PREFIX ?= /usr/local
MAKEFLAGS = -k
MAKEFLAGS := -k
CFLAGS = -O2 -Wall -Wno-parentheses
CFLAGS := -O2 -Wall -Wno-parentheses
CPPFLAGS += -Iinclude \
-D_FILE_OFFSET_BITS=64 \
-DSO_RXQ_OVFL=40 \
-DPF_CAN=29 \
-DAF_CAN=PF_CAN \
-D_GNU_SOURCE
CPPFLAGS += \
-Iinclude \
-DAF_CAN=PF_CAN \
-DPF_CAN=29 \
-DSO_RXQ_OVFL=40 \
-DSCM_TIMESTAMPING_OPT_STATS=54 \
-D_FILE_OFFSET_BITS=64 \
-D_GNU_SOURCE
PROGRAMS_ISOTP = isotpdump isotprecv isotpsend isotpsniffer isotptun isotpserver isotpperf
PROGRAMS_CANGW = cangw
PROGRAMS_SLCAN = slcan_attach slcand
PROGRAMS_J1939 = jacd jspy jsr testj1939
PROGRAMS = can-calc-bit-timing candump cansniffer cansend canplayer cangen canbusload\
log2long log2asc asc2log\
canlogserver bcmserver\
$(PROGRAMS_ISOTP)\
$(PROGRAMS_CANGW)\
$(PROGRAMS_SLCAN)\
$(PROGRAMS_J1939)\
slcanpty canfdtest
PROGRAMS_CANGW := \
cangw
PROGRAMS_ISOTP := \
isotpdump \
isotpperf \
isotprecv \
isotpsend \
isotpserver \
isotpsniffer \
isotptun
PROGRAMS_J1939 := \
jacd \
jcat \
jspy \
jsr \
testj1939
PROGRAMS_SLCAN := \
slcan_attach \
slcand
PROGRAMS := \
$(PROGRAMS_CANGW) \
$(PROGRAMS_ISOTP) \
$(PROGRAMS_J1939) \
$(PROGRAMS_SLCAN) \
asc2log \
bcmserver \
can-calc-bit-timing \
canbusload \
candump \
canfdtest \
cangen \
canlogserver \
canplayer \
cansend \
cansniffer \
log2asc \
log2long \
slcanpty
all: $(PROGRAMS)
@@ -77,31 +109,33 @@ install:
distclean:
rm -f $(PROGRAMS) $(LIBRARIES) *.o *~
cansend.o: lib.h
cangen.o: lib.h
candump.o: lib.h
canplayer.o: lib.h
canlogserver.o: lib.h
canbusload.o: lib.h
log2long.o: lib.h
log2asc.o: lib.h
asc2log.o: lib.h
canbusload.o: lib.h
candump.o: lib.h
cangen.o: lib.h
canlogserver.o: lib.h
canplayer.o: lib.h
cansend.o: lib.h
log2asc.o: lib.h
log2long.o: lib.h
jacd.o: libj1939.h
jcat.o: libj1939.h
jspy.o: libj1939.h
jsr.o: libj1939.h
testj1939.o: libj1939.h
canframelen.o: canframelen.h
cansend: cansend.o lib.o
cangen: cangen.o lib.o
candump: candump.o lib.o
canplayer: canplayer.o lib.o
canlogserver: canlogserver.o lib.o
log2long: log2long.o lib.o
log2asc: log2asc.o lib.o
asc2log: asc2log.o lib.o
canbusload: canbusload.o canframelen.o
candump: candump.o lib.o
cangen: cangen.o lib.o
canlogserver: canlogserver.o lib.o
canplayer: canplayer.o lib.o
cansend: cansend.o lib.o
log2asc: log2asc.o lib.o
log2long: log2long.o lib.o
jacd: jacd.o libj1939.o
jcat: jcat.o libj1939.o
jspy: jspy.o libj1939.o
jsr: jsr.o libj1939.o
testj1939: testj1939.o libj1939.o
canbusload: canbusload.o canframelen.o
+14 -2
View File
@@ -18,10 +18,11 @@ subsystem (aka SocketCAN):
#### CAN access via IP sockets
* canlogserver : log CAN frames from a remote/local host
* bcmserver : interactive BCM configuration (remote/local)
* [socketcand](https://github.com/dschanoeh/socketcand) : use RAW/BCM/ISO-TP sockets via TCP/IP sockets
* [socketcand](https://github.com/linux-can/socketcand) : use RAW/BCM/ISO-TP sockets via TCP/IP sockets
* [cannelloni](https://github.com/mguentner/cannelloni) : UDP/SCTP based SocketCAN tunnel
#### CAN in-kernel gateway configuration
* cangw : CAN gateway userpace tool for netlink configuration
* cangw : CAN gateway userspace tool for netlink configuration
#### CAN bus measurement and testing
* canbusload : calculate and display the CAN busload
@@ -47,6 +48,17 @@ subsystem (aka SocketCAN):
* slcand : daemon for serial line CAN interface configuration
* slcanpty : creates a pty for applications using the slcan ASCII protocol
#### CMake Project Generator
* Place your build folder anywhere, passing CMake the path. Relative or absolute.
* Some examples using a build folder under the source tree root:
* Android : ``cmake -DCMAKE_TOOLCHAIN_FILE=~/Android/Sdk/ndk-bundle/build/cmake/android.toolchain.cmake -DANDROID_PLATFORM=android-21 -DANDROID_ABI=armeabi-v7a .. && make``
* Android Studio : Copy repo under your project's ``app`` folder, add ``add_subdirectory(can-utils)`` to your ``CMakeLists.txt`` file after ``cmake_minimum_required()``. Generating project will build Debug/Release for all supported EABI types. ie. arm64-v8a, armeabi-v7a, x86, x86_64.
* Raspberry Pi : ``cmake -DCMAKE_TOOLCHAIN_FILE=~/rpi/tools/build/cmake/rpi.toolchain.cmake .. && make``
* Linux : ``cmake -GNinja .. && ninja``
* Linux Eclipse Photon (Debug) : ``CC=clang cmake -G"Eclipse CDT4 - Unix Makefiles" ../can-utils/ -DCMAKE_BUILD_TYPE=Debug -DCMAKE_ECLIPSE_VERSION=4.8.0``
* To override the base installation directory use: ``CMAKE_INSTALL_PREFIX``
ie. ``CC=clang cmake -DCMAKE_INSTALL_PREFIX=./out .. && make install``
### Additional Information:
* [SocketCAN Documentation (Linux Kernel)](https://www.kernel.org/doc/Documentation/networking/can.txt)
+1
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* asc2log.c - convert ASC logfile to compact CAN frame logfile
*
+2 -1
View File
@@ -1,7 +1,8 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* tst-bcm-server.c
*
* Test programm that implements a socket server which understands ASCII
* Test program that implements a socket server which understands ASCII
* messages for simple broadcast manager frame send commands.
*
* < interface command ival_s ival_us can_id can_dlc [data]* >
+3 -3
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* can-calc-bit-timing.c: Calculate CAN bit timing parameters
*
* Copyright (C) 2008 Wolfgang Grandegger <wg@grandegger.com>
@@ -11,9 +12,8 @@
* email:pisa@cmp.felk.cvut.cz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* any later version.
* it under the terms of the version 2 of the GNU General Public License
* as published by the Free Software Foundation
*/
#include <errno.h>
+26 -44
View File
@@ -33,7 +33,7 @@ testj1939 can be told to print the used API calls by adding **-v** program argum
Do in terminal 1
./testj1939 -r can0:
testj1939 -B -r can0
Send raw CAN in terminal 2
@@ -54,20 +54,11 @@ In J1939, this means that ECU 0x40 sends directly to ECU 0x41
Since we did not bind to address 0x41, this traffic
is not meant for us and *testj1939* does not receive it.
### Use source address
Binding a can-j1939 socket to a source address will register
allow you to send packets.
./testj1939 can0:0x80
Your system had, for a small moment, source address 0x80 assigned.
### receive with source address
Terminal 1:
./testj1939 -r can0:0x80
testj1939 -r can0:0x80
Terminal 2:
@@ -87,37 +78,42 @@ Open in terminal 1:
And to these test in another terminal
./testj1939 -s can0:0x80,0x3ffff
testj1939 -B -s can0:0x80 can0:,0x3ffff
This produces **1BFFFF80#0123456789ABCDEF** on CAN.
Note: To be able to send a broadcast we need to use, we need to use "-B" flag.
### Multiple source addresses on 1 CAN device
./testj1939 -s can0:0x90,0x3ffff
testj1939 -B -s can0:0x90 can0:,0x3ffff
produces **1BFFFF90#0123456789ABCDEF** ,
### Use PDU1 PGN
./testj1939 -s can0:0x80,0x12345
testj1939 -B -s can0:0x80 can0:,0x12300
emits **1923FF80#0123456789ABCDEF** .
Note that the real PGN is **0x12300**, and destination address is **0xff**.
Note that the PGN is **0x12300**, and destination address is **0xff**.
### Use destination address info
Since in this example we use unicast source and destination addresses, we do
not need to use "-B" (broadcast) flag.
The destination field may be set during sendto().
*testj1939* implements that like this
./testj1939 -s can0:0x80,0x12345 can0:0x40
testj1939 -s can0:0x80 can0:0x40,0x12300
emits **19234080#0123456789ABCDEF** .
The destination CAN iface __must__ always match the source CAN iface.
Specifing one during bind is therefore sufficient.
Specifying one during bind is therefore sufficient.
./testj1939 -s can0:,0x12300 :0x40
testj1939 -s can0:0x80 :0x40,0x12300
emits the very same.
@@ -129,13 +125,13 @@ __sendto( *peername* )__ , and only one is used.
For broadcasted transmissions
./testj1939 -s can0:0x80,0x12300 :,0x32100
testj1939 -B -s can0:0x80 :,0x32100
emits **1B21FF80#0123456789ABCDEF** rather than 1923FF80#012345678ABCDEF
emits **1B21FF80#0123456789ABCDEF**
Desitination specific transmissions
Destination specific transmissions
./testj1939 -s can0:0x80,0x12300 :0x40,0x32100
testj1939 -s can0:0x80,0x12300 :0x40,0x32100
emits **1B214080#0123456789ABCDEF** .
@@ -146,30 +142,16 @@ It makes sometimes sense to omit the PGN in __bind( *sockname* )__ .
J1939 transparently switches to *Transport Protocol* when packets
do not fit into single CAN packets.
./testj1939 -s20 can0:0x80 :,0x12300
emits:
18ECFF80#20140003FF002301
This is the first fragment for broadcasted *Transport Protocol*.
_testj1939_ returns before the subsequent packets can leave, and
as the last socket on the system closes, can-j1939 effectively
cleans up all resources. Real-world applications will run like forever,
and will not encounter this side-effect.
Try again, and instruct _testj1939_ to keep the socket open for 1 second.
./testj1939 -w1.0 -s20 can0:0x80 :,0x12300
testj1939 -B -s20 can0:0x80 :,0x12300
emits:
18ECFF80#20140003FF002301
18EBFF80#010123456789ABCD
18EBFF80#02EF0123456789AB
18EBFF80#03CDEF01234567
18EBFF80#03CDEF01234567FF
The fragments for broadcasted *Transport Protocol* are seperated
The fragments for broadcasted *Transport Protocol* are separated
__50ms__ from each other.
Destination specific *Transport Protocol* applies flow control
and may emit CAN packets much faster.
@@ -178,11 +160,11 @@ First assign 0x90 to the local system.
This becomes important because the kernel must interact in the
transport protocol sessions before the complete packet is delivered.
./testj1939 can0:0x90 -r &
testj1939 can0:0x90 -r &
Now test:
./testj1939 -s20 can0:0x80 :0x90,0x12300
testj1939 -s20 can0:0x80 :0x90,0x12300
emits:
@@ -190,7 +172,7 @@ emits:
18EC8090#110301FFFF002301
18EB9080#010123456789ABCD
18EB9080#02EF0123456789AB
18EB9080#03CDEF01234567
18EB9080#03CDEF01234567FF
18EC8090#13140003FF002301
The flow control causes a bit overhead.
@@ -200,8 +182,8 @@ This overhead scales very good for larger J1939 packets.
### Change priority of J1939 packets
./testj1939 -s can0:0x80,0x0100
./testj1939 -s -p3 can0:0x80,0x0200
testj1939 -B -s can0:0x80 :,0x0100
testj1939 -B -s -p3 can0:0x80 :,0x0200
emits
+2 -2
View File
@@ -19,7 +19,7 @@ See [Wikipedia:socketcan](http://en.wikipedia.org/wiki/Socketcan)
* CAN id is composed of
* 0..8: SA (source address)
* 9..26:
* PDU1: PGN+DA (destionation address)
* PDU1: PGN+DA (destination address)
* PDU2: PGN
* 27..29: PRIO
@@ -61,7 +61,7 @@ will emit a single CAN frame.
send(sock, data, 9, 0);
will use fragementation, emitting 1+ CAN frames.
will use fragmentation, emitting 1+ CAN frames.
# Using J1939
+3 -2
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* canbusload.c
*
@@ -102,7 +103,7 @@ void print_usage(char *prg)
fprintf(stderr, "Up to %d CAN interfaces with mandatory bitrate can be specified on the \n", MAXSOCK);
fprintf(stderr, "commandline in the form: <ifname>@<bitrate>\n\n");
fprintf(stderr, "The bitrate is mandatory as it is needed to know the CAN bus bitrate to\n");
fprintf(stderr, "calcultate the bus load percentage based on the received CAN frames.\n");
fprintf(stderr, "calculate the bus load percentage based on the received CAN frames.\n");
fprintf(stderr, "Due to the bitstuffing estimation the calculated busload may exceed 100%%.\n");
fprintf(stderr, "For each given interface the data is presented in one line which contains:\n\n");
fprintf(stderr, "(interface) (received CAN frames) (used bits total) (used bits for payload)\n");
@@ -386,7 +387,7 @@ int main(int argc, char **argv)
if (FD_ISSET(s[i], &rdfs)) {
nbytes = read(s[i], &frame, sizeof(struct can_frame));
nbytes = read(s[i], &frame, sizeof(frame));
if (nbytes < 0) {
perror("read");
+13 -73
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* candump.c
*
@@ -124,12 +125,9 @@ void print_usage(char *prg)
fprintf(stderr, " -a (enable additional ASCII output)\n");
fprintf(stderr, " -S (swap byte order in printed CAN data[] - marked with '%c' )\n", SWAP_DELIMITER);
fprintf(stderr, " -s <level> (silent mode - %d: off (default) %d: animation %d: silent)\n", SILENT_OFF, SILENT_ANI, SILENT_ON);
fprintf(stderr, " -b <can> (bridge mode - send received frames to <can>)\n");
fprintf(stderr, " -B <can> (bridge mode - like '-b' with disabled loopback)\n");
fprintf(stderr, " -u <usecs> (delay bridge forwarding by <usecs> microseconds)\n");
fprintf(stderr, " -l (log CAN-frames into file. Sets '-s %d' by default)\n", SILENT_ON);
fprintf(stderr, " -L (use log file format on stdout)\n");
fprintf(stderr, " -n <count> (terminate after receiption of <count> CAN frames)\n");
fprintf(stderr, " -n <count> (terminate after reception of <count> CAN frames)\n");
fprintf(stderr, " -r <size> (set socket receive buffer to <size>)\n");
fprintf(stderr, " -D (Don't exit if a \"detected\" can device goes down.\n");
fprintf(stderr, " -d (monitor dropped CAN frames)\n");
@@ -145,14 +143,14 @@ void print_usage(char *prg)
fprintf(stderr, " #<error_mask> (set error frame filter, see include/linux/can/error.h)\n");
fprintf(stderr, " [j|J] (join the given CAN filters - logical AND semantic)\n");
fprintf(stderr, "\nCAN IDs, masks and data content are given and expected in hexadecimal values.\n");
fprintf(stderr, "When can_id and can_mask are both 8 digits, they are assumed to be 29 bit EFF.\n");
fprintf(stderr, "When the can_id is 8 digits long the CAN_EFF_FLAG is set for 29 bit EFF format.\n");
fprintf(stderr, "Without any given filter all data frames are received ('0:0' default filter).\n");
fprintf(stderr, "\nUse interface name '%s' to receive from all CAN interfaces.\n", ANYDEV);
fprintf(stderr, "\nExamples:\n");
fprintf(stderr, "%s -c -c -ta can0,123:7FF,400:700,#000000FF can2,400~7F0 can3 can8\n", prg);
fprintf(stderr, "%s -l any,0~0,#FFFFFFFF (log only error frames but no(!) data frames)\n", prg);
fprintf(stderr, "%s -l any,0:0,#FFFFFFFF (log error frames and also all data frames)\n", prg);
fprintf(stderr, "%s vcan2,92345678:DFFFFFFF (match only for extended CAN ID 12345678)\n", prg);
fprintf(stderr, "%s vcan2,12345678:DFFFFFFF (match only for extended CAN ID 12345678)\n", prg);
fprintf(stderr, "%s vcan2,123:7FF (matches CAN ID 123 - including EFF and RTR frames)\n", prg);
fprintf(stderr, "%s vcan2,123:C00007FF (matches CAN ID 123 - only SFF and non-RTR frames)\n", prg);
fprintf(stderr, "\n");
@@ -216,8 +214,6 @@ int main(int argc, char **argv)
{
fd_set rdfs;
int s[MAXSOCK];
int bridge = 0;
useconds_t bridge_delay = 0;
unsigned char timestamp = 0;
unsigned char hwtimestamp = 0;
unsigned char down_causes_exit = 1;
@@ -256,7 +252,7 @@ int main(int argc, char **argv)
last_tv.tv_sec = 0;
last_tv.tv_usec = 0;
while ((opt = getopt(argc, argv, "t:HciaSs:b:B:u:lDdxLn:r:heT:?")) != -1) {
while ((opt = getopt(argc, argv, "t:HciaSs:lDdxLn:r:heT:?")) != -1) {
switch (opt) {
case 't':
timestamp = optarg[0];
@@ -300,49 +296,6 @@ int main(int argc, char **argv)
}
break;
case 'b':
case 'B':
if (strlen(optarg) >= IFNAMSIZ) {
fprintf(stderr, "Name of CAN device '%s' is too long!\n\n", optarg);
return 1;
} else {
bridge = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (bridge < 0) {
perror("bridge socket");
return 1;
}
addr.can_family = AF_CAN;
strcpy(ifr.ifr_name, optarg);
if (ioctl(bridge, SIOCGIFINDEX, &ifr) < 0)
perror("SIOCGIFINDEX");
addr.can_ifindex = ifr.ifr_ifindex;
if (!addr.can_ifindex) {
perror("invalid bridge interface");
return 1;
}
/* disable default receive filter on this write-only RAW socket */
setsockopt(bridge, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
if (opt == 'B') {
const int loopback = 0;
setsockopt(bridge, SOL_CAN_RAW, CAN_RAW_LOOPBACK,
&loopback, sizeof(loopback));
}
if (bind(bridge, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bridge bind");
return 1;
}
}
break;
case 'u':
bridge_delay = (useconds_t)strtoul(optarg, (char **)NULL, 10);
break;
case 'l':
log = 1;
break;
@@ -502,12 +455,16 @@ int main(int argc, char **argv)
&rfilter[numfilter].can_id,
&rfilter[numfilter].can_mask) == 2) {
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_mask) == 2) {
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;
@@ -612,7 +569,7 @@ int main(int argc, char **argv)
if (log) {
time_t currtime;
struct tm now;
char fname[sizeof("candump-2006-11-20_202026.log")+1];
char fname[83]; /* suggested by -Wformat-overflow= */
if (time(&currtime) == (time_t)-1) {
perror("time");
@@ -630,9 +587,9 @@ int main(int argc, char **argv)
now.tm_sec);
if (silent != SILENT_ON)
printf("\nWarning: console output active while logging!");
fprintf(stderr, "Warning: Console output active while logging!\n");
fprintf(stderr, "\nEnabling Logfile '%s'\n\n", fname);
fprintf(stderr, "Enabling Logfile '%s'\n", fname);
logfile = fopen(fname, "w");
if (!logfile) {
@@ -698,20 +655,6 @@ int main(int argc, char **argv)
if (count && (--count == 0))
running = 0;
if (bridge) {
if (bridge_delay)
usleep(bridge_delay);
nbytes = write(bridge, &frame, nbytes);
if (nbytes < 0) {
perror("bridge write");
return 1;
} else if ((size_t)nbytes != CAN_MTU && (size_t)nbytes != CANFD_MTU) {
fprintf(stderr,"bridge write: incomplete CAN frame\n");
return 1;
}
}
for (cmsg = CMSG_FIRSTHDR(&msg);
cmsg && (cmsg->cmsg_level == SOL_SOCKET);
@@ -765,7 +708,7 @@ int main(int argc, char **argv)
max_devname_len, devname[idx], buf);
}
if (logfrmt) {
if ((logfrmt) && (silent == SILENT_OFF)){
char buf[CL_CFSZ]; /* max length */
/* print CAN frame in log file style to stdout */
@@ -854,9 +797,6 @@ int main(int argc, char **argv)
for (i=0; i<currmax; i++)
close(s[i]);
if (bridge)
close(bridge);
if (log)
fclose(logfile);
+56 -27
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* canfdtest.c - Full-duplex test program (DUT and host part)
*
@@ -5,9 +6,8 @@
* (C) 2009 Wolfgang Grandegger <wg@grandegger.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* any later version.
* it under the terms of the version 2 of the GNU General Public License
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -47,6 +47,7 @@ static int running = 1;
static int verbose;
static int sockfd;
static int test_loops;
static int exit_sig;
static void print_usage(char *prg)
{
@@ -71,47 +72,47 @@ static void print_usage(char *prg)
exit(1);
}
static void print_frame(struct can_frame *frame)
static void print_frame(struct can_frame *frame, int inc)
{
int i;
printf("%04x: ", frame->can_id);
printf("%04x: ", frame->can_id + inc);
if (frame->can_id & CAN_RTR_FLAG) {
printf("remote request");
} else {
printf("[%d]", frame->can_dlc);
for (i = 0; i < frame->can_dlc; i++)
printf(" %02x", frame->data[i]);
printf(" %02x", frame->data[i] + inc);
}
printf("\n");
}
static void print_compare(struct can_frame *exp, struct can_frame *rec)
static void print_compare(struct can_frame *exp, struct can_frame *rec, int inc)
{
printf("expected: ");
print_frame(exp);
print_frame(exp, inc);
printf("received: ");
print_frame(rec);
print_frame(rec, 0);
}
static void compare_frame(struct can_frame *exp, struct can_frame *rec)
static void compare_frame(struct can_frame *exp, struct can_frame *rec, int inc)
{
int i;
if (rec->can_id != exp->can_id) {
if (rec->can_id != exp->can_id + inc) {
printf("Message ID mismatch!\n");
print_compare(exp, rec);
print_compare(exp, rec, inc);
running = 0;
} else if (rec->can_dlc != exp->can_dlc) {
printf("Message length mismatch!\n");
print_compare(exp, rec);
print_compare(exp, rec, inc);
running = 0;
} else {
for (i = 0; i < rec->can_dlc; i++) {
if (rec->data[i] != exp->data[i]) {
if (rec->data[i] != ((exp->data[i] + inc) & 0xff)) {
printf("Databyte %x mismatch !\n", i);
print_compare(exp,
rec);
rec, inc);
running = 0;
}
}
@@ -149,6 +150,7 @@ static void signal_handler(int signo)
{
close(sockfd);
running = 0;
exit_sig = signo;
}
static int recv_frame(struct can_frame *frame)
@@ -235,9 +237,10 @@ static int can_echo_dut(void)
static int can_echo_gen(void)
{
struct can_frame tx_frames[CAN_MSG_COUNT];
int recv_tx[CAN_MSG_COUNT];
struct can_frame rx_frame;
unsigned char counter = 0;
int send_pos = 0, recv_pos = 0, unprocessed = 0, loops = 0;
int send_pos = 0, recv_rx_pos = 0, recv_tx_pos = 0, unprocessed = 0, loops = 0;
int i;
while (running) {
@@ -245,16 +248,13 @@ static int can_echo_gen(void)
/* still send messages */
tx_frames[send_pos].can_dlc = CAN_MSG_LEN;
tx_frames[send_pos].can_id = CAN_MSG_ID;
recv_tx[send_pos] = 0;
for (i = 0; i < CAN_MSG_LEN; i++)
tx_frames[send_pos].data[i] = counter + i;
if (send_frame(&tx_frames[send_pos]))
return -1;
/* increment to be equal to expected */
tx_frames[send_pos].can_id++;
for (i = 0; i < CAN_MSG_LEN; i++)
tx_frames[send_pos].data[i]++;
send_pos++;
if (send_pos == CAN_MSG_COUNT)
send_pos = 0;
@@ -272,18 +272,32 @@ static int can_echo_gen(void)
return -1;
if (verbose > 1)
print_frame(&rx_frame);
print_frame(&rx_frame, 0);
/* compare with expected */
compare_frame(&tx_frames[recv_pos], &rx_frame);
/* own frame */
if (rx_frame.can_id == CAN_MSG_ID) {
compare_frame(&tx_frames[recv_tx_pos], &rx_frame, 0);
recv_tx[recv_tx_pos] = 1;
recv_tx_pos++;
if (recv_tx_pos == CAN_MSG_COUNT)
recv_tx_pos = 0;
continue;
} else {
if (!recv_tx[recv_rx_pos]) {
printf("RX before TX!\n");
running = 0;
}
/* compare with expected */
compare_frame(&tx_frames[recv_rx_pos], &rx_frame, 1);
recv_rx_pos++;
if (recv_rx_pos == CAN_MSG_COUNT)
recv_rx_pos = 0;
}
loops++;
if (test_loops && loops >= test_loops)
break;
recv_pos++;
if (recv_pos == CAN_MSG_COUNT)
recv_pos = 0;
unprocessed--;
}
}
@@ -300,6 +314,7 @@ int main(int argc, char *argv[])
int family = PF_CAN, type = SOCK_RAW, proto = CAN_RAW;
int echo_gen = 0;
int opt, err;
int recv_own_msgs = 1;
signal(SIGTERM, signal_handler);
signal(SIGHUP, signal_handler);
@@ -337,6 +352,14 @@ int main(int argc, char *argv[])
return 1;
}
if (echo_gen) {
if (setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS,
&recv_own_msgs, sizeof(recv_own_msgs)) == -1) {
perror("setsockopt");
return 1;
}
}
addr.can_family = family;
addr.can_ifindex = if_nametoindex(intf_name);
@@ -355,5 +378,11 @@ int main(int argc, char *argv[])
printf("Exiting...\n");
close(sockfd);
if (exit_sig) {
signal(exit_sig, SIG_DFL);
kill(getpid(), exit_sig);
}
return err;
}
+1
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* canframelen.c
*
+1
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* canframelen.h
*
+1
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* cangen.c - CAN frames generator for testing purposes
*
+185 -19
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* cangw.c - manage PF_CAN netlink gateway
*
@@ -67,6 +68,12 @@ struct modattr {
__u8 instruction;
} __attribute__((packed));
struct fdmodattr {
struct canfd_frame cf;
__u8 modtype;
__u8 instruction;
} __attribute__((packed));
#define RTCAN_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct rtcanmsg))))
#define RTCAN_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct rtcanmsg))
@@ -124,7 +131,36 @@ void printmod(const char *type, const void *data)
printf(":%03X.%X.", mod.cf.can_id, mod.cf.can_dlc);
for (i = 0; i < 8; i++)
for (i = 0; i < CAN_MAX_DLEN; i++)
printf("%02X", mod.cf.data[i]);
printf(" ");
}
void printfdmod(const char *type, const void *data)
{
struct fdmodattr mod;
int i;
memcpy (&mod, data, CGW_FDMODATTR_LEN);
printf("-M %s:", type);
if (mod.modtype & CGW_MOD_ID)
printf("I");
if (mod.modtype & CGW_MOD_FLAGS)
printf("F");
if (mod.modtype & CGW_MOD_LEN)
printf("L");
if (mod.modtype & CGW_MOD_DATA)
printf("D");
printf(":%03X.%X.%X.", mod.cf.can_id, mod.cf.flags, mod.cf.len);
for (i = 0; i < CANFD_MAX_DLEN; i++)
printf("%02X", mod.cf.data[i]);
printf(" ");
@@ -193,13 +229,15 @@ void print_usage(char *prg)
fprintf(stderr, " -L (list all rules)\n");
fprintf(stderr, "Mandatory: -s <src_dev> (source netdevice)\n");
fprintf(stderr, " -d <dst_dev> (destination netdevice)\n");
fprintf(stderr, "Options: -t (preserve src_dev rx timestamp)\n");
fprintf(stderr, "Options: -X (this is a CAN FD rule)\n");
fprintf(stderr, " -t (preserve src_dev rx timestamp)\n");
fprintf(stderr, " -e (echo sent frames - recommended on vcanx)\n");
fprintf(stderr, " -i (allow to route to incoming interface)\n");
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 frame modifications)\n");
fprintf(stderr, " -m <mod> (set Classic 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");
fprintf(stderr, " -p <profile>:[<profile_data>] (CRC8 checksum profile & parameters)\n");
@@ -216,6 +254,14 @@ void print_usage(char *prg)
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_data> is always eight(!) u8 values containing the CAN frames data\n");
fprintf(stderr, "<MOD> is a CAN FD frame modification instruction consisting of\n");
fprintf(stderr, "<instruction>:<canfd_frame-elements>:<can_id>.<flags>.<len>.<can_data>\n");
fprintf(stderr, " - <instruction> is one of 'AND' 'OR' 'XOR' 'SET'\n");
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, " - <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");
fprintf(stderr, "Example:\n");
@@ -281,7 +327,8 @@ int parse_crc8_profile(char *optarg, struct cgw_csum_crc8 *crc8)
int parse_mod(char *optarg, struct modattr *modmsg)
{
char *ptr, *nptr;
char hexdata[17] = {0};
char hexdata[(CAN_MAX_DLEN * 2) + 1] = {0};
canid_t can_id;
ptr = optarg;
nptr = strchr(ptr, ':');
@@ -330,30 +377,97 @@ int parse_mod(char *optarg, struct modattr *modmsg)
ptr++;
}
if (sscanf(++ptr, "%x.%hhx.%16s", &modmsg->cf.can_id,
if (sscanf(++ptr, "%x.%hhx.%16s", &can_id,
(unsigned char *)&modmsg->cf.can_dlc, hexdata) != 3)
return 5;
/* 4-bit masks can have values from 0 to 0xF */
if (modmsg->cf.can_dlc > 0xF)
modmsg->cf.can_id = can_id;
if (strlen(hexdata) != (CAN_MAX_DLEN * 2))
return 6;
/* but when setting CAN_DLC the value has to be limited to 8 */
if (modmsg->instruction == CGW_MOD_SET && modmsg->cf.can_dlc > 8)
if (b64hex(hexdata, &modmsg->cf.data[0], CAN_MAX_DLEN))
return 7;
if (strlen(hexdata) != 16)
return 8;
return 0; /* ok */
}
if (b64hex(hexdata, &modmsg->cf.data[0], 8))
return 9;
int parse_fdmod(char *optarg, struct fdmodattr *modmsg)
{
char *ptr, *nptr;
char hexdata[(CANFD_MAX_DLEN * 2) + 1] = {0};
canid_t can_id;
ptr = optarg;
nptr = strchr(ptr, ':');
if ((nptr - ptr > 3) || (nptr - ptr == 0))
return 1;
if (!strncmp(ptr, "AND", 3))
modmsg->instruction = CGW_FDMOD_AND;
else if (!strncmp(ptr, "OR", 2))
modmsg->instruction = CGW_FDMOD_OR;
else if (!strncmp(ptr, "XOR", 3))
modmsg->instruction = CGW_FDMOD_XOR;
else if (!strncmp(ptr, "SET", 3))
modmsg->instruction = CGW_FDMOD_SET;
else
return 2;
ptr = nptr+1;
nptr = strchr(ptr, ':');
if ((nptr - ptr > 4) || (nptr - ptr == 0))
return 3;
modmsg->modtype = 0;
while (*ptr != ':') {
switch (*ptr) {
case 'I':
modmsg->modtype |= CGW_MOD_ID;
break;
case 'F':
modmsg->modtype |= CGW_MOD_FLAGS;
break;
case 'L':
modmsg->modtype |= CGW_MOD_LEN;
break;
case 'D':
modmsg->modtype |= CGW_MOD_DATA;
break;
default:
return 4;
}
ptr++;
}
if (sscanf(++ptr, "%x.%hhx.%hhx.%128s", &can_id,
(unsigned char *)&modmsg->cf.flags,
(unsigned char *)&modmsg->cf.len, hexdata) != 4)
return 5;
modmsg->cf.can_id = can_id;
if (strlen(hexdata) != (CANFD_MAX_DLEN * 2))
return 6;
if (b64hex(hexdata, &modmsg->cf.data[0], CANFD_MAX_DLEN))
return 7;
return 0; /* ok */
}
int parse_rtlist(char *prgname, unsigned char *rxbuf, int len)
{
char ifname[IF_NAMESIZE]; /* internface name for if_indextoname() */
char ifname[IF_NAMESIZE]; /* interface name for if_indextoname() */
struct rtcanmsg *rtc;
struct rtattr *rta;
struct nlmsghdr *nlh;
@@ -419,6 +533,10 @@ int parse_rtlist(char *prgname, unsigned char *rxbuf, int len)
case CGW_MOD_OR:
case CGW_MOD_XOR:
case CGW_MOD_SET:
case CGW_FDMOD_AND:
case CGW_FDMOD_OR:
case CGW_FDMOD_XOR:
case CGW_FDMOD_SET:
case CGW_MOD_UID:
case CGW_LIM_HOPS:
case CGW_CS_XOR:
@@ -456,6 +574,9 @@ int parse_rtlist(char *prgname, unsigned char *rxbuf, int len)
printf("-s %s ", if_indextoname(src_ifindex, ifname));
printf("-d %s ", if_indextoname(dst_ifindex, ifname));
if (rtc->flags & CGW_FLAGS_CAN_FD)
printf("-X ");
if (rtc->flags & CGW_FLAGS_CAN_ECHO)
printf("-e ");
@@ -493,6 +614,22 @@ int parse_rtlist(char *prgname, unsigned char *rxbuf, int len)
printmod("SET", RTA_DATA(rta));
break;
case CGW_FDMOD_AND:
printfdmod("AND", RTA_DATA(rta));
break;
case CGW_FDMOD_OR:
printfdmod("OR", RTA_DATA(rta));
break;
case CGW_FDMOD_XOR:
printfdmod("XOR", RTA_DATA(rta));
break;
case CGW_FDMOD_SET:
printfdmod("SET", RTA_DATA(rta));
break;
case CGW_MOD_UID:
printf("-u %X ", *(__u32 *)RTA_DATA(rta));
break;
@@ -548,8 +685,7 @@ int main(int argc, char **argv)
struct {
struct nlmsghdr nh;
struct rtcanmsg rtcan;
char buf[600];
char buf[1500];
} req;
unsigned char rxbuf[8192]; /* netlink receive buffer */
@@ -570,14 +706,16 @@ int main(int argc, char **argv)
char crc8tab[513] = {0};
struct modattr modmsg[CGW_MOD_FUNCS];
struct fdmodattr fdmodmsg[CGW_MOD_FUNCS];
int modidx = 0;
int fdmodidx = 0;
int i;
memset(&req, 0, sizeof(req));
memset(&cs_xor, 0, sizeof(cs_xor));
memset(&cs_crc8, 0, sizeof(cs_crc8));
while ((opt = getopt(argc, argv, "ADFLs:d:teiu:l:f:c:p:x:m:?")) != -1) {
while ((opt = getopt(argc, argv, "ADFLs:d:Xteiu:l:f:c:p:x:m:M:?")) != -1) {
switch (opt) {
case 'A':
@@ -608,6 +746,10 @@ int main(int argc, char **argv)
dst_ifindex = if_nametoindex(optarg);
break;
case 'X':
flags |= CGW_FLAGS_CAN_FD;
break;
case 't':
flags |= CGW_FLAGS_CAN_SRC_TSTAMP;
break;
@@ -685,6 +827,14 @@ int main(int argc, char **argv)
}
break;
case 'M':
/* may be triggered by each of the CGW_FDMOD_FUNCS functions */
if ((fdmodidx < CGW_MOD_FUNCS) && (err = parse_fdmod(optarg, &fdmodmsg[fdmodidx++]))) {
printf("Problem %d with modification definition '%s'.\n", err, optarg);
exit(1);
}
break;
case '?':
print_usage(basename(argv[0]));
exit(0);
@@ -709,8 +859,20 @@ int main(int argc, char **argv)
exit(1);
}
if (!modidx && (have_cs_crc8 || have_cs_xor)) {
printf("-c or -x can only be used in conjunction with -m\n");
if (flags & CGW_FLAGS_CAN_FD) {
if (modidx) {
printf("No -m modifications allowed in CAN FD mode!\n");
exit(1);
}
} else {
if (fdmodidx) {
printf("No -M modifications allowed in Classic CAN mode!\n");
exit(1);
}
}
if ((!modidx && !fdmodidx) && (have_cs_crc8 || have_cs_xor)) {
printf("-c or -x can only be used in conjunction with -m/-M\n");
exit(1);
}
@@ -784,6 +946,10 @@ int main(int argc, char **argv)
for (i = 0; i < modidx; i++)
addattr_l(&req.nh, sizeof(req), modmsg[i].instruction, &modmsg[i], CGW_MODATTR_LEN);
/* add up to CGW_FDMOD_FUNCS modification definitions */
for (i = 0; i < fdmodidx; i++)
addattr_l(&req.nh, sizeof(req), fdmodmsg[i].instruction, &fdmodmsg[i], CGW_FDMODATTR_LEN);
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = 0;
+2
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* canlogserver.c
*
@@ -61,6 +62,7 @@
#include <linux/can.h>
#include <linux/can/raw.h>
#include <linux/sockios.h>
#include <signal.h>
#include <errno.h>
+2 -1
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* canplayer.c - replay a compact CAN frame logfile to CAN devices
*
@@ -348,7 +349,7 @@ int main(int argc, char **argv)
}
if (assignments) {
/* add & check user assginments from commandline */
/* add & check user assignments from commandline */
for (i=0; i<assignments; i++) {
if (strlen(argv[optind+i]) >= BUFSZ) {
fprintf(stderr, "Assignment too long!\n");
+8 -3
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* cansend.c - simple command line tool to send CAN-frames via CAN_RAW sockets
*
@@ -75,16 +76,19 @@ int main(int argc, char **argv)
required_mtu = parse_canframe(argv[2], &frame);
if (!required_mtu){
fprintf(stderr, "\nWrong CAN-frame format! Try:\n\n");
fprintf(stderr, " <can_id>#{R|data} for CAN 2.0 frames\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 RTR frames\n");
fprintf(stderr, " <can_id>##<flags>{data} for CAN FD frames\n\n");
fprintf(stderr, "<can_id> can have 3 (SFF) or 8 (EFF) hex chars\n");
fprintf(stderr, "{data} has 0..8 (0..64 CAN FD) ASCII hex-values (optionally");
fprintf(stderr, " separated by '.')\n");
fprintf(stderr, "{len} is an optional 0..8 value as RTR frames can contain a");
fprintf(stderr, " valid dlc field\n");
fprintf(stderr, "<flags> a single ASCII Hex value (0 .. F) which defines");
fprintf(stderr, " canfd_frame.flags\n\n");
fprintf(stderr, "e.g. 5A1#11.2233.44556677.88 / 123#DEADBEEF / 5AA# / ");
fprintf(stderr, "123##1 / 213##311\n 1F334455#1122334455667788 / 123#R ");
fprintf(stderr, "for remote transmission request.\n\n");
fprintf(stderr, "123##1 / 213##311223344\n 1F334455#1122334455667788 / ");
fprintf(stderr, "123#R / 00000123#R3\n\n");
return 1;
}
@@ -102,6 +106,7 @@ int main(int argc, char **argv)
return 1;
}
memset(&addr, 0, sizeof(addr));
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
+8 -3
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* cansniffer.c
*
@@ -61,6 +62,7 @@
#include <linux/can.h>
#include <linux/can/bcm.h>
#include <linux/sockios.h>
#include "terminal.h"
@@ -690,12 +692,15 @@ void writesettings(char* name){
for (i=0; i < 2048 ;i++) {
sprintf(buf, "<%03X>%c.", i, (is_set(i, ENABLE))?'1':'0');
write(fd, buf, 7);
if (write(fd, buf, 7) < 0)
perror("write");
for (j=0; j<8 ; j++){
sprintf(buf, "%02X", sniftab[i].notch.data[j]);
write(fd, buf, 2);
if (write(fd, buf, 2) < 0)
perror("write");
}
write(fd, "\n", 1);
if (write(fd, "\n", 1) < 0)
perror("write");
/* 7 + 16 + 1 = 24 bytes per entry */
}
close(fd);
+19
View File
@@ -0,0 +1,19 @@
if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt")
message(FATAL_ERROR "Cannot find install manifest: ${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt")
endif()
file(READ "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt" files)
string(REGEX REPLACE "[\r\n]" ";" files "${files}")
foreach(file ${files})
message(STATUS "Uninstalling ${file}")
if(EXISTS "${file}")
file(REMOVE ${file})
if (EXISTS "${file}")
message(FATAL_ERROR "Problem when removing ${file}, please check your permissions")
endif()
else()
message(STATUS "File ${file} does not exist.")
endif()
endforeach()
+3
View File
@@ -88,6 +88,9 @@ AC_CHECK_DECL(AF_CAN,,
AC_CHECK_DECL(N_SLCAN,,
[AC_DEFINE([N_SLCAN], [17], [N_SLCAN])]
)
AC_CHECK_DECL(SCM_TIMESTAMPING_OPT_STATS,,
[AC_DEFINE([SCM_TIMESTAMPING_OPT_STATS], [54], [SCM_TIMESTAMPING_OPT_STATS])]
)
AC_DEFINE(_GNU_SOURCE)
+3 -6
View File
@@ -1,4 +1,4 @@
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
/* SPDX-License-Identifier: ((GPL-2.0-only WITH Linux-syscall-note) OR BSD-3-Clause) */
/*
* linux/can.h
*
@@ -77,7 +77,7 @@ typedef __u32 canid_t;
/*
* Controller Area Network Error Message Frame Mask structure
*
* bit 0-28 : error class mask (see include/linux/can/error.h)
* bit 0-28 : error class mask (see include/uapi/linux/can/error.h)
* bit 29-31 : set to zero
*/
typedef __u32 can_err_mask_t;
@@ -181,10 +181,7 @@ struct sockaddr_can {
int can_ifindex;
union {
/* transport protocol class address information (e.g. ISOTP) */
struct {
canid_t rx_id;
canid_t tx_id;
} tp;
struct { canid_t rx_id, tx_id; } tp;
/* J1939 address information */
struct {
+1 -1
View File
@@ -1,4 +1,4 @@
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
/* SPDX-License-Identifier: ((GPL-2.0-only WITH Linux-syscall-note) OR BSD-3-Clause) */
/*
* linux/can/bcm.h
*
+1 -1
View File
@@ -1,4 +1,4 @@
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
/* SPDX-License-Identifier: ((GPL-2.0-only WITH Linux-syscall-note) OR BSD-3-Clause) */
/*
* linux/can/error.h
*
+16 -3
View File
@@ -1,4 +1,4 @@
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
/* SPDX-License-Identifier: ((GPL-2.0-only WITH Linux-syscall-note) OR BSD-3-Clause) */
/*
* linux/can/gw.h
*
@@ -80,6 +80,10 @@ enum {
CGW_DELETED, /* number of deleted CAN frames (see max_hops param) */
CGW_LIM_HOPS, /* limit the number of hops of this specific rule */
CGW_MOD_UID, /* user defined identifier for modification updates */
CGW_FDMOD_AND, /* CAN FD frame modification binary AND */
CGW_FDMOD_OR, /* CAN FD frame modification binary OR */
CGW_FDMOD_XOR, /* CAN FD frame modification binary XOR */
CGW_FDMOD_SET, /* CAN FD frame modification set alternate values */
__CGW_MAX
};
@@ -88,15 +92,18 @@ enum {
#define CGW_FLAGS_CAN_ECHO 0x01
#define CGW_FLAGS_CAN_SRC_TSTAMP 0x02
#define CGW_FLAGS_CAN_IIF_TX_OK 0x04
#define CGW_FLAGS_CAN_FD 0x08
#define CGW_MOD_FUNCS 4 /* AND OR XOR SET */
/* CAN frame elements that are affected by curr. 3 CAN frame modifications */
#define CGW_MOD_ID 0x01
#define CGW_MOD_DLC 0x02
#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_DATA 0x04
#define CGW_MOD_FLAGS 0x08 /* CAN FD flags */
#define CGW_FRAME_MODS 3 /* ID DLC DATA */
#define CGW_FRAME_MODS 4 /* ID DLC/LEN DATA FLAGS */
#define MAX_MODFUNCTIONS (CGW_MOD_FUNCS * CGW_FRAME_MODS)
@@ -105,7 +112,13 @@ struct cgw_frame_mod {
__u8 modtype;
} __attribute__((packed));
struct cgw_fdframe_mod {
struct canfd_frame cf;
__u8 modtype;
} __attribute__((packed));
#define CGW_MODATTR_LEN sizeof(struct cgw_frame_mod)
#define CGW_FDMODATTR_LEN sizeof(struct cgw_fdframe_mod)
struct cgw_csum_xor {
__s8 from_idx;
+24 -7
View File
@@ -1,4 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
/*
* j1939.h
*
@@ -16,9 +16,15 @@
#include <linux/socket.h>
#include <linux/can.h>
#define J1939_IDLE_ADDR 0xfe
#define J1939_NO_ADDR 0xff
#define J1939_MAX_UNICAST_ADDR 0xfd
#define J1939_IDLE_ADDR 0xfe
#define J1939_NO_ADDR 0xff /* == broadcast or no addr */
#define J1939_NO_NAME 0
#define J1939_PGN_REQUEST 0x0ea00 /* Request PG */
#define J1939_PGN_ADDRESS_CLAIMED 0x0ee00 /* Address Claimed */
#define J1939_PGN_ADDRESS_COMMANDED 0x0fed8 /* Commanded Address */
#define J1939_PGN_PDU1_MAX 0x3ff00
#define J1939_PGN_MAX 0x3ffff
#define J1939_NO_PGN 0x40000
/* J1939 Parameter Group Number
@@ -58,23 +64,34 @@ typedef __u64 name_t;
enum {
SO_J1939_FILTER = 1, /* set filters */
SO_J1939_PROMISC = 2, /* set/clr promiscuous mode */
SO_J1939_RECV_OWN = 3,
SO_J1939_SEND_PRIO = 4,
SO_J1939_SEND_PRIO = 3,
SO_J1939_ERRQUEUE = 4,
};
enum {
SCM_J1939_DEST_ADDR = 1,
SCM_J1939_DEST_NAME = 2,
SCM_J1939_PRIO = 3,
SCM_J1939_ERRQUEUE = 4,
};
enum {
J1939_NLA_PAD,
J1939_NLA_BYTES_ACKED,
};
enum {
J1939_EE_INFO_NONE,
J1939_EE_INFO_TX_ABORT,
};
struct j1939_filter {
name_t name;
name_t name_mask;
__u8 addr;
__u8 addr_mask;
pgn_t pgn;
pgn_t pgn_mask;
__u8 addr;
__u8 addr_mask;
};
#define J1939_FILTER_MAX 512 /* maximum number of j1939_filter set via setsockopt() */
+4 -4
View File
@@ -1,4 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
/*
* linux/can/netlink.h
*
@@ -40,15 +40,15 @@ struct can_bittiming {
};
/*
* CAN harware-dependent bit-timing constant
* CAN hardware-dependent bit-timing constant
*
* Used for calculating and checking bit-timing parameters
*/
struct can_bittiming_const {
char name[16]; /* Name of the CAN controller hardware */
__u32 tseg1_min; /* Time segement 1 = prop_seg + phase_seg1 */
__u32 tseg1_min; /* Time segment 1 = prop_seg + phase_seg1 */
__u32 tseg1_max;
__u32 tseg2_min; /* Time segement 2 = phase_seg2 */
__u32 tseg2_min; /* Time segment 2 = phase_seg2 */
__u32 tseg2_max;
__u32 sjw_max; /* Synchronisation jump width */
__u32 brp_min; /* Bit-rate prescaler */
+1 -1
View File
@@ -1,4 +1,4 @@
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
/* SPDX-License-Identifier: ((GPL-2.0-only WITH Linux-syscall-note) OR BSD-3-Clause) */
/*
* linux/can/raw.h
*
+1 -1
View File
@@ -1,4 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
#ifndef _UAPI_CAN_VXCAN_H
#define _UAPI_CAN_VXCAN_H
+54
View File
@@ -0,0 +1,54 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _UAPI_LINUX_ERRQUEUE_H
#define _UAPI_LINUX_ERRQUEUE_H
#include <linux/types.h>
struct sock_extended_err {
__u32 ee_errno;
__u8 ee_origin;
__u8 ee_type;
__u8 ee_code;
__u8 ee_pad;
__u32 ee_info;
__u32 ee_data;
};
#define SO_EE_ORIGIN_NONE 0
#define SO_EE_ORIGIN_LOCAL 1
#define SO_EE_ORIGIN_ICMP 2
#define SO_EE_ORIGIN_ICMP6 3
#define SO_EE_ORIGIN_TXSTATUS 4
#define SO_EE_ORIGIN_ZEROCOPY 5
#define SO_EE_ORIGIN_TXTIME 6
#define SO_EE_ORIGIN_TIMESTAMPING SO_EE_ORIGIN_TXSTATUS
#define SO_EE_OFFENDER(ee) ((struct sockaddr*)((ee)+1))
#define SO_EE_CODE_ZEROCOPY_COPIED 1
#define SO_EE_CODE_TXTIME_INVALID_PARAM 1
#define SO_EE_CODE_TXTIME_MISSED 2
/**
* struct scm_timestamping - timestamps exposed through cmsg
*
* The timestamping interfaces SO_TIMESTAMPING, MSG_TSTAMP_*
* communicate network timestamps by passing this struct in a cmsg with
* recvmsg(). See Documentation/networking/timestamping.txt for details.
*/
struct scm_timestamping {
struct timespec ts[3];
};
/* The type of scm_timestamping, passed in sock_extended_err ee_info.
* This defines the type of ts[0]. For SCM_TSTAMP_SND only, if ts[0]
* is zero, then this is a hardware timestamp and recorded in ts[2].
*/
enum {
SCM_TSTAMP_SND, /* driver passed skb to NIC, or HW */
SCM_TSTAMP_SCHED, /* data entered the packet scheduler */
SCM_TSTAMP_ACK, /* data acknowledged by peer */
};
#endif /* _UAPI_LINUX_ERRQUEUE_H */
+162
View File
@@ -0,0 +1,162 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* Userspace API for hardware time stamping of network packets
*
* Copyright (C) 2008,2009 Intel Corporation
* Author: Patrick Ohly <patrick.ohly@intel.com>
*
*/
#ifndef _NET_TIMESTAMPING_H
#define _NET_TIMESTAMPING_H
#include <linux/types.h>
#include <linux/socket.h> /* for SO_TIMESTAMPING */
/* SO_TIMESTAMPING gets an integer bit field comprised of these values */
enum {
SOF_TIMESTAMPING_TX_HARDWARE = (1<<0),
SOF_TIMESTAMPING_TX_SOFTWARE = (1<<1),
SOF_TIMESTAMPING_RX_HARDWARE = (1<<2),
SOF_TIMESTAMPING_RX_SOFTWARE = (1<<3),
SOF_TIMESTAMPING_SOFTWARE = (1<<4),
SOF_TIMESTAMPING_SYS_HARDWARE = (1<<5),
SOF_TIMESTAMPING_RAW_HARDWARE = (1<<6),
SOF_TIMESTAMPING_OPT_ID = (1<<7),
SOF_TIMESTAMPING_TX_SCHED = (1<<8),
SOF_TIMESTAMPING_TX_ACK = (1<<9),
SOF_TIMESTAMPING_OPT_CMSG = (1<<10),
SOF_TIMESTAMPING_OPT_TSONLY = (1<<11),
SOF_TIMESTAMPING_OPT_STATS = (1<<12),
SOF_TIMESTAMPING_OPT_PKTINFO = (1<<13),
SOF_TIMESTAMPING_OPT_TX_SWHW = (1<<14),
SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_TX_SWHW,
SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) |
SOF_TIMESTAMPING_LAST
};
/*
* SO_TIMESTAMPING flags are either for recording a packet timestamp or for
* reporting the timestamp to user space.
* Recording flags can be set both via socket options and control messages.
*/
#define SOF_TIMESTAMPING_TX_RECORD_MASK (SOF_TIMESTAMPING_TX_HARDWARE | \
SOF_TIMESTAMPING_TX_SOFTWARE | \
SOF_TIMESTAMPING_TX_SCHED | \
SOF_TIMESTAMPING_TX_ACK)
/**
* struct hwtstamp_config - %SIOCGHWTSTAMP and %SIOCSHWTSTAMP parameter
*
* @flags: no flags defined right now, must be zero for %SIOCSHWTSTAMP
* @tx_type: one of HWTSTAMP_TX_*
* @rx_filter: one of HWTSTAMP_FILTER_*
*
* %SIOCGHWTSTAMP and %SIOCSHWTSTAMP expect a &struct ifreq with a
* ifr_data pointer to this structure. For %SIOCSHWTSTAMP, if the
* driver or hardware does not support the requested @rx_filter value,
* the driver may use a more general filter mode. In this case
* @rx_filter will indicate the actual mode on return.
*/
struct hwtstamp_config {
int flags;
int tx_type;
int rx_filter;
};
/* possible values for hwtstamp_config->tx_type */
enum hwtstamp_tx_types {
/*
* No outgoing packet will need hardware time stamping;
* should a packet arrive which asks for it, no hardware
* time stamping will be done.
*/
HWTSTAMP_TX_OFF,
/*
* Enables hardware time stamping for outgoing packets;
* the sender of the packet decides which are to be
* time stamped by setting %SOF_TIMESTAMPING_TX_SOFTWARE
* before sending the packet.
*/
HWTSTAMP_TX_ON,
/*
* Enables time stamping for outgoing packets just as
* HWTSTAMP_TX_ON does, but also enables time stamp insertion
* directly into Sync packets. In this case, transmitted Sync
* packets will not received a time stamp via the socket error
* queue.
*/
HWTSTAMP_TX_ONESTEP_SYNC,
};
/* possible values for hwtstamp_config->rx_filter */
enum hwtstamp_rx_filters {
/* time stamp no incoming packet at all */
HWTSTAMP_FILTER_NONE,
/* time stamp any incoming packet */
HWTSTAMP_FILTER_ALL,
/* return value: time stamp all packets requested plus some others */
HWTSTAMP_FILTER_SOME,
/* PTP v1, UDP, any kind of event packet */
HWTSTAMP_FILTER_PTP_V1_L4_EVENT,
/* PTP v1, UDP, Sync packet */
HWTSTAMP_FILTER_PTP_V1_L4_SYNC,
/* PTP v1, UDP, Delay_req packet */
HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ,
/* PTP v2, UDP, any kind of event packet */
HWTSTAMP_FILTER_PTP_V2_L4_EVENT,
/* PTP v2, UDP, Sync packet */
HWTSTAMP_FILTER_PTP_V2_L4_SYNC,
/* PTP v2, UDP, Delay_req packet */
HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ,
/* 802.AS1, Ethernet, any kind of event packet */
HWTSTAMP_FILTER_PTP_V2_L2_EVENT,
/* 802.AS1, Ethernet, Sync packet */
HWTSTAMP_FILTER_PTP_V2_L2_SYNC,
/* 802.AS1, Ethernet, Delay_req packet */
HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ,
/* PTP v2/802.AS1, any layer, any kind of event packet */
HWTSTAMP_FILTER_PTP_V2_EVENT,
/* PTP v2/802.AS1, any layer, Sync packet */
HWTSTAMP_FILTER_PTP_V2_SYNC,
/* PTP v2/802.AS1, any layer, Delay_req packet */
HWTSTAMP_FILTER_PTP_V2_DELAY_REQ,
/* NTP, UDP, all versions and packet modes */
HWTSTAMP_FILTER_NTP_ALL,
};
/* SCM_TIMESTAMPING_PKTINFO control message */
struct scm_ts_pktinfo {
__u32 if_index;
__u32 pkt_length;
__u32 reserved[2];
};
/*
* SO_TXTIME gets a struct sock_txtime with flags being an integer bit
* field comprised of these values.
*/
enum txtime_flags {
SOF_TXTIME_DEADLINE_MODE = (1 << 0),
SOF_TXTIME_REPORT_ERRORS = (1 << 1),
SOF_TXTIME_FLAGS_LAST = SOF_TXTIME_REPORT_ERRORS,
SOF_TXTIME_FLAGS_MASK = (SOF_TXTIME_FLAGS_LAST - 1) |
SOF_TXTIME_FLAGS_LAST
};
struct sock_txtime {
__kernel_clockid_t clockid;/* reference clockid */
__u32 flags; /* as defined by enum txtime_flags */
};
#endif /* _NET_TIMESTAMPING_H */
+252
View File
@@ -0,0 +1,252 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _UAPI__LINUX_NETLINK_H
#define _UAPI__LINUX_NETLINK_H
#include <linux/kernel.h>
#include <linux/socket.h> /* for __kernel_sa_family_t */
#include <linux/types.h>
#define NETLINK_ROUTE 0 /* Routing/device hook */
#define NETLINK_UNUSED 1 /* Unused number */
#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */
#define NETLINK_FIREWALL 3 /* Unused number, formerly ip_queue */
#define NETLINK_SOCK_DIAG 4 /* socket monitoring */
#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */
#define NETLINK_XFRM 6 /* ipsec */
#define NETLINK_SELINUX 7 /* SELinux event notifications */
#define NETLINK_ISCSI 8 /* Open-iSCSI */
#define NETLINK_AUDIT 9 /* auditing */
#define NETLINK_FIB_LOOKUP 10
#define NETLINK_CONNECTOR 11
#define NETLINK_NETFILTER 12 /* netfilter subsystem */
#define NETLINK_IP6_FW 13
#define NETLINK_DNRTMSG 14 /* DECnet routing messages */
#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */
#define NETLINK_GENERIC 16
/* leave room for NETLINK_DM (DM Events) */
#define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */
#define NETLINK_ECRYPTFS 19
#define NETLINK_RDMA 20
#define NETLINK_CRYPTO 21 /* Crypto layer */
#define NETLINK_SMC 22 /* SMC monitoring */
#define NETLINK_INET_DIAG NETLINK_SOCK_DIAG
#define MAX_LINKS 32
struct sockaddr_nl {
__kernel_sa_family_t nl_family; /* AF_NETLINK */
unsigned short nl_pad; /* zero */
__u32 nl_pid; /* port ID */
__u32 nl_groups; /* multicast groups mask */
};
struct nlmsghdr {
__u32 nlmsg_len; /* Length of message including header */
__u16 nlmsg_type; /* Message content */
__u16 nlmsg_flags; /* Additional flags */
__u32 nlmsg_seq; /* Sequence number */
__u32 nlmsg_pid; /* Sending process port ID */
};
/* Flags values */
#define NLM_F_REQUEST 0x01 /* It is request message. */
#define NLM_F_MULTI 0x02 /* Multipart message, terminated by NLMSG_DONE */
#define NLM_F_ACK 0x04 /* Reply with ack, with zero or error code */
#define NLM_F_ECHO 0x08 /* Echo this request */
#define NLM_F_DUMP_INTR 0x10 /* Dump was inconsistent due to sequence change */
#define NLM_F_DUMP_FILTERED 0x20 /* Dump was filtered as requested */
/* Modifiers to GET request */
#define NLM_F_ROOT 0x100 /* specify tree root */
#define NLM_F_MATCH 0x200 /* return all matching */
#define NLM_F_ATOMIC 0x400 /* atomic GET */
#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH)
/* Modifiers to NEW request */
#define NLM_F_REPLACE 0x100 /* Override existing */
#define NLM_F_EXCL 0x200 /* Do not touch, if it exists */
#define NLM_F_CREATE 0x400 /* Create, if it does not exist */
#define NLM_F_APPEND 0x800 /* Add to end of list */
/* Modifiers to DELETE request */
#define NLM_F_NONREC 0x100 /* Do not delete recursively */
/* Flags for ACK message */
#define NLM_F_CAPPED 0x100 /* request was capped */
#define NLM_F_ACK_TLVS 0x200 /* extended ACK TVLs were included */
/*
4.4BSD ADD NLM_F_CREATE|NLM_F_EXCL
4.4BSD CHANGE NLM_F_REPLACE
True CHANGE NLM_F_CREATE|NLM_F_REPLACE
Append NLM_F_CREATE
Check NLM_F_EXCL
*/
#define NLMSG_ALIGNTO 4U
#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
#define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN)
#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
(struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \
(nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
(nlh)->nlmsg_len <= (len))
#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
#define NLMSG_NOOP 0x1 /* Nothing. */
#define NLMSG_ERROR 0x2 /* Error */
#define NLMSG_DONE 0x3 /* End of a dump */
#define NLMSG_OVERRUN 0x4 /* Data lost */
#define NLMSG_MIN_TYPE 0x10 /* < 0x10: reserved control messages */
struct nlmsgerr {
int error;
struct nlmsghdr msg;
/*
* followed by the message contents unless NETLINK_CAP_ACK was set
* or the ACK indicates success (error == 0)
* message length is aligned with NLMSG_ALIGN()
*/
/*
* followed by TLVs defined in enum nlmsgerr_attrs
* if NETLINK_EXT_ACK was set
*/
};
/**
* enum nlmsgerr_attrs - nlmsgerr attributes
* @NLMSGERR_ATTR_UNUSED: unused
* @NLMSGERR_ATTR_MSG: error message string (string)
* @NLMSGERR_ATTR_OFFS: offset of the invalid attribute in the original
* message, counting from the beginning of the header (u32)
* @NLMSGERR_ATTR_COOKIE: arbitrary subsystem specific cookie to
* be used - in the success case - to identify a created
* object or operation or similar (binary)
* @__NLMSGERR_ATTR_MAX: number of attributes
* @NLMSGERR_ATTR_MAX: highest attribute number
*/
enum nlmsgerr_attrs {
NLMSGERR_ATTR_UNUSED,
NLMSGERR_ATTR_MSG,
NLMSGERR_ATTR_OFFS,
NLMSGERR_ATTR_COOKIE,
__NLMSGERR_ATTR_MAX,
NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
};
#define NETLINK_ADD_MEMBERSHIP 1
#define NETLINK_DROP_MEMBERSHIP 2
#define NETLINK_PKTINFO 3
#define NETLINK_BROADCAST_ERROR 4
#define NETLINK_NO_ENOBUFS 5
#ifndef __KERNEL__
#define NETLINK_RX_RING 6
#define NETLINK_TX_RING 7
#endif
#define NETLINK_LISTEN_ALL_NSID 8
#define NETLINK_LIST_MEMBERSHIPS 9
#define NETLINK_CAP_ACK 10
#define NETLINK_EXT_ACK 11
#define NETLINK_GET_STRICT_CHK 12
struct nl_pktinfo {
__u32 group;
};
struct nl_mmap_req {
unsigned int nm_block_size;
unsigned int nm_block_nr;
unsigned int nm_frame_size;
unsigned int nm_frame_nr;
};
struct nl_mmap_hdr {
unsigned int nm_status;
unsigned int nm_len;
__u32 nm_group;
/* credentials */
__u32 nm_pid;
__u32 nm_uid;
__u32 nm_gid;
};
#ifndef __KERNEL__
enum nl_mmap_status {
NL_MMAP_STATUS_UNUSED,
NL_MMAP_STATUS_RESERVED,
NL_MMAP_STATUS_VALID,
NL_MMAP_STATUS_COPY,
NL_MMAP_STATUS_SKIP,
};
#define NL_MMAP_MSG_ALIGNMENT NLMSG_ALIGNTO
#define NL_MMAP_MSG_ALIGN(sz) __ALIGN_KERNEL(sz, NL_MMAP_MSG_ALIGNMENT)
#define NL_MMAP_HDRLEN NL_MMAP_MSG_ALIGN(sizeof(struct nl_mmap_hdr))
#endif
#define NET_MAJOR 36 /* Major 36 is reserved for networking */
enum {
NETLINK_UNCONNECTED = 0,
NETLINK_CONNECTED,
};
/*
* <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
* +---------------------+- - -+- - - - - - - - - -+- - -+
* | Header | Pad | Payload | Pad |
* | (struct nlattr) | ing | | ing |
* +---------------------+- - -+- - - - - - - - - -+- - -+
* <-------------- nlattr->nla_len -------------->
*/
struct nlattr {
__u16 nla_len;
__u16 nla_type;
};
/*
* nla_type (16 bits)
* +---+---+-------------------------------+
* | N | O | Attribute Type |
* +---+---+-------------------------------+
* N := Carries nested attributes
* O := Payload stored in network byte order
*
* Note: The N and O flag are mutually exclusive.
*/
#define NLA_F_NESTED (1 << 15)
#define NLA_F_NET_BYTEORDER (1 << 14)
#define NLA_TYPE_MASK ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
#define NLA_ALIGNTO 4
#define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
#define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr)))
/* Generic 32 bitflags attribute content sent to the kernel.
*
* The value is a bitmap that defines the values being set
* The selector is a bitmask that defines which value is legit
*
* Examples:
* value = 0x0, and selector = 0x1
* implies we are selecting bit 1 and we want to set its value to 0.
*
* value = 0x2, and selector = 0x2
* implies we are selecting bit 2 and we want to set its value to 1.
*
*/
struct nla_bitfield32 {
__u32 value;
__u32 selector;
};
#endif /* _UAPI__LINUX_NETLINK_H */
+131 -1
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* isotpdump.c - dump and explain ISO15765-2 protocol CAN frames
*
@@ -47,6 +48,7 @@
#include <string.h>
#include <libgen.h>
#include <time.h>
#include <strings.h>
#include <net/if.h>
#include <sys/types.h>
@@ -55,6 +57,7 @@
#include <linux/can.h>
#include <linux/can/raw.h>
#include <linux/sockios.h>
#include "terminal.h"
#define NO_CAN_ID 0xFFFFFFFFU
@@ -72,10 +75,120 @@ void print_usage(char *prg)
fprintf(stderr, " -c (color mode)\n");
fprintf(stderr, " -a (print data also in ASCII-chars)\n");
fprintf(stderr, " -t <type> (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\n");
fprintf(stderr, " -u (print uds messages)\n");
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
fprintf(stderr, "\nUDS output contains a flag which provides information about the type of the message.\n");
fprintf(stderr, "Flags: [SRQ] = Service Request\n");
fprintf(stderr, " [PSR] = Positive Service Response\n");
fprintf(stderr, " [NRC] = Negative Response Code\n");
fprintf(stderr, " [???] = Unknown (not specified)\n");
fprintf(stderr, "\n");
}
void print_uds_message(int service, int nrc)
{
char *service_name;
char *flag = "[???]";
if ((service >= 0x50 && service <= 0x7E) || (service >= 0xC3 && service <= 0xC8)) {
flag = "[PSR]";
service = service - 0x40;
} else if ((service >= 0x10 && service <= 0x3E) ||
(service >= 0x83 && service <= 0x88) ||
(service >= 0xBA && service <= 0xBE))
flag = "[SRQ]";
switch(service) {
case 0x10: service_name = "DiagnosticSessionControl"; break;
case 0x11: service_name = "ECUReset"; break;
case 0x14: service_name = "ClearDiagnosticInformation"; break;
case 0x19: service_name = "ReadDTCInformation"; break;
case 0x22: service_name = "ReadDataByIdentifier"; break;
case 0x23: service_name = "ReadMemoryByAddress"; break;
case 0x24: service_name = "ReadScalingDataByIdentifier"; break;
case 0x27: service_name = "SecurityAccess"; break;
case 0x28: service_name = "CommunicationControl"; break;
case 0x2A: service_name = "ReadDataByPeriodicIdentifier"; break;
case 0x2C: service_name = "DynamicallyDefineDataIdentifier"; break;
case 0x2E: service_name = "WriteDataByIdentifier"; break;
case 0x2F: service_name = "InputOutputControlByIdentifier"; break;
case 0x31: service_name = "RoutineControl"; break;
case 0x34: service_name = "RequestDownload"; break;
case 0x35: service_name = "RequestUpload"; break;
case 0x36: service_name = "TransferData"; break;
case 0x37: service_name = "RequestTransferExit"; break;
case 0x38: service_name = "RequestFileTransfer"; break;
case 0x3D: service_name = "WriteMemoryByAddress"; break;
case 0x3E: service_name = "TesterPresent"; break;
case 0x83: service_name = "AccessTimingParameter"; break;
case 0x84: service_name = "SecuredDataTransmision"; break;
case 0x85: service_name = "ControlDTCSetting"; break;
case 0x86: service_name = "ResponseOnEvent"; break;
case 0x87: service_name = "LinkControl"; break;
case 0x7F: flag = "[NRC]";
switch (nrc) {
case 0x00: service_name = "positiveResponse"; break;
case 0x10: service_name = "generalReject"; break;
case 0x11: service_name = "serviceNotSupported"; break;
case 0x12: service_name = "sub-functionNotSupported"; break;
case 0x13: service_name = "incorrectMessageLengthOrInvalidFormat"; break;
case 0x14: service_name = "responseTooLong"; break;
case 0x21: service_name = "busyRepeatRequest"; break;
case 0x22: service_name = "conditionsNotCorrect"; break;
case 0x24: service_name = "requestSequenceError"; break;
case 0x25: service_name = "noResponseFromSubnetComponent"; break;
case 0x26: service_name = "FailurePreventsExecutionOfRequestedAction"; break;
case 0x31: service_name = "requestOutOfRange"; break;
case 0x33: service_name = "securityAccessDenied"; break;
case 0x35: service_name = "invalidKey"; break;
case 0x36: service_name = "exceedNumberOfAttempts"; break;
case 0x37: service_name = "requiredTimeDelayNotExpired"; break;
case 0x70: service_name = "uploadDownloadNotAccepted"; break;
case 0x71: service_name = "transferDataSuspended"; break;
case 0x72: service_name = "generalProgrammingFailure"; break;
case 0x73: service_name = "wrongBlockSequenceCounter"; break;
case 0x78: service_name = "requestCorrectlyReceived-ResponsePending"; break;
case 0x7E: service_name = "sub-functionNotSupportedInActiveSession"; break;
case 0x7F: service_name = "serviceNotSupportedInActiveSession"; break;
case 0x81: service_name = "rpmTooHigh"; break;
case 0x82: service_name = "rpmTooLow"; break;
case 0x83: service_name = "engineIsRunning"; break;
case 0x84: service_name = "engineIsNotRunning"; break;
case 0x85: service_name = "engineRunTimeTooLow"; break;
case 0x86: service_name = "temperatureTooHigh"; break;
case 0x87: service_name = "temperatureTooLow"; break;
case 0x88: service_name = "vehicleSpeedTooHigh"; break;
case 0x89: service_name = "vehicleSpeedTooLow"; break;
case 0x8A: service_name = "throttle/PedalTooHigh"; break;
case 0x8B: service_name = "throttle/PedalTooLow"; break;
case 0x8C: service_name = "transmissionRangeNotInNeutral"; break;
case 0x8D: service_name = "transmissionRangeNotInGear"; break;
case 0x8F: service_name = "brakeSwitch(es)NotClosed (Brake Pedal not pressed or not applied)"; break;
case 0x90: service_name = "shifterLeverNotInPark"; break;
case 0x91: service_name = "torqueConverterClutchLocked"; break;
case 0x92: service_name = "voltageTooHigh"; break;
case 0x93: service_name = "voltageTooLow"; break;
default:
if (nrc > 0x37 && nrc < 0x50) {
service_name = "reservedByExtendedDataLinkSecurityDocument"; break;
}
else if (nrc > 0x93 && nrc < 0xF0) {
service_name = "reservedForSpecificConditionsNotCorrect"; break;
}
else if (nrc > 0xEF && nrc < 0xFE) {
service_name = "vehicleManufacturerSpecificConditionsNotCorrect"; break;
}
else {
service_name = "ISOSAEReserved"; break;
}
}
break;
default: service_name = "Unknown";
}
printf("%s %s", flag, service_name);
}
int main(int argc, char **argv)
{
int s;
@@ -93,6 +206,8 @@ int main(int argc, char **argv)
int rx_extany = 0;
int asc = 0;
int color = 0;
int uds_output = 0;
int is_ff = 0;
int timestamp = 0;
int datidx = 0;
unsigned long fflen = 0;
@@ -103,7 +218,7 @@ int main(int argc, char **argv)
last_tv.tv_sec = 0;
last_tv.tv_usec = 0;
while ((opt = getopt(argc, argv, "s:d:ax:X:ct:?")) != -1) {
while ((opt = getopt(argc, argv, "s:d:ax:X:ct:u?")) != -1) {
switch (opt) {
case 's':
src = strtoul(optarg, (char **)NULL, 16);
@@ -151,6 +266,10 @@ int main(int argc, char **argv)
}
break;
case 'u':
uds_output = 1;
break;
case '?':
print_usage(basename(argv[0]));
exit(0);
@@ -291,6 +410,7 @@ int main(int argc, char **argv)
switch (n_pci & 0xF0) {
case 0x00:
is_ff = 1;
if (n_pci & 0xF) {
printf("[SF] ln: %-4d data:", n_pci & 0xF);
datidx = ext+1;
@@ -301,6 +421,7 @@ int main(int argc, char **argv)
break;
case 0x10:
is_ff = 1;
fflen = ((n_pci & 0x0F)<<8) + frame.data[ext+1];
if (fflen)
datidx = ext+2;
@@ -362,6 +483,15 @@ int main(int argc, char **argv)
}
printf("'");
}
if (uds_output && is_ff) {
int offset = 3;
if (asc)
offset = 1;
printf("%*s", ((7-ext) - (frame.len-datidx))*offset + 3,
" - ");
print_uds_message(frame.data[datidx], frame.data[datidx+2]);
is_ff = 0;
}
}
if (color)
+2
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* isotpperf.c - ISO15765-2 protocol performance visualisation
*
@@ -56,6 +57,7 @@
#include <linux/can.h>
#include <linux/can/raw.h>
#include <linux/sockios.h>
#define NO_CAN_ID 0xFFFFFFFFU
#define PERCENTRES 2 /* resolution in percent for bargraph */
+2 -1
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* isotprecv.c
*
@@ -70,7 +71,7 @@ void print_usage(char *prg)
fprintf(stderr, " -m <val> (STmin in ms/ns. See spec.)\n");
fprintf(stderr, " -f <time ns> (force rx stmin value in nanosecs)\n");
fprintf(stderr, " -w <num> (max. wait frame transmissions.)\n");
fprintf(stderr, " -l (loop: do not exit after pdu receiption.)\n");
fprintf(stderr, " -l (loop: do not exit after pdu reception.)\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 written on STDOUT in space separated ASCII hex values.\n");
+1
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* isotpsend.c
*
+3 -2
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* isotpserver.c
*
@@ -101,10 +102,10 @@ void print_usage(char *prg)
fprintf(stderr, "\nUsage: %s -l <port> -s <can_id> -d <can_id> [options] <CAN interface>\n", prg);
fprintf(stderr, "Options: (* = mandatory)\n");
fprintf(stderr, "\n");
fprintf(stderr, "ip adressing:\n");
fprintf(stderr, "ip addressing:\n");
fprintf(stderr, " * -l <port> (local port for the server)\n");
fprintf(stderr, "\n");
fprintf(stderr, "isotp adressing:\n");
fprintf(stderr, "isotp addressing:\n");
fprintf(stderr, " * -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " * -d <can_id> (destination can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -x <addr>[:<rxaddr>] (extended addressing / opt. separate rxaddr)\n");
+69 -25
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* isotpsniffer.c - dump ISO15765-2 datagrams using PF_CAN isotp protocol
*
@@ -43,6 +44,7 @@
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
@@ -55,6 +57,7 @@
#include <linux/can.h>
#include <linux/can/isotp.h>
#include <linux/sockios.h>
#include "terminal.h"
#define NO_CAN_ID 0xFFFFFFFFU
@@ -73,6 +76,7 @@ void print_usage(char *prg)
fprintf(stderr, " -c (color mode)\n");
fprintf(stderr, " -t <type> (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\n");
fprintf(stderr, " -f <format> (1 = HEX, 2 = ASCII, 3 = HEX & ASCII - default: %d)\n", FORMAT_DEFAULT);
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
fprintf(stderr, " -h <len> (head: print only first <len> bytes)\n");
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
fprintf(stderr, "\n");
@@ -135,7 +139,7 @@ void printbuf(unsigned char *buffer, int nbytes, int color, int timestamp,
}
}
/* the source socket gets pdu data from the detination id */
/* the source socket gets pdu data from the destination id */
printf(" %s %03X [%d] ", candevice, src & CAN_EFF_MASK, nbytes);
if (format & FORMAT_HEX) {
for (i=0; i<nbytes; i++) {
@@ -151,7 +155,7 @@ void printbuf(unsigned char *buffer, int nbytes, int color, int timestamp,
if (format & FORMAT_ASCII) {
printf("'");
for (i=0; i<nbytes; i++) {
if ((buffer[i] > 0x1F) && (buffer[i] < 0x7F))
if (isprint(buffer[i]))
printf("%c", buffer[i]);
else
printf(".");
@@ -173,10 +177,12 @@ void printbuf(unsigned char *buffer, int nbytes, int color, int timestamp,
int main(int argc, char **argv)
{
fd_set rdfs;
int s, t;
int s = -1, t = -1;
struct sockaddr_can addr;
char if_name[IFNAMSIZ];
static struct can_isotp_options opts;
static struct can_isotp_ll_options llopts;
int r = 0;
int opt, quit = 0;
int color = 0;
int head = 0;
@@ -190,7 +196,7 @@ int main(int argc, char **argv)
unsigned char buffer[4096];
int nbytes;
while ((opt = getopt(argc, argv, "s:d:x:X:h:ct:f:?")) != -1) {
while ((opt = getopt(argc, argv, "s:d:x:X:h:ct:f:L:?")) != -1) {
switch (opt) {
case 's':
src = strtoul(optarg, (char **)NULL, 16);
@@ -218,6 +224,17 @@ int main(int argc, char **argv)
format = (atoi(optarg) & (FORMAT_ASCII | FORMAT_HEX));
break;
case 'L':
if (sscanf(optarg, "%hhu:%hhu:%hhu",
&llopts.mtu,
&llopts.tx_dl,
&llopts.tx_flags) != 3) {
printf("unknown link layer options '%s'.\n", optarg);
print_usage(basename(argv[0]));
exit(1);
}
break;
case 'h':
head = atoi(optarg);
break;
@@ -238,35 +255,37 @@ int main(int argc, char **argv)
case '?':
print_usage(basename(argv[0]));
exit(0);
break;
goto out;
default:
fprintf(stderr, "Unknown option %c\n", opt);
print_usage(basename(argv[0]));
exit(1);
break;
goto out;
}
}
if ((argc - optind) != 1 || src == NO_CAN_ID || dst == NO_CAN_ID) {
print_usage(basename(argv[0]));
exit(1);
r = 1;
goto out;
}
if ((opts.flags & CAN_ISOTP_RX_EXT_ADDR) && (!(opts.flags & CAN_ISOTP_EXTEND_ADDR))) {
print_usage(basename(argv[0]));
exit(1);
r = 1;
goto out;
}
if ((s = socket(PF_CAN, SOCK_DGRAM, CAN_ISOTP)) < 0) {
perror("socket");
exit(1);
r = 1;
goto out;
}
if ((t = socket(PF_CAN, SOCK_DGRAM, CAN_ISOTP)) < 0) {
perror("socket");
exit(1);
r = 1;
goto out;
}
opts.flags |= CAN_ISOTP_LISTEN_MODE;
@@ -284,8 +303,8 @@ int main(int argc, char **argv)
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind");
close(s);
exit(1);
r = 1;
goto out;
}
if (opts.flags & CAN_ISOTP_RX_EXT_ADDR) {
@@ -297,15 +316,30 @@ int main(int argc, char **argv)
opts.rx_ext_address = tmpext;
}
setsockopt(t, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts));
if ((setsockopt(t, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts))) < 0) {
perror("setsockopt");
r = 1;
goto out;
}
if ((setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &llopts, sizeof(llopts))) < 0) {
perror("setsockopt");
r = 1;
goto out;
}
if ((setsockopt(t, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &llopts, sizeof(llopts))) < 0) {
perror("setsockopt");
r = 1;
goto out;
}
addr.can_addr.tp.tx_id = dst;
addr.can_addr.tp.rx_id = src;
if (bind(t, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind");
close(s);
exit(1);
r = 1;
goto out;
}
while (!quit) {
@@ -330,10 +364,13 @@ int main(int argc, char **argv)
nbytes = read(s, buffer, 4096);
if (nbytes < 0) {
perror("read socket s");
return -1;
r = 1;
goto out;
}
if (nbytes > 4095) {
r = 1;
goto out;
}
if (nbytes > 4095)
return -1;
printbuf(buffer, nbytes, color?2:0, timestamp, format,
&tv, &last_tv, dst, s, if_name, head);
}
@@ -342,16 +379,23 @@ int main(int argc, char **argv)
nbytes = read(t, buffer, 4096);
if (nbytes < 0) {
perror("read socket t");
return -1;
r = 1;
goto out;
}
if (nbytes > 4095) {
r = 1;
goto out;
}
if (nbytes > 4095)
return -1;
printbuf(buffer, nbytes, color?1:0, timestamp, format,
&tv, &last_tv, src, t, if_name, head);
}
}
close(s);
out:
if (s != -1)
close(s);
if (t != -1)
close(t);
return 0;
return r;
}
+14 -10
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* isotptun.c - IP over CAN ISO-TP (ISO15765-2) tunnel / proof-of-concept
*
@@ -142,7 +143,7 @@ int main(int argc, char **argv)
extern int optind, opterr, optopt;
static int verbose;
unsigned char buffer[BUF_LEN];
static char name[IFNAMSIZ] = DEFAULT_NAME;
static char name[sizeof(ifr.ifr_name)] = DEFAULT_NAME;
int nbytes;
int run_as_daemon = 0;
@@ -163,7 +164,13 @@ int main(int argc, char **argv)
break;
case 'n':
strncpy(name, optarg, IFNAMSIZ-1);
if (strlen(optarg) > sizeof(name) - 1) {
print_usage(basename(argv[0]));
exit(EXIT_FAILURE);
}
/* ensure string termination */
memset(name, 0, sizeof(name));
strncpy(name, optarg, sizeof(name) - 1);
break;
case 'x':
@@ -298,17 +305,14 @@ int main(int argc, char **argv)
}
}
strncpy(ifr.ifr_name, argv[optind], IFNAMSIZ);
ifr.ifr_ifindex = if_nametoindex(ifr.ifr_name);
if (!ifr.ifr_ifindex) {
addr.can_family = AF_CAN;
addr.can_ifindex = if_nametoindex(argv[optind]);
if (!addr.can_ifindex) {
perror_syslog("if_nametoindex");
close(s);
exit(EXIT_FAILURE);
}
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror_syslog("bind");
close(s);
@@ -324,8 +328,8 @@ int main(int argc, char **argv)
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
ifr.ifr_name[IFNAMSIZ - 1] = '\0';
/* string termination is ensured at commandline option handling */
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
if (ioctl(t, TUNSETIFF, (void *) &ifr) < 0) {
perror_syslog("ioctl tunfd");
+56 -52
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2011 EIA Electronics
*
@@ -19,7 +20,7 @@
#include <unistd.h>
#include <getopt.h>
#include <error.h>
#include <err.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <net/if.h>
@@ -154,12 +155,12 @@ static int parse_range(char *str)
for (tok = strtok(str, ",;"); tok; tok = strtok(NULL, ",;")) {
a0 = ae = strtoul(tok, &endp, 0);
if (endp <= tok)
error(1, 0, "parsing range '%s'", tok);
err(1, "parsing range '%s'", tok);
if (*endp == '-') {
tok = endp+1;
ae = strtoul(tok, &endp, 0);
if (endp <= tok)
error(1, 0, "parsing addr '%s'", tok);
err(1, "parsing addr '%s'", tok);
if (ae < a0)
ae = a0;
}
@@ -175,14 +176,14 @@ static int parse_range(char *str)
/* j1939 socket */
static const struct j1939_filter filt[] = {
{
.pgn = 0x0ee00,
.pgn_mask = 0x3ff00,
.pgn = J1939_PGN_ADDRESS_CLAIMED,
.pgn_mask = J1939_PGN_PDU1_MAX,
}, {
.pgn = 0x0ea00,
.pgn_mask = 0x3ff00,
.pgn = J1939_PGN_REQUEST,
.pgn_mask = J1939_PGN_PDU1_MAX,
}, {
.pgn = 0x0fed8,
.pgn_mask = 0x3ffff,
.pgn_mask = J1939_PGN_MAX,
},
};
@@ -195,7 +196,7 @@ static int open_socket(const char *device, uint64_t name)
.can_addr.j1939 = {
.name = name,
.addr = J1939_IDLE_ADDR,
.pgn = 0x0ee00,
.pgn = J1939_NO_PGN,
},
.can_ifindex = if_nametoindex(s.intf),
};
@@ -204,35 +205,28 @@ static int open_socket(const char *device, uint64_t name)
fprintf(stderr, "- socket(PF_CAN, SOCK_DGRAM, CAN_J1939);\n");
sock = ret = socket(PF_CAN, SOCK_DGRAM, CAN_J1939);
if (ret < 0)
error(1, errno, "socket(j1939)");
if (s.verbose)
fprintf(stderr, "- setsockopt(, SOL_SOCKET, SO_BINDTODEVICE, %s, %zd);\n", device, strlen(device));
ret = setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE,
device, strlen(device));
if (ret < 0)
error(1, errno, "bindtodevice %s", device);
err(1, "socket(j1939)");
if (s.verbose)
fprintf(stderr, "- setsockopt(, SOL_CAN_J1939, SO_J1939_FILTER, <filter>, %zd);\n", sizeof(filt));
ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_FILTER,
&filt, sizeof(filt));
if (ret < 0)
error(1, errno, "setsockopt filter");
err(1, "setsockopt filter");
value = 1;
if (s.verbose)
fprintf(stderr, "- setsockopt(, SOL_CAN_J1939, SO_J1939_RECV_OWN, %d, %zd);\n", value, sizeof(value));
ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_RECV_OWN,
fprintf(stderr, "- setsockopt(, SOL_SOCKET, SO_BROADCAST, %d, %zd);\n", value, sizeof(value));
ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
&value, sizeof(value));
if (ret < 0)
error(1, errno, "setsockopt receive own msgs");
err(1, "setsockopt set broadcast");
if (s.verbose)
fprintf(stderr, "- bind(, %s, %zi);\n", libj1939_addr2str(&saddr), sizeof(saddr));
ret = bind(sock, (void *)&saddr, sizeof(saddr));
if (ret < 0)
error(1, errno, "bind()");
err(1, "bind()");
return sock;
}
@@ -241,15 +235,23 @@ static int repeat_address(int sock, uint64_t name)
{
int ret;
uint8_t dat[8];
static const struct sockaddr_can saddr = {
.can_family = AF_CAN,
.can_addr.j1939 = {
.pgn = J1939_PGN_ADDRESS_CLAIMED,
.addr = J1939_NO_ADDR,
},
};
memcpy(dat, &name, 8);
if (!host_is_little_endian())
bswap(dat, 8);
if (s.verbose)
fprintf(stderr, "- send(, %" PRId64 ", 8, 0);\n", name);
ret = send(sock, dat, 8, 0);
ret = sendto(sock, dat, sizeof(dat), 0, (const struct sockaddr *)&saddr,
sizeof(saddr));
if (must_warn(ret))
error(1, errno, "send address claim for 0x%02x", s.last_sa);
err(1, "send address claim for 0x%02x", s.last_sa);
return ret;
}
static int claim_address(int sock, uint64_t name, int sa)
@@ -260,7 +262,7 @@ static int claim_address(int sock, uint64_t name, int sa)
.can_addr.j1939 = {
.name = name,
.addr = sa,
.pgn = 0x0ee00,
.pgn = J1939_NO_PGN,
},
.can_ifindex = if_nametoindex(s.intf),
};
@@ -269,7 +271,7 @@ static int claim_address(int sock, uint64_t name, int sa)
fprintf(stderr, "- bind(, %s, %zi);\n", libj1939_addr2str(&saddr), sizeof(saddr));
ret = bind(sock, (void *)&saddr, sizeof(saddr));
if (ret < 0)
error(1, errno, "rebind with sa 0x%02x", sa);
err(1, "rebind with sa 0x%02x", sa);
s.last_sa = sa;
return repeat_address(sock, name);
}
@@ -280,7 +282,7 @@ static int request_addresses(int sock)
int ret;
static const struct sockaddr_can saddr = {
.can_family = AF_CAN,
.can_addr.j1939.pgn = 0x0ea00,
.can_addr.j1939.pgn = J1939_PGN_REQUEST,
.can_addr.j1939.addr = J1939_NO_ADDR,
};
@@ -288,7 +290,7 @@ static int request_addresses(int sock)
fprintf(stderr, "- sendto(, { 0, 0xee, 0, }, %zi, 0, %s, %zi);\n", sizeof(dat), libj1939_addr2str(&saddr), sizeof(saddr));
ret = sendto(sock, dat, sizeof(dat), 0, (void *)&saddr, sizeof(saddr));
if (must_warn(ret))
error(1, errno, "send request for address claims");
err(1, "send request for address claims");
return ret;
}
@@ -356,7 +358,7 @@ static void install_signal(int sig)
sigfillset(&sigact.sa_mask);
ret = sigaction(sig, &sigact, NULL);
if (ret < 0)
error(1, errno, "sigaction for signal %i", sig);
err(1, "sigaction for signal %i", sig);
}
static void schedule_itimer(int msec)
@@ -372,7 +374,7 @@ static void schedule_itimer(int msec)
ret = setitimer(ITIMER_REAL, &val, NULL);
} while ((ret < 0) && (errno == EINTR));
if (ret < 0)
error(1, errno, "setitimer %i msec", msec);
err(1, "setitimer %i msec", msec);
}
/* dump status */
@@ -413,7 +415,7 @@ static void save_cache(void)
return;
fp = fopen(s.cachefile, "w");
if (!fp)
error(1, errno, "fopen %s, w", s.cachefile);
err(1, "fopen %s, w", s.cachefile);
time(&t);
fprintf(fp, "# saved on %s\n", ctime(&t));
@@ -436,7 +438,7 @@ static void restore_cache(void)
if (!fp) {
if (ENOENT == errno)
return;
error(1, errno, "fopen %s, r", s.cachefile);
err(1, "fopen %s, r", s.cachefile);
}
while (!feof(fp)) {
ret = getline(&line, &sz, fp);
@@ -458,7 +460,7 @@ static void restore_cache(void)
/* main */
int main(int argc, char *argv[])
{
int ret, sock, pgn, sa, opt;
int ret, sock, sock_rx, pgn, sa, opt;
socklen_t slen;
uint8_t dat[9];
struct sockaddr_can saddr;
@@ -484,9 +486,10 @@ int main(int argc, char *argv[])
break;
case 'p':
#ifdef _GNU_SOURCE
asprintf(&program_invocation_name, "%s.%s", program_invocation_short_name, optarg);
if (asprintf(&program_invocation_name, "%s.%s", program_invocation_short_name, optarg) < 0)
err(1, "asprintf(program invocation name)");
#else
error(0, 0, "compile with -D_GNU_SOURCE to use -p");
err(0, "compile with -D_GNU_SOURCE to use -p");
#endif
break;
default:
@@ -505,19 +508,20 @@ int main(int argc, char *argv[])
ret = parse_range(s.ranges);
if (!ret)
error(1, 0, "no addresses in range");
err(1, "no addresses in range");
if ((s.current_sa < J1939_IDLE_ADDR) && !(addr[s.current_sa].flags & F_USE)) {
if (s.verbose)
error(0, 0, "forget saved address 0x%02x", s.current_sa);
err(0, "forget saved address 0x%02x", s.current_sa);
s.current_sa = J1939_IDLE_ADDR;
}
if (s.verbose)
error(0, 0, "ready for %s:%016llx", s.intf, (long long)s.name);
err(0, "ready for %s:%016llx", s.intf, (long long)s.name);
if (!s.intf || !s.name)
error(1, 0, "bad arguments");
err(1, "bad arguments");
ret = sock = open_socket(s.intf, s.name);
sock_rx = open_socket(s.intf, s.name);
install_signal(SIGTERM);
install_signal(SIGINT);
@@ -534,7 +538,7 @@ int main(int argc, char *argv[])
case STATE_INITIAL:
ret = request_addresses(sock);
if (ret < 0)
error(1, errno, "could not sent initial request");
err(1, "could not sent initial request");
s.state = STATE_REQ_SENT;
break;
case STATE_REQ_PENDING:
@@ -544,7 +548,7 @@ int main(int argc, char *argv[])
/* claim addr */
sa = choose_new_sa(s.name, s.current_sa);
if (sa == J1939_IDLE_ADDR)
error(1, 0, "no free address to use");
err(1, "no free address to use");
ret = claim_address(sock, s.name, sa);
if (ret < 0)
schedule_itimer(50);
@@ -561,23 +565,23 @@ int main(int argc, char *argv[])
}
slen = sizeof(saddr);
ret = recvfrom(sock, dat, sizeof(dat), 0, (void *)&saddr, &slen);
ret = recvfrom(sock_rx, dat, sizeof(dat), 0, (void *)&saddr, &slen);
if (ret < 0) {
if (EINTR == errno)
continue;
error(1, errno, "recvfrom()");
err(1, "recvfrom()");
}
switch (saddr.can_addr.j1939.pgn) {
case 0x0ea00:
case J1939_PGN_REQUEST:
if (ret < 3)
break;
pgn = dat[0] + (dat[1] << 8) + ((dat[2] & 0x03) << 16);
if (pgn != 0x0ee00)
if (pgn != J1939_PGN_ADDRESS_CLAIMED)
/* not interested */
break;
if (s.state == STATE_REQ_SENT) {
if (s.verbose)
error(0, 0, "request sent, pending for 1250 ms");
err(0, "request sent, pending for 1250 ms");
schedule_itimer(1250);
s.state = STATE_REQ_PENDING;
} else if (s.state == STATE_OPERATIONAL) {
@@ -586,7 +590,7 @@ int main(int argc, char *argv[])
schedule_itimer(50);
}
break;
case 0x0ee00:
case J1939_PGN_ADDRESS_CLAIMED:
if (saddr.can_addr.j1939.addr >= J1939_IDLE_ADDR) {
sa = lookup_name(saddr.can_addr.j1939.name);
if (sa < J1939_IDLE_ADDR)
@@ -604,17 +608,17 @@ int main(int argc, char *argv[])
addr[sa].flags |= F_SEEN;
if (s.name == saddr.can_addr.j1939.name) {
/* ourselve, disable itimer */
/* ourselves, disable itimer */
s.current_sa = sa;
if (s.verbose)
error(0, 0, "claimed 0x%02x", sa);
err(0, "claimed 0x%02x", sa);
} else if (sa == s.current_sa) {
if (s.verbose)
error(0, 0, "address collision for 0x%02x", sa);
err(0, "address collision for 0x%02x", sa);
if (s.name > saddr.can_addr.j1939.name) {
sa = choose_new_sa(s.name, sa);
if (sa == J1939_IDLE_ADDR) {
error(0, 0, "no address left");
err(0, "no address left");
/* put J1939_IDLE_ADDR in cache file */
s.current_sa = sa;
goto done;
@@ -639,7 +643,7 @@ int main(int argc, char *argv[])
}
done:
if (s.verbose)
error(0, 0, "shutdown");
err(0, "shutdown");
claim_address(sock, s.name, J1939_IDLE_ADDR);
save_cache();
return 0;
+681
View File
@@ -0,0 +1,681 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2018 Pengutronix, Oleksij Rempel <o.rempel@pengutronix.de>
*/
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <net/if.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <poll.h>
#include <linux/errqueue.h>
#include <linux/netlink.h>
#include <linux/net_tstamp.h>
#include <linux/socket.h>
#include "libj1939.h"
#define J1939_MAX_ETP_PACKET_SIZE (7 * 0x00ffffff)
#define JCAT_BUF_SIZE (1000 * 1024)
/*
* min()/max()/clamp() macros that also do
* strict type-checking.. See the
* "unnecessary" pointer comparison.
*/
#define min(x, y) ({ \
typeof(x) _min1 = (x); \
typeof(y) _min2 = (y); \
(void) (&_min1 == &_min2); \
_min1 < _min2 ? _min1 : _min2; })
struct jcat_stats {
int err;
uint32_t tskey;
uint32_t send;
};
struct jcat_priv {
int sock;
int infile;
int outfile;
size_t max_transfer;
unsigned long repeat;
unsigned long round;
int todo_prio;
bool valid_peername;
bool todo_recv;
bool todo_filesize;
bool todo_connect;
unsigned long polltimeout;
struct sockaddr_can sockname;
struct sockaddr_can peername;
struct sock_extended_err *serr;
struct scm_timestamping *tss;
struct jcat_stats stats;
};
static const char help_msg[] =
"jcat: netcat tool for j1939\n"
"Usage: jcat FROM TO\n"
" FROM / TO - or [IFACE][:[SA][,[PGN][,NAME]]]\n"
"Options:\n"
" -i <infile> (default stdin)\n"
" -s <size> Set maximal transfer size. Default: 117440505 byte\n"
" -r Receive data\n"
" -P <timeout> poll timeout in milliseconds before sending data.\n"
" With this option send() will be used with MSG_DONTWAIT flag.\n"
" -R <count> Set send repeat count. Default: 1\n"
"\n"
"Example:\n"
"jcat -i some_file_to_send can0:0x80 :0x90,0x12300\n"
"jcat can0:0x90 -r > /tmp/some_file_to_receive\n"
"\n"
;
static const char optstring[] = "?i:vs:rp:P:R:";
static void jcat_init_sockaddr_can(struct sockaddr_can *sac)
{
sac->can_family = AF_CAN;
sac->can_addr.j1939.addr = J1939_NO_ADDR;
sac->can_addr.j1939.name = J1939_NO_NAME;
sac->can_addr.j1939.pgn = J1939_NO_PGN;
}
static ssize_t jcat_send_one(struct jcat_priv *priv, int out_fd,
const void *buf, size_t buf_size)
{
ssize_t num_sent;
int flags = 0;
if (priv->polltimeout)
flags |= MSG_DONTWAIT;
if (priv->valid_peername && !priv->todo_connect)
num_sent = sendto(out_fd, buf, buf_size, flags,
(struct sockaddr *)&priv->peername,
sizeof(priv->peername));
else
num_sent = send(out_fd, buf, buf_size, flags);
if (num_sent == -1) {
warn("%s: transfer error: %i", __func__, -errno);
return -errno;
}
if (num_sent == 0) /* Should never happen */ {
warn("%s: transferred 0 bytes", __func__);
return -EINVAL;
}
if (num_sent > buf_size) /* Should never happen */ {
warn("%s: send more then read", __func__);
return -EINVAL;
}
return num_sent;
}
static void jcat_print_timestamp(struct jcat_priv *priv, const char *name,
struct timespec *cur)
{
struct jcat_stats *stats = &priv->stats;
if (!(cur->tv_sec | cur->tv_nsec))
return;
fprintf(stderr, " %s: %lu s %lu us (seq=%u, send=%u)",
name, cur->tv_sec, cur->tv_nsec / 1000,
stats->tskey, stats->send);
fprintf(stderr, "\n");
}
static const char *jcat_tstype_to_str(int tstype)
{
switch (tstype) {
case SCM_TSTAMP_SCHED:
return " ENQ";
case SCM_TSTAMP_SND:
return " SND";
case SCM_TSTAMP_ACK:
return " ACK";
default:
return " unk";
}
}
/* Check the stats of SCM_TIMESTAMPING_OPT_STATS */
static void jcat_scm_opt_stats(struct jcat_priv *priv, void *buf, int len)
{
struct jcat_stats *stats = &priv->stats;
int offset = 0;
while (offset < len) {
struct nlattr *nla = (struct nlattr *) (buf + offset);
switch (nla->nla_type) {
case J1939_NLA_BYTES_ACKED:
stats->send = *(uint32_t *)((void *)nla + NLA_HDRLEN);
break;
default:
warnx("not supported J1939_NLA field\n");
}
offset += NLA_ALIGN(nla->nla_len);
}
}
static int jcat_extract_serr(struct jcat_priv *priv)
{
struct jcat_stats *stats = &priv->stats;
struct sock_extended_err *serr = priv->serr;
struct scm_timestamping *tss = priv->tss;
switch (serr->ee_origin) {
case SO_EE_ORIGIN_TIMESTAMPING:
/*
* We expect here following patterns:
* serr->ee_info == SCM_TSTAMP_ACK
* Activated with SOF_TIMESTAMPING_TX_ACK
* or
* serr->ee_info == SCM_TSTAMP_SCHED
* Activated with SOF_TIMESTAMPING_SCHED
* and
* serr->ee_data == tskey
* session message counter which is activate
* with SOF_TIMESTAMPING_OPT_ID
* the serr->ee_errno should be ENOMSG
*/
if (serr->ee_errno != ENOMSG)
warnx("serr: expected ENOMSG, got: %i",
serr->ee_errno);
stats->tskey = serr->ee_data;
jcat_print_timestamp(priv, jcat_tstype_to_str(serr->ee_info),
&tss->ts[0]);
if (serr->ee_info == SCM_TSTAMP_SCHED)
return -EINTR;
else
return 0;
case SO_EE_ORIGIN_LOCAL:
/*
* The serr->ee_origin == SO_EE_ORIGIN_LOCAL is
* currently used to notify about locally
* detected protocol/stack errors.
* Following patterns are expected:
* serr->ee_info == J1939_EE_INFO_TX_ABORT
* is used to notify about session TX
* abort.
* serr->ee_data == tskey
* session message counter which is activate
* with SOF_TIMESTAMPING_OPT_ID
* serr->ee_errno == actual error reason
* error reason is converted from J1939
* abort to linux error name space.
*/
if (serr->ee_info != J1939_EE_INFO_TX_ABORT)
warnx("serr: unknown ee_info: %i",
serr->ee_info);
jcat_print_timestamp(priv, " ABT", &tss->ts[0]);
warnx("serr: tx error: %i, %s", serr->ee_errno, strerror(serr->ee_errno));
return serr->ee_errno;
default:
warnx("serr: wrong origin: %u", serr->ee_origin);
}
return 0;
}
static int jcat_parse_cm(struct jcat_priv *priv, struct cmsghdr *cm)
{
const size_t hdr_len = CMSG_ALIGN(sizeof(struct cmsghdr));
if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_TIMESTAMPING) {
priv->tss = (void *)CMSG_DATA(cm);
} else if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_TIMESTAMPING_OPT_STATS) {
void *jstats = (void *)CMSG_DATA(cm);
/* Activated with SOF_TIMESTAMPING_OPT_STATS */
jcat_scm_opt_stats(priv, jstats, cm->cmsg_len - hdr_len);
} else if (cm->cmsg_level == SOL_CAN_J1939 &&
cm->cmsg_type == SCM_J1939_ERRQUEUE) {
priv->serr = (void *)CMSG_DATA(cm);
} else
warnx("serr: not supported type: %d.%d",
cm->cmsg_level, cm->cmsg_type);
return 0;
}
static int jcat_recv_err(struct jcat_priv *priv)
{
char control[100];
struct cmsghdr *cm;
int ret;
struct msghdr msg = {
.msg_control = control,
.msg_controllen = sizeof(control),
};
ret = recvmsg(priv->sock, &msg, MSG_ERRQUEUE);
if (ret == -1)
err(EXIT_FAILURE, "recvmsg error notification: %i", errno);
if (msg.msg_flags & MSG_CTRUNC)
err(EXIT_FAILURE, "recvmsg error notification: truncated");
priv->serr = NULL;
priv->tss = NULL;
for (cm = CMSG_FIRSTHDR(&msg); cm && cm->cmsg_len;
cm = CMSG_NXTHDR(&msg, cm)) {
jcat_parse_cm(priv, cm);
if (priv->serr && priv->tss)
return jcat_extract_serr(priv);
}
return 0;
}
static int jcat_send_loop(struct jcat_priv *priv, int out_fd, char *buf,
size_t buf_size)
{
struct jcat_stats *stats = &priv->stats;
ssize_t count;
char *tmp_buf = buf;
unsigned int events = POLLOUT | POLLERR;
bool tx_done = false;
count = buf_size;
while (!tx_done) {
ssize_t num_sent = 0;
if (priv->polltimeout) {
struct pollfd fds = {
.fd = priv->sock,
.events = events,
};
int ret;
ret = poll(&fds, 1, priv->polltimeout);
if (ret == -EINTR)
continue;
else if (ret < 0)
return -errno;
else if (!ret)
return -ETIME;
if (!(fds.revents & events)) {
warn("%s: something else is wrong", __func__);
return -EIO;
}
if (fds.revents & POLLERR) {
ret = jcat_recv_err(priv);
if (ret == -EINTR)
continue;
else if (ret)
return ret;
else if ((priv->repeat - 1) == stats->tskey)
tx_done = true;
}
if (fds.revents & POLLOUT) {
num_sent = jcat_send_one(priv, out_fd, tmp_buf, count);
if (num_sent < 0)
return num_sent;
}
} else {
num_sent = jcat_send_one(priv, out_fd, tmp_buf, count);
if (num_sent < 0)
return num_sent;
}
count -= num_sent;
tmp_buf += num_sent;
if (buf + buf_size < tmp_buf + count) {
warn("%s: send buffer is bigger than the read buffer",
__func__);
return -EINVAL;
}
if (!count) {
if (priv->repeat == priv->round)
events = POLLERR;
else
tx_done = true;
}
}
return 0;
}
static int jcat_sendfile(struct jcat_priv *priv, int out_fd, int in_fd,
off_t *offset, size_t count)
{
int ret = EXIT_SUCCESS;
off_t orig = 0;
char *buf;
size_t to_read, num_read, buf_size;
buf_size = min(priv->max_transfer, count);
buf = malloc(buf_size);
if (!buf) {
warn("can't allocate buf");
ret = EXIT_FAILURE;
goto do_nofree;
}
if (offset) {
/* Save current file offset and set offset to value in '*offset' */
orig = lseek(in_fd, 0, SEEK_CUR);
if (orig == -1) {
ret = EXIT_FAILURE;
goto do_free;
}
if (lseek(in_fd, *offset, SEEK_SET) == -1) {
ret = EXIT_FAILURE;
goto do_free;
}
}
while (count > 0) {
to_read = min(buf_size, count);
num_read = read(in_fd, buf, to_read);
if (num_read == -1) {
ret = EXIT_FAILURE;
goto do_free;
}
if (num_read == 0)
break; /* EOF */
ret = jcat_send_loop(priv, out_fd, buf, num_read);
if (ret)
goto do_free;
count -= num_read;
}
if (offset) {
/* Return updated file offset in '*offset', and reset the file offset
to the value it had when we were called. */
*offset = lseek(in_fd, 0, SEEK_CUR);
if (*offset == -1) {
ret = EXIT_FAILURE;
goto do_free;
}
if (lseek(in_fd, orig, SEEK_SET) == -1) {
ret = EXIT_FAILURE;
goto do_free;
}
}
do_free:
free(buf);
do_nofree:
return ret;
}
static size_t jcat_get_file_size(int fd)
{
off_t offset;
offset = lseek(fd, 0, SEEK_END);
if (offset == -1)
err(1, "%s lseek()\n", __func__);
if (lseek(fd, 0, SEEK_SET) == -1)
err(1, "%s lseek() start\n", __func__);
return offset;
}
static int jcat_send(struct jcat_priv *priv)
{
unsigned int size = 0;
int ret, i;
if (priv->todo_filesize)
size = jcat_get_file_size(priv->infile);
if (!size)
return EXIT_FAILURE;
for (i = 0; i < priv->repeat; i++) {
priv->round++;
ret = jcat_sendfile(priv, priv->sock, priv->infile, NULL, size);
if (ret)
break;
if (lseek(priv->infile, 0, SEEK_SET) == -1)
err(1, "%s lseek() start\n", __func__);
}
return ret;
}
static int jcat_recv_one(struct jcat_priv *priv, uint8_t *buf, size_t buf_size)
{
int ret;
ret = recv(priv->sock, buf, buf_size, 0);
if (ret < 0) {
warn("recvf()");
return EXIT_FAILURE;
}
ret = write(priv->outfile, buf, ret);
if (ret < 0) {
warn("write stdout()");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
static int jcat_recv(struct jcat_priv *priv)
{
int ret = EXIT_SUCCESS;
size_t buf_size;
uint8_t *buf;
buf_size = priv->max_transfer;
buf = malloc(buf_size);
if (!buf) {
warn("can't allocate rx buf");
return EXIT_FAILURE;;
}
while (priv->todo_recv) {
ret = jcat_recv_one(priv, buf, buf_size);
if (ret)
break;
}
free(buf);
return ret;
}
static int jcat_sock_prepare(struct jcat_priv *priv)
{
unsigned int sock_opt;
int value;
int ret;
/* open socket */
priv->sock = socket(PF_CAN, SOCK_DGRAM, CAN_J1939);
if (priv->sock < 0) {
warn("socket(j1939)");
return EXIT_FAILURE;
}
if (priv->todo_prio >= 0) {
ret = setsockopt(priv->sock, SOL_CAN_J1939, SO_J1939_SEND_PRIO,
&priv->todo_prio, sizeof(priv->todo_prio));
if (ret < 0) {
warn("set priority %i", priv->todo_prio);
return EXIT_FAILURE;
}
}
value = 1;
ret = setsockopt(priv->sock, SOL_CAN_J1939, SO_J1939_ERRQUEUE, &value,
sizeof(value));
if (ret < 0) {
warn("set recverr");
return EXIT_FAILURE;
}
sock_opt = SOF_TIMESTAMPING_SOFTWARE |
SOF_TIMESTAMPING_OPT_CMSG |
SOF_TIMESTAMPING_TX_ACK |
SOF_TIMESTAMPING_TX_SCHED |
SOF_TIMESTAMPING_OPT_STATS | SOF_TIMESTAMPING_OPT_TSONLY |
SOF_TIMESTAMPING_OPT_ID;
if (setsockopt(priv->sock, SOL_SOCKET, SO_TIMESTAMPING,
(char *) &sock_opt, sizeof(sock_opt)))
err(1, "setsockopt timestamping");
ret = bind(priv->sock, (void *)&priv->sockname, sizeof(priv->sockname));
if (ret < 0) {
warn("bind()");
return EXIT_FAILURE;
}
if (!priv->todo_connect)
return EXIT_SUCCESS;
if (!priv->valid_peername) {
warn("no peername supplied");
return EXIT_FAILURE;
}
ret = connect(priv->sock, (void *)&priv->peername,
sizeof(priv->peername));
if (ret < 0) {
warn("connect()");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
static int jcat_parse_args(struct jcat_priv *priv, int argc, char *argv[])
{
int opt;
/* argument parsing */
while ((opt = getopt(argc, argv, optstring)) != -1)
switch (opt) {
case 'i':
priv->infile = open(optarg, O_RDONLY);
if (priv->infile == -1)
err(EXIT_FAILURE, "can't open input file");
priv->todo_filesize = 1;
break;
case 's':
priv->max_transfer = strtoul(optarg, NULL, 0);
if (priv->max_transfer > J1939_MAX_ETP_PACKET_SIZE)
err(EXIT_FAILURE, "used value (%zu) is bigger then allowed maximal size: %u.\n",
priv->max_transfer, J1939_MAX_ETP_PACKET_SIZE);
break;
case 'r':
priv->todo_recv = 1;
break;
case 'p':
priv->todo_prio = strtoul(optarg, NULL, 0);
break;
case 'P':
priv->polltimeout = strtoul(optarg, NULL, 0);
break;
case 'c':
priv->todo_connect = 1;
break;
case 'R':
priv->repeat = strtoul(optarg, NULL, 0);
if (priv->repeat < 1)
err(EXIT_FAILURE, "send/repeat count can't be less then 1\n");
break;
default:
fputs(help_msg, stderr);
return EXIT_FAILURE;
}
if (argv[optind]) {
if (strcmp("-", argv[optind]))
libj1939_parse_canaddr(argv[optind], &priv->sockname);
optind++;
}
if (argv[optind]) {
if (strcmp("-", argv[optind])) {
libj1939_parse_canaddr(argv[optind], &priv->peername);
priv->valid_peername = 1;
}
optind++;
}
return EXIT_SUCCESS;
}
int main(int argc, char *argv[])
{
struct jcat_priv *priv;
int ret;
priv = malloc(sizeof(*priv));
if (!priv)
err(EXIT_FAILURE, "can't allocate priv");
bzero(priv, sizeof(*priv));
priv->todo_prio = -1;
priv->infile = STDIN_FILENO;
priv->outfile = STDOUT_FILENO;
priv->max_transfer = J1939_MAX_ETP_PACKET_SIZE;
priv->polltimeout = 100000;
priv->repeat = 1;
jcat_init_sockaddr_can(&priv->sockname);
jcat_init_sockaddr_can(&priv->peername);
ret = jcat_parse_args(priv, argc, argv);
if (ret)
return ret;
ret = jcat_sock_prepare(priv);
if (ret)
return ret;
if (priv->todo_recv)
ret = jcat_recv(priv);
else
ret = jcat_send(priv);
close(priv->infile);
close(priv->outfile);
close(priv->sock);
return ret;
}
+16 -18
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2011 EIA Electronics
*
@@ -18,7 +19,7 @@
#include <unistd.h>
#include <getopt.h>
#include <error.h>
#include <err.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/time.h>
@@ -74,7 +75,7 @@ static struct {
};
/*
* usefull buffers
* useful buffers
*/
static const int ival_1 = 1;
@@ -104,9 +105,6 @@ int main(int argc, char **argv)
uint64_t dst_name;
long recvflags;
#ifdef _GNU_SOURCE
program_invocation_name = program_invocation_short_name;
#endif
/* argument parsing */
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1)
switch (opt) {
@@ -122,7 +120,7 @@ int main(int argc, char **argv)
case 't':
if (optarg) {
if (!strchr("adzA", optarg[0]))
error(1, 0, "unknown time option '%c'", optarg[0]);
err(1, "unknown time option '%c'", optarg[0]);
s.time = optarg[0];
} else {
s.time = 'z';
@@ -137,19 +135,19 @@ int main(int argc, char **argv)
optarg = argv[optind];
ret = libj1939_str2addr(optarg, 0, &s.addr);
if (ret < 0) {
error(0, 0, "bad URI %s", optarg);
err(0, "bad URI %s", optarg);
return 1;
}
}
buf = malloc(s.pkt_len);
if (!buf)
error(1, errno, "malloc %u", s.pkt_len);
err(1, "malloc %u", s.pkt_len);
/* setup socket */
sock = socket(PF_CAN, SOCK_DGRAM, CAN_J1939);
if (sock < 0)
error(1, errno, "socket(can, dgram, j1939)");
err(1, "socket(can, dgram, j1939)");
memset(&filt, 0, sizeof(filt));
if (s.addr.can_addr.j1939.name) {
@@ -162,7 +160,7 @@ int main(int argc, char **argv)
filt.addr_mask = ~0;
++filter;
}
if (s.addr.can_addr.j1939.pgn <= 0x3ffff) {
if (s.addr.can_addr.j1939.pgn <= J1939_PGN_MAX) {
filt.pgn = s.addr.can_addr.j1939.pgn;
filt.pgn_mask = ~0;
++filter;
@@ -170,23 +168,23 @@ int main(int argc, char **argv)
if (filter) {
ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_FILTER, &filt, sizeof(filt));
if (ret < 0)
error(1, errno, "setsockopt filter");
err(1, "setsockopt filter");
}
if (s.promisc) {
ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_PROMISC, &ival_1, sizeof(ival_1));
if (ret < 0)
error(1, errno, "setsockopt promisc");
err(1, "setsockopt promisc");
}
if (s.time) {
ret = setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &ival_1, sizeof(ival_1));
if (ret < 0)
error(1, errno, "setsockopt timestamp");
err(1, "setsockopt timestamp");
}
ret = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &s.pkt_len, sizeof(s.pkt_len));
if (ret < 0)
error(1, errno, "setsockopt rcvbuf %u", s.pkt_len);
err(1, "setsockopt rcvbuf %u", s.pkt_len);
/* bind(): to default, only ifindex is used. */
memset(&src, 0, sizeof(src));
@@ -197,7 +195,7 @@ int main(int argc, char **argv)
src.can_addr.j1939.pgn = J1939_NO_PGN;
ret = bind(sock, (void *)&src, sizeof(src));
if (ret < 0)
error(1, errno, "bind(%s)", argv[1]);
err(1, "bind(%s)", argv[1]);
/* these settings are static and can be held out of the hot path */
iov.iov_base = &buf[0];
@@ -208,7 +206,7 @@ int main(int argc, char **argv)
memset(&tref, 0, sizeof(tref));
if (s.verbose)
error(0, 0, "listening");
err(0, "listening");
while (1) {
/* these settings may be modified by recvmsg() */
iov.iov_len = s.pkt_len;
@@ -221,12 +219,12 @@ int main(int argc, char **argv)
if (ret < 0) {
switch (errno) {
case ENETDOWN:
error(0, errno, "ifindex %i", s.addr.can_ifindex);
err(0, "ifindex %i", s.addr.can_ifindex);
continue;
case EINTR:
continue;
default:
error(1, errno, "recvmsg(ifindex %i)", s.addr.can_ifindex);
err(1, "recvmsg(ifindex %i)", s.addr.can_ifindex);
break;
}
}
+18 -17
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2011 EIA Electronics
*
@@ -17,7 +18,7 @@
#include <unistd.h>
#include <getopt.h>
#include <error.h>
#include <err.h>
#include <poll.h>
#include <sys/types.h>
#include <sys/socket.h>
@@ -105,7 +106,7 @@ int main(int argc, char **argv)
case 's':
s.pkt_len = strtoul(optarg, 0, 0);
if (!s.pkt_len)
error(1, EINVAL, "packet size of %s", optarg);
err(1, "packet size of %s", optarg);
break;
case 'p':
s.priority = strtoul(optarg, 0, 0);
@@ -124,14 +125,14 @@ int main(int argc, char **argv)
optarg = argv[optind++];
ret = libj1939_str2addr(optarg, 0, &s.src);
if (ret < 0)
error(1, 0, "bad address spec [%s]", optarg);
err(1, "bad address spec [%s]", optarg);
s.defined |= DEF_SRC;
}
if (argv[optind]) {
optarg = argv[optind++];
ret = libj1939_str2addr(optarg, 0, &s.dst);
if (ret < 0)
error(1, 0, "bad address spec [%s]", optarg);
err(1, "bad address spec [%s]", optarg);
s.defined |= DEF_DST;
}
@@ -139,36 +140,36 @@ int main(int argc, char **argv)
struct stat st;
if (fstat(STDIN_FILENO, &st) < 0)
error(1, errno, "stat stdin, could not determine buffer size");
err(1, "stat stdin, could not determine buffer size");
s.pkt_len = st.st_size ?: 1024;
}
/* prepare */
buf = malloc(s.pkt_len);
if (!buf)
error(1, errno, "malloc %u", s.pkt_len);
err(1, "malloc %u", s.pkt_len);
sock = socket(PF_CAN, SOCK_DGRAM, CAN_J1939);
if (sock < 0)
error(1, errno, "socket(can, dgram, j1939)");
err(1, "socket(can, dgram, j1939)");
if (s.defined & DEF_PRIO) {
ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_SEND_PRIO, &s.priority, sizeof(s.priority));
if (ret < 0)
error(1, errno, "setsockopt priority");
err(1, "setsockopt priority");
}
if (s.defined & DEF_SRC) {
s.src.can_family = AF_CAN;
ret = bind(sock, (void *)&s.src, sizeof(s.src));
if (ret < 0)
error(1, errno, "bind(%s), %i", libj1939_addr2str(&s.src), -errno);
err(1, "bind(%s), %i", libj1939_addr2str(&s.src), -errno);
}
if (s.defined & DEF_DST) {
s.dst.can_family = AF_CAN;
ret = connect(sock, (void *)&s.dst, sizeof(s.dst));
if (ret < 0)
error(1, errno, "connect(%s), %i", libj1939_addr2str(&s.dst), -errno);
err(1, "connect(%s), %i", libj1939_addr2str(&s.dst), -errno);
}
pfd[0].fd = STDIN_FILENO;
@@ -182,27 +183,26 @@ int main(int argc, char **argv)
if (ret < 0) {
if (errno == EINTR)
continue;
error(1, errno, "poll()");
err(1, "poll()");
}
if (pfd[0].revents) {
ret = read(pfd[0].fd, buf, s.pkt_len);
if (ret < 0)
error(1, errno, "read(stdin)");
err(1, "read(stdin)");
if (!ret)
break;
len = ret;
do {
ret = send(pfd[1].fd, buf, len, s.sendflags);
if (ret < 0)
error(errno != ENOBUFS, errno, "write(%s)",
libj1939_addr2str(&s.src));
if (ret < 0 && errno != ENOBUFS)
err(1, "write(%s)", libj1939_addr2str(&s.src));
} while (ret < 0);
}
if (pfd[1].revents) {
ret = read(pfd[1].fd, buf, s.pkt_len);
if (ret < 0) {
ret = errno;
error(0, errno, "read(%s)", libj1939_addr2str(&s.dst));
err(0, "read(%s)", libj1939_addr2str(&s.dst));
switch (ret) {
case EHOSTDOWN:
break;
@@ -210,7 +210,8 @@ int main(int argc, char **argv)
exit(1);
}
} else {
write(STDOUT_FILENO, buf, ret);
if (write(STDOUT_FILENO, buf, ret) < 0)
err(1, "write(stdout)");
}
}
}
+1
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* lib.c - library for command line tools
*
+2 -1
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* lib.h - library include for command line tools
*
@@ -96,7 +97,7 @@ int hexstring2data(char *arg, unsigned char *data, int maxdlen);
int parse_canframe(char *cs, struct canfd_frame *cf);
/*
* Transfers a valid ASCII string decribing a CAN frame into struct canfd_frame.
* Transfers a valid ASCII string describing a CAN frame into struct canfd_frame.
*
* CAN 2.0 frames
* - string layout <can_id>#{R{len}|data}
+26 -5
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2011 EIA Electronics
*
@@ -12,10 +13,9 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <err.h>
#include <inttypes.h>
#include <error.h>
#include <unistd.h>
#include <fcntl.h>
#include <net/if.h>
@@ -41,7 +41,7 @@ static inline void fetch_names(void)
if (!saved) {
saved = if_nameindex();
if (!saved)
error(1, errno, "if_nameindex()");
err(1, "if_nameindex()");
}
}
@@ -92,6 +92,27 @@ static int libj1939_ifindex(const char *str)
return 0;
}
void libj1939_parse_canaddr(char *spec, struct sockaddr_can *paddr)
{
char *str;
str = strsep(&spec, ":");
if (strlen(str))
paddr->can_ifindex = if_nametoindex(str);
str = strsep(&spec, ",");
if (str && strlen(str))
paddr->can_addr.j1939.addr = strtoul(str, NULL, 0);
str = strsep(&spec, ",");
if (str && strlen(str))
paddr->can_addr.j1939.pgn = strtoul(str, NULL, 0);
str = strsep(&spec, ",");
if (str && strlen(str))
paddr->can_addr.j1939.name = strtoull(str, NULL, 0);
}
int libj1939_str2addr(const char *str, char **endp, struct sockaddr_can *can)
{
char *p;
@@ -162,13 +183,13 @@ const char *libj1939_addr2str(const struct sockaddr_can *can)
}
if (can->can_addr.j1939.name) {
str += sprintf(str, "%016llx", (unsigned long long)can->can_addr.j1939.name);
if (can->can_addr.j1939.pgn == 0x0ee00)
if (can->can_addr.j1939.pgn == J1939_PGN_ADDRESS_CLAIMED)
str += sprintf(str, ".%02x", can->can_addr.j1939.addr);
} else if (can->can_addr.j1939.addr <= 0xfe)
str += sprintf(str, "%02x", can->can_addr.j1939.addr);
else
str += sprintf(str, "-");
if (can->can_addr.j1939.pgn <= 0x3ffff)
if (can->can_addr.j1939.pgn <= J1939_PGN_MAX)
str += sprintf(str, ",%05x", can->can_addr.j1939.pgn);
return buf;
+13
View File
@@ -1,3 +1,15 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2011 EIA Electronics
*
* Authors:
* Kurt Van Dijck <kurt.van.dijck@eia.be>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the version 2 of the GNU General Public License
* as published by the Free Software Foundation
*/
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/j1939.h>
@@ -9,6 +21,7 @@
extern "C" {
#endif
void libj1939_parse_canaddr(char *spec, struct sockaddr_can *paddr);
extern int libj1939_str2addr(const char *str, char **endp, struct sockaddr_can *can);
extern const char *libj1939_addr2str(const struct sockaddr_can *can);
+1
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* log2asc.c - convert compact CAN frame logfile to ASC logfile
*
+1
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* log2long.c - convert compact CAN frame representation into user readable
*
+33 -13
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* slcan_attach.c - userspace tool for serial line CAN interface driver SLCAN
*
@@ -87,7 +88,8 @@ int main(int argc, char **argv)
int send_read_status_flags = 0;
char *speed = NULL;
char *btr = NULL;
char buf[IFNAMSIZ+1];
char buf[20];
static struct ifreq ifr;
char *tty;
char *name = NULL;
int opt;
@@ -132,7 +134,7 @@ int main(int argc, char **argv)
case 'n':
name = optarg;
if (strlen(name) > IFNAMSIZ-1)
if (strlen(name) > sizeof(ifr.ifr_newname) - 1)
print_usage(argv[0]);
break;
@@ -157,25 +159,40 @@ int main(int argc, char **argv)
if (speed) {
sprintf(buf, "C\rS%s\r", speed);
write(fd, buf, strlen(buf));
if (write(fd, buf, strlen(buf)) <= 0) {
perror("write");
exit(EXIT_FAILURE);
}
}
if (btr) {
sprintf(buf, "C\rs%s\r", btr);
write(fd, buf, strlen(buf));
if (write(fd, buf, strlen(buf)) <= 0) {
perror("write");
exit(EXIT_FAILURE);
}
}
if (send_read_status_flags) {
sprintf(buf, "F\r");
write(fd, buf, strlen(buf));
if (write(fd, buf, strlen(buf)) <= 0) {
perror("write");
exit(EXIT_FAILURE);
}
}
if (send_listen) {
sprintf(buf, "L\r");
write(fd, buf, strlen(buf));
if (write(fd, buf, strlen(buf)) <= 0) {
perror("write");
exit(EXIT_FAILURE);
}
} else if (send_open) {
sprintf(buf, "O\r");
write(fd, buf, strlen(buf));
if (write(fd, buf, strlen(buf)) <= 0) {
perror("write");
exit(EXIT_FAILURE);
}
}
/* set slcan line discipline on given tty */
@@ -185,16 +202,15 @@ int main(int argc, char **argv)
}
/* retrieve the name of the created CAN netdevice */
if (ioctl (fd, SIOCGIFNAME, buf) < 0) {
if (ioctl (fd, SIOCGIFNAME, ifr.ifr_name) < 0) {
perror("ioctl SIOCGIFNAME");
exit(1);
}
printf("attached tty %s to netdevice %s\n", tty, buf);
printf("attached tty %s to netdevice %s\n", tty, ifr.ifr_name);
/* try to rename the created device if requested */
if (name) {
struct ifreq ifr;
int s = socket(PF_INET, SOCK_DGRAM, 0);
printf("rename netdevice %s to %s ... ", buf, name);
@@ -202,8 +218,9 @@ int main(int argc, char **argv)
if (s < 0)
perror("socket for interface rename");
else {
strncpy (ifr.ifr_name, buf, IFNAMSIZ);
strncpy (ifr.ifr_newname, name, IFNAMSIZ);
/* current slcan%d name is still in ifr.ifr_name */
memset (ifr.ifr_newname, 0, sizeof(ifr.ifr_newname));
strncpy (ifr.ifr_newname, name, sizeof(ifr.ifr_newname) - 1);
if (ioctl(s, SIOCSIFNAME, &ifr) < 0)
printf("failed!\n");
@@ -229,7 +246,10 @@ int main(int argc, char **argv)
if (send_close) {
sprintf(buf, "C\r");
write(fd, buf, strlen(buf));
if (write(fd, buf, strlen(buf)) <= 0) {
perror("write");
exit(EXIT_FAILURE);
}
}
}
+52 -33
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* slcand.c - userspace daemon for serial line CAN interface driver SLCAN
*
@@ -5,9 +6,8 @@
* Copyright (c) 2009 Verari Systems Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* it under the terms of the version 2 of the GNU General Public License
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -180,7 +180,8 @@ int main(int argc, char *argv[])
char *tty = NULL;
char const *devprefix = "/dev/";
char *name = NULL;
char buf[IFNAMSIZ+1];
char buf[20];
static struct ifreq ifr;
struct termios tios;
speed_t old_ispeed;
speed_t old_ospeed;
@@ -270,6 +271,8 @@ int main(int argc, char *argv[])
print_usage(argv[0]);
name = argv[optind + 1];
if (name && (strlen(name) > sizeof(ifr.ifr_newname) - 1))
print_usage(argv[0]);
/* Prepare the tty device name string */
pch = strstr(tty, devprefix);
@@ -280,23 +283,6 @@ int main(int argc, char *argv[])
syslogger(LOG_INFO, "starting on TTY device %s", ttypath);
/* Daemonize */
if (run_as_daemon) {
if (daemon(0, 0)) {
syslogger(LOG_ERR, "failed to daemonize");
exit(EXIT_FAILURE);
}
}
else {
/* Trap signals that we expect to receive */
signal(SIGINT, child_handler);
signal(SIGTERM, child_handler);
}
/* */
slcand_running = 1;
/* Now we are a daemon -- do the work for which we were paid */
fd = open(ttypath, O_RDWR | O_NONBLOCK | O_NOCTTY);
if (fd < 0) {
syslogger(LOG_NOTICE, "failed to open TTY device %s\n", ttypath);
@@ -305,7 +291,7 @@ int main(int argc, char *argv[])
}
/* Configure baud rate */
memset(&tios, 0, sizeof(struct termios));
memset(&tios, 0, sizeof(tios));
if (tcgetattr(fd, &tios) < 0) {
syslogger(LOG_NOTICE, "failed to get attributes for TTY device %s: %s\n", ttypath, strerror(errno));
exit(EXIT_FAILURE);
@@ -343,25 +329,40 @@ int main(int argc, char *argv[])
if (speed) {
sprintf(buf, "C\rS%s\r", speed);
write(fd, buf, strlen(buf));
if (write(fd, buf, strlen(buf)) <= 0) {
perror("write");
exit(EXIT_FAILURE);
}
}
if (btr) {
sprintf(buf, "C\rs%s\r", btr);
write(fd, buf, strlen(buf));
if (write(fd, buf, strlen(buf)) <= 0) {
perror("write");
exit(EXIT_FAILURE);
}
}
if (send_read_status_flags) {
sprintf(buf, "F\r");
write(fd, buf, strlen(buf));
if (write(fd, buf, strlen(buf)) <= 0) {
perror("write");
exit(EXIT_FAILURE);
}
}
if (send_listen) {
sprintf(buf, "L\r");
write(fd, buf, strlen(buf));
if (write(fd, buf, strlen(buf)) <= 0) {
perror("write");
exit(EXIT_FAILURE);
}
} else if (send_open) {
sprintf(buf, "O\r");
write(fd, buf, strlen(buf));
if (write(fd, buf, strlen(buf)) <= 0) {
perror("write");
exit(EXIT_FAILURE);
}
}
/* set slcan like discipline on given tty */
@@ -371,23 +372,23 @@ int main(int argc, char *argv[])
}
/* retrieve the name of the created CAN netdevice */
if (ioctl(fd, SIOCGIFNAME, buf) < 0) {
if (ioctl(fd, SIOCGIFNAME, ifr.ifr_name) < 0) {
perror("ioctl SIOCGIFNAME");
exit(EXIT_FAILURE);
}
syslogger(LOG_NOTICE, "attached TTY %s to netdevice %s\n", ttypath, buf);
syslogger(LOG_NOTICE, "attached TTY %s to netdevice %s\n", ttypath, ifr.ifr_name);
/* try to rename the created netdevice */
if (name) {
struct ifreq ifr;
int s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0)
perror("socket for interface rename");
else {
strncpy(ifr.ifr_name, buf, IFNAMSIZ);
strncpy(ifr.ifr_newname, name, IFNAMSIZ);
/* current slcan%d name is still in ifr.ifr_name */
memset (ifr.ifr_newname, 0, sizeof(ifr.ifr_newname));
strncpy (ifr.ifr_newname, name, sizeof(ifr.ifr_newname) - 1);
if (ioctl(s, SIOCSIFNAME, &ifr) < 0) {
syslogger(LOG_NOTICE, "netdevice %s rename to %s failed\n", buf, name);
@@ -400,6 +401,21 @@ int main(int argc, char *argv[])
}
}
/* Daemonize */
if (run_as_daemon) {
if (daemon(0, 0)) {
syslogger(LOG_ERR, "failed to daemonize");
exit(EXIT_FAILURE);
}
}
else {
/* Trap signals that we expect to receive */
signal(SIGINT, child_handler);
signal(SIGTERM, child_handler);
}
slcand_running = 1;
/* The Big Loop */
while (slcand_running)
sleep(1); /* wait 1 second */
@@ -414,7 +430,10 @@ int main(int argc, char *argv[])
if (send_close) {
sprintf(buf, "C\r");
write(fd, buf, strlen(buf));
if (write(fd, buf, strlen(buf)) <= 0) {
perror("write");
exit(EXIT_FAILURE);
}
}
/* Reset old rates */
+5 -4
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* slcanpty.c - creates a pty for applications using the slcan ASCII protocol
* and converts the ASCII data to a CAN network interface (and vice versa)
@@ -5,9 +6,8 @@
* Copyright (c)2009 Oliver Hartkopp
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* it under the terms of the version 2 of the GNU General Public License
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -37,6 +37,7 @@
#include <linux/can.h>
#include <linux/can/raw.h>
#include <linux/sockios.h>
/* maximum rx buffer len: extended CAN frame with timestamp */
#define SLC_MTU (sizeof("T1111222281122334455667788EA5F\r")+1)
@@ -74,7 +75,7 @@ int pty2can(int pty, int socket, struct can_filter *fi,
nbytes = read(pty, &buf[rxoffset], sizeof(buf)-rxoffset-1);
if (nbytes <= 0) {
/* nbytes == 0 : no error but pty decriptor has been closed */
/* nbytes == 0 : no error but pty descriptor has been closed */
if (nbytes < 0)
perror("read pty");
+1
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research
* All rights reserved.
+85 -41
View File
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2013 EIA Electronics
*
@@ -19,7 +20,7 @@
#include <unistd.h>
#include <getopt.h>
#include <error.h>
#include <err.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <net/if.h>
@@ -38,6 +39,10 @@ static const char help_msg[] =
" This atually receives packets\n"
" -c Issue connect()\n"
" -p=PRIO Set priority to PRIO\n"
" -P Promiscuous mode. Allow to receive all packets\n"
" -b Do normal bind with SA+1 and rebind with actual SA\n"
" -B Allow to send and receive broadcast packets.\n"
" -o Omit bind\n"
" -n Emit 64bit NAMEs in output\n"
" -w[TIME] Return after TIME (default 1) seconds\n"
"\n"
@@ -46,32 +51,11 @@ static const char help_msg[] =
"\n"
;
static const char optstring[] = "?vs::rep:cnw::";
static void parse_canaddr(char *spec, struct sockaddr_can *paddr)
{
char *str;
str = strsep(&spec, ":");
if (strlen(str))
paddr->can_ifindex = if_nametoindex(str);
str = strsep(&spec, ",");
if (str && strlen(str))
paddr->can_addr.j1939.addr = strtoul(str, NULL, 0);
str = strsep(&spec, ",");
if (str && strlen(str))
paddr->can_addr.j1939.pgn = strtoul(str, NULL, 0);
str = strsep(&spec, ",");
if (str && strlen(str))
paddr->can_addr.j1939.name = strtoul(str, NULL, 0);
}
static const char optstring[] = "?vbBPos::rep:cnw::";
static void onsigalrm(int sig)
{
error(0, 0, "exit as requested");
err(0, "exit as requested");
exit(0);
}
@@ -82,7 +66,7 @@ static void schedule_oneshot_itimer(double delay)
it.it_value.tv_sec = delay;
it.it_value.tv_usec = (long)(delay * 1e6) % 1000000;
if (setitimer(ITIMER_REAL, &it, NULL) < 0)
error(1, errno, "schedule itimer %.3lfs", delay);
err(1, "schedule itimer %.3lfs", delay);
}
/* main */
@@ -109,7 +93,9 @@ int main(int argc, char *argv[])
uint8_t dat[128];
int valid_peername = 0;
int todo_send = 0, todo_recv = 0, todo_echo = 0, todo_prio = -1;
int todo_connect = 0, todo_names = 0, todo_wait = 0;
int todo_connect = 0, todo_names = 0, todo_wait = 0, todo_rebind = 0;
int todo_broadcast = 0, todo_promisc = 0;
int no_bind = 0;
/* argument parsing */
while ((opt = getopt(argc, argv, optstring)) != -1)
@@ -119,6 +105,8 @@ int main(int argc, char *argv[])
break;
case 's':
todo_send = strtoul(optarg ?: "8", NULL, 0);
if (todo_send > sizeof(dat))
err(1, "Unsupported size. max: %zu", sizeof(dat));
break;
case 'r':
todo_recv = 1;
@@ -129,12 +117,24 @@ int main(int argc, char *argv[])
case 'p':
todo_prio = strtoul(optarg, NULL, 0);
break;
case 'P':
todo_promisc = 1;
break;
case 'c':
todo_connect = 1;
break;
case 'n':
todo_names = 1;
break;
case 'b':
todo_rebind = 1;
break;
case 'B':
todo_broadcast = 1;
break;
case 'o':
no_bind = 1;
break;
case 'w':
schedule_oneshot_itimer(strtod(optarg ?: "1", NULL));
signal(SIGALRM, onsigalrm);
@@ -148,13 +148,16 @@ int main(int argc, char *argv[])
if (argv[optind]) {
if (strcmp("-", argv[optind]))
parse_canaddr(argv[optind], &sockname);
libj1939_parse_canaddr(argv[optind], &sockname);
++optind;
}
if (todo_rebind)
sockname.can_addr.j1939.addr++;
if (argv[optind]) {
if (strcmp("-", argv[optind])) {
parse_canaddr(argv[optind], &peername);
libj1939_parse_canaddr(argv[optind], &peername);
valid_peername = 1;
}
++optind;
@@ -165,7 +168,27 @@ int main(int argc, char *argv[])
fprintf(stderr, "- socket(PF_CAN, SOCK_DGRAM, CAN_J1939);\n");
sock = ret = socket(PF_CAN, SOCK_DGRAM, CAN_J1939);
if (ret < 0)
error(1, errno, "socket(j1939)");
err(1, "socket(j1939)");
if (todo_promisc) {
if (verbose)
fprintf(stderr, "- setsockopt(, SOL_SOCKET, SO_J1939_PROMISC, %d, %zd);\n",
todo_promisc, sizeof(todo_promisc));
ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_PROMISC,
&todo_promisc, sizeof(todo_promisc));
if (ret < 0)
err(1, "setsockopt: filed to set promiscuous mode");
}
if (todo_broadcast) {
if (verbose)
fprintf(stderr, "- setsockopt(, SOL_SOCKET, SO_BROADCAST, %d, %zd);\n",
todo_broadcast, sizeof(todo_broadcast));
ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
&todo_broadcast, sizeof(todo_broadcast));
if (ret < 0)
err(1, "setsockopt: filed to set broadcast");
}
if (todo_prio >= 0) {
if (verbose)
@@ -173,23 +196,37 @@ int main(int argc, char *argv[])
ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_SEND_PRIO,
&todo_prio, sizeof(todo_prio));
if (ret < 0)
error(1, errno, "set priority %i", todo_prio);
err(1, "set priority %i", todo_prio);
}
if (verbose)
fprintf(stderr, "- bind(, %s, %zi);\n", libj1939_addr2str(&sockname), sizeof(sockname));
ret = bind(sock, (void *)&sockname, sizeof(sockname));
if (ret < 0)
error(1, errno, "bind()");
if (!no_bind) {
if (verbose)
fprintf(stderr, "- bind(, %s, %zi);\n", libj1939_addr2str(&sockname), sizeof(sockname));
ret = bind(sock, (void *)&sockname, sizeof(sockname));
if (ret < 0)
err(1, "bind()");
if (todo_rebind) {
/* rebind with actual SA */
sockname.can_addr.j1939.addr--;
if (verbose)
fprintf(stderr, "- bind(, %s, %zi);\n", libj1939_addr2str(&sockname), sizeof(sockname));
ret = bind(sock, (void *)&sockname, sizeof(sockname));
if (ret < 0)
err(1, "re-bind()");
}
}
if (todo_connect) {
if (!valid_peername)
error(1, 0, "no peername supplied");
err(1, "no peername supplied");
if (verbose)
fprintf(stderr, "- connect(, %s, %zi);\n", libj1939_addr2str(&peername), sizeof(peername));
ret = connect(sock, (void *)&peername, sizeof(peername));
if (ret < 0)
error(1, errno, "connect()");
err(1, "connect()");
}
if (todo_send) {
@@ -218,7 +255,7 @@ int main(int argc, char *argv[])
}
if (ret < 0)
error(1, errno, "sendto");
err(1, "sendto");
}
/* main loop */
@@ -240,7 +277,7 @@ int main(int argc, char *argv[])
fprintf(stderr, "-\t<interrupted>\n");
continue;
}
error(1, errno, "recvfrom()");
err(1, "recvfrom()");
}
if (todo_echo) {
@@ -249,15 +286,22 @@ int main(int argc, char *argv[])
ret = sendto(sock, dat, ret, 0,
(void *)&peername, peernamelen);
if (ret < 0)
error(1, errno, "sendto");
err(1, "sendto");
}
if (todo_recv) {
int i = 0;
if (todo_names && peername.can_addr.j1939.name)
printf("%016llx ", peername.can_addr.j1939.name);
printf("%02x %05x:", peername.can_addr.j1939.addr,
peername.can_addr.j1939.pgn);
for (j = 0; j < ret; ++j)
for (j = 0; j < ret; ++j, i++) {
if (i == 8) {
printf("\n%05x ", j);
i = 0;
}
printf(" %02x", dat[j]);
}
printf("\n");
}
}