mirror of
https://github.com/linux-can/can-utils.git
synced 2026-09-21 15:29:56 +02:00
Compare commits
327
Commits
v2018.02.0
...
v2020.11.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
856d0a662a | ||
|
|
ccfa3c8b00 | ||
|
|
a6cac755b4 | ||
|
|
86bfa25f9d | ||
|
|
4573e852f9 | ||
|
|
09466c2f1d | ||
|
|
eada3b4f53 | ||
|
|
cb5d2fd653 | ||
|
|
a726c2a57a | ||
|
|
a8131b7996 | ||
|
|
93ef09d9b0 | ||
|
|
677f9ec26f | ||
|
|
f3cf4cdf88 | ||
|
|
2afcbd2fee | ||
|
|
00134246c2 | ||
|
|
a1c20aeb45 | ||
|
|
d699135833 | ||
|
|
de5b9607dc | ||
|
|
36fc75bdb7 | ||
|
|
68d5f87889 | ||
|
|
4d50109a69 | ||
|
|
ac9124c776 | ||
|
|
0bcb5d9c2c | ||
|
|
1e0fb39e8b | ||
|
|
9567230494 | ||
|
|
985121aaad | ||
|
|
7975f9859c | ||
|
|
c9bb22022d | ||
|
|
2f125e44ce | ||
|
|
9841820ea0 | ||
|
|
fb5903f226 | ||
|
|
4aaad29082 | ||
|
|
a16f8ed471 | ||
|
|
6e3b123d5b | ||
|
|
c93d3a63c5 | ||
|
|
5fa35cbe2a | ||
|
|
f4cec293dc | ||
|
|
bd3ea25fe1 | ||
|
|
d8be4d8a4f | ||
|
|
b3b501d922 | ||
|
|
0c888d7942 | ||
|
|
ac8ae17727 | ||
|
|
3794644caa | ||
|
|
fc3b0449a9 | ||
|
|
c55d181360 | ||
|
|
d8435a56af | ||
|
|
204235c9ce | ||
|
|
d3b29dfa48 | ||
|
|
a591dadd96 | ||
|
|
5e713b3ee0 | ||
|
|
5d5ccf38ee | ||
|
|
bda4b0ad8c | ||
|
|
f766174677 | ||
|
|
7759b00c58 | ||
|
|
48bb69bc7b | ||
|
|
b153fe3f35 | ||
|
|
3e85fc5422 | ||
|
|
33f3593436 | ||
|
|
3e67b5cbd1 | ||
|
|
d5320d554e | ||
|
|
17a5fe6022 | ||
|
|
5a93509655 | ||
|
|
d7df79e687 | ||
|
|
18573d1dd2 | ||
|
|
8d2ed4c959 | ||
|
|
c27c61424f | ||
|
|
194959270f | ||
|
|
f6d963b5d9 | ||
|
|
485d813545 | ||
|
|
ce7f22928d | ||
|
|
dd8fb0b697 | ||
|
|
b7ba7f32fc | ||
|
|
b99f540039 | ||
|
|
7fb2585641 | ||
|
|
e1f75da433 | ||
|
|
435a59a394 | ||
|
|
73e421557f | ||
|
|
ea844bdc5e | ||
|
|
e6dfcb773e | ||
|
|
c43a168c68 | ||
|
|
7cb3e760fe | ||
|
|
a4905ed7c8 | ||
|
|
ab23c6f7e7 | ||
|
|
c912d6f8d5 | ||
|
|
58dc257e11 | ||
|
|
327587b2c8 | ||
|
|
659e0acfe6 | ||
|
|
88ad7e5755 | ||
|
|
112421dc22 | ||
|
|
dec3c5eda1 | ||
|
|
bad90515f0 | ||
|
|
da87d595c5 | ||
|
|
af531c3d52 | ||
|
|
8e3c050b1c | ||
|
|
a5c049d37a | ||
|
|
57949154cc | ||
|
|
24b73044c5 | ||
|
|
b29a75d4c6 | ||
|
|
0f9c69c193 | ||
|
|
13ecaa6d7e | ||
|
|
d7f28a0ffe | ||
|
|
e393697112 | ||
|
|
645cd1b1ba | ||
|
|
aa5386f1cb | ||
|
|
ff3d0e0d05 | ||
|
|
29605e3314 | ||
|
|
d92adf68e8 | ||
|
|
063e361cc5 | ||
|
|
e9e1a02085 | ||
|
|
19b3ffe34b | ||
|
|
6553ccaf06 | ||
|
|
1b5d3adbe5 | ||
|
|
e15b044a1d | ||
|
|
669fa79b21 | ||
|
|
75d9c7e95f | ||
|
|
85ae5aaecf | ||
|
|
1f5c9638ab | ||
|
|
1d3125bef2 | ||
|
|
62f995601e | ||
|
|
647210ee1c | ||
|
|
eac93ced80 | ||
|
|
da42cf4bb5 | ||
|
|
43610bd621 | ||
|
|
46895a41c5 | ||
|
|
2c87dcf468 | ||
|
|
8df3d1dd3f | ||
|
|
255e360233 | ||
|
|
d91288f754 | ||
|
|
9b75c6020f | ||
|
|
41c8ead6c0 | ||
|
|
3bb659d18d | ||
|
|
9cde2ebe8f | ||
|
|
7729c046c5 | ||
|
|
61dbb56ef6 | ||
|
|
3014d390b4 | ||
|
|
ad9fc28f9e | ||
|
|
9a079942cd | ||
|
|
ed9c646608 | ||
|
|
df0b25c17e | ||
|
|
3c8197e4d1 | ||
|
|
43a3cca54d | ||
|
|
becc0fc6cc | ||
|
|
c5cb7e1a7c | ||
|
|
729e346d31 | ||
|
|
7575d43fd2 | ||
|
|
2a8867f3cb | ||
|
|
ab2e8ffe0e | ||
|
|
ac55db508a | ||
|
|
64e33bf9ad | ||
|
|
adf29573f4 | ||
|
|
bd6ef44321 | ||
|
|
6d112a7209 | ||
|
|
6f44582c19 | ||
|
|
507ff82d81 | ||
|
|
1665abf46f | ||
|
|
853989bed2 | ||
|
|
f3ced10007 | ||
|
|
819a03f6e2 | ||
|
|
e266422c54 | ||
|
|
5ca66d7bea | ||
|
|
d007263021 | ||
|
|
f91b537c01 | ||
|
|
b43d1b4d27 | ||
|
|
f638cdc79b | ||
|
|
d89b38de8a | ||
|
|
d39cb046d1 | ||
|
|
9e491bc553 | ||
|
|
09f6dc6d17 | ||
|
|
8e6c11128d | ||
|
|
276688f2ad | ||
|
|
0155472ee0 | ||
|
|
211c5cea49 | ||
|
|
c1fdfb09fc | ||
|
|
506252e9bc | ||
|
|
89c66aba5f | ||
|
|
c61c9bc030 | ||
|
|
9240ccfcb7 | ||
|
|
3d6a53550e | ||
|
|
1cf4d86874 | ||
|
|
4db63e4b55 | ||
|
|
24af048812 | ||
|
|
4568d4a180 | ||
|
|
3e2c1d3cbd | ||
|
|
65399166c1 | ||
|
|
1127609357 | ||
|
|
f503097a38 | ||
|
|
c56259ab33 | ||
|
|
6db632531d | ||
|
|
f4a9e5b57d | ||
|
|
69865c8247 | ||
|
|
b740fb7fab | ||
|
|
bceadb8696 | ||
|
|
eb639c1b3d | ||
|
|
6cdccbbafc | ||
|
|
8106214b55 | ||
|
|
da65fdfe0d | ||
|
|
ae69062657 | ||
|
|
506f6f3043 | ||
|
|
8027b498cf | ||
|
|
a9985c7652 | ||
|
|
665d8699eb | ||
|
|
4e36059f6a | ||
|
|
6831eeeb62 | ||
|
|
a8456276df | ||
|
|
6eeedb0e66 | ||
|
|
b6a44803fd | ||
|
|
153501c0ab | ||
|
|
8cf6353039 | ||
|
|
5d3f8073b2 | ||
|
|
d75122f649 | ||
|
|
9ae877ce32 | ||
|
|
da33f96edf | ||
|
|
b04108c615 | ||
|
|
ecf80e8f91 | ||
|
|
bf30a4bc01 | ||
|
|
63d9a3d87b | ||
|
|
c0dba0a454 | ||
|
|
a67bf7aa89 | ||
|
|
276077de00 | ||
|
|
ffd60c9b74 | ||
|
|
8426d63ecf | ||
|
|
14ccc06eba | ||
|
|
35b2ef691c | ||
|
|
a08b61621d | ||
|
|
275f606a1f | ||
|
|
791b6de786 | ||
|
|
7e9bc7719b | ||
|
|
0b93e9836f | ||
|
|
d66295ee75 | ||
|
|
26ae1fffa8 | ||
|
|
de8bb5fd8f | ||
|
|
a8d4827d0f | ||
|
|
7337cb12de | ||
|
|
d5ba0e2d23 | ||
|
|
226d6393b8 | ||
|
|
1331c56393 | ||
|
|
319bd5de45 | ||
|
|
83a1210b75 | ||
|
|
818dacd78f | ||
|
|
d45f3f46bd | ||
|
|
07054c06f5 | ||
|
|
24923df749 | ||
|
|
0669215a4b | ||
|
|
9aa993df4c | ||
|
|
c10c049ce7 | ||
|
|
e9590b1ca7 | ||
|
|
9ffb16495c | ||
|
|
59f92965b9 | ||
|
|
9d0c08d8cb | ||
|
|
bb2cc1140f | ||
|
|
c4e68aff78 | ||
|
|
0e542c8dba | ||
|
|
7b7331976a | ||
|
|
a965086356 | ||
|
|
8ada533538 | ||
|
|
f185160bfb | ||
|
|
0d8b0a8837 | ||
|
|
045f75ad64 | ||
|
|
25025d05ae | ||
|
|
edcce70373 | ||
|
|
05368ef1ae | ||
|
|
05a66d63fa | ||
|
|
6260263ef3 | ||
|
|
9ff370ea82 | ||
|
|
e92806db21 | ||
|
|
5e342e3c50 | ||
|
|
38fa644069 | ||
|
|
afb88e9019 | ||
|
|
19d41bec45 | ||
|
|
48a4a4bef4 | ||
|
|
b931fb514c | ||
|
|
7192b0b9d7 | ||
|
|
b8a2fa319a | ||
|
|
314f8a92ae | ||
|
|
06d3beb08c | ||
|
|
83667e822c | ||
|
|
9f60ed6fa0 | ||
|
|
e1d5ee9907 | ||
|
|
c59dff1bb1 | ||
|
|
4a1818aa55 | ||
|
|
b6cb9a04e5 | ||
|
|
46d620b27c | ||
|
|
2328c6cfa0 | ||
|
|
e0277cc960 | ||
|
|
7b70a433cf | ||
|
|
5551de5e56 | ||
|
|
ed5b495da6 | ||
|
|
4da344b2aa | ||
|
|
8991b5c47d | ||
|
|
f6e07960d3 | ||
|
|
02b87eb120 | ||
|
|
5b68a2cef1 | ||
|
|
0083a3762b | ||
|
|
23e5e227ac | ||
|
|
e649b6ee2a | ||
|
|
c45a17e96b | ||
|
|
8681e57230 | ||
|
|
3f2bc6e1ea | ||
|
|
371d8e6da4 | ||
|
|
12664efa9f | ||
|
|
04c171c285 | ||
|
|
572a66fb94 | ||
|
|
a6954bdaae | ||
|
|
1c81f7fb2d | ||
|
|
5b8145f63d | ||
|
|
3e4d589fec | ||
|
|
54ff81cc40 | ||
|
|
1ba9b86451 | ||
|
|
1ce4dc7b39 | ||
|
|
ba603c59ae | ||
|
|
18834410ac | ||
|
|
0ff988eeef | ||
|
|
55b0ba8308 | ||
|
|
7a4dd732af | ||
|
|
db7261d403 | ||
|
|
6cedc8a5c6 | ||
|
|
d0c855c558 | ||
|
|
8a3e0453aa | ||
|
|
47f2e7a180 | ||
|
|
872b73766c | ||
|
|
33a9249571 | ||
|
|
01041fddd6 | ||
|
|
f51c897d68 | ||
|
|
9d52f81058 | ||
|
|
6ca4ce8ac9 | ||
|
|
8389744f79 | ||
|
|
b00cb24f12 |
@@ -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
|
||||
+5
-3
@@ -32,6 +32,7 @@ GNUmakefile.in
|
||||
/canlogserver
|
||||
/canplayer
|
||||
/cansend
|
||||
/cansequence
|
||||
/cansniffer
|
||||
/isotpdump
|
||||
/isotpperf
|
||||
@@ -40,9 +41,10 @@ GNUmakefile.in
|
||||
/isotpserver
|
||||
/isotpsniffer
|
||||
/isotptun
|
||||
/jacd
|
||||
/jspy
|
||||
/jsr
|
||||
/j1939acd
|
||||
/j1939cat
|
||||
/j1939spy
|
||||
/j1939sr
|
||||
/log2asc
|
||||
/log2long
|
||||
/slcan_attach
|
||||
|
||||
+135
-2
@@ -2,6 +2,9 @@ language: c
|
||||
|
||||
matrix:
|
||||
include:
|
||||
|
||||
# native
|
||||
|
||||
- env: test="x64 4.8.4 (make)"
|
||||
os: linux
|
||||
dist: trusty
|
||||
@@ -12,13 +15,141 @@ 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
|
||||
|
||||
# ppc64le
|
||||
|
||||
- env: test="ppc64le 4.8.4 (make)"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: gcc
|
||||
script: make
|
||||
arch: ppc64le
|
||||
|
||||
- env: test="ppc64le 4.8.4 (autotools)"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: gcc
|
||||
script: ./autogen.sh && ./configure CFLAGS="-Werror -Wno-unused-result" && make distcheck
|
||||
arch: ppc64le
|
||||
|
||||
- env: test="ppc64le 5.0 (autotools)"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: clang
|
||||
script: ./autogen.sh && ./configure CFLAGS="-Werror -Wno-unused-result" && make distcheck
|
||||
arch: ppc64le
|
||||
|
||||
- env: test="ppc64le 4.8.4 (CMake gcc)"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: gcc
|
||||
before_script:
|
||||
- mkdir gcc_rel && cd gcc_rel
|
||||
- cmake ..
|
||||
script: make
|
||||
arch: ppc64le
|
||||
|
||||
- env: test="ppc64le 5.0 (CMake clang)"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: clang
|
||||
before_script:
|
||||
- mkdir clang_rel && cd clang_rel
|
||||
- cmake ..
|
||||
script: make
|
||||
arch: ppc64le
|
||||
|
||||
- env: test="ppc64le 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
|
||||
arch: ppc64le
|
||||
|
||||
# Android
|
||||
|
||||
- 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 +158,7 @@ addons:
|
||||
- automake
|
||||
- libtool
|
||||
- m4
|
||||
- cmake
|
||||
- ninja-build
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
+150
-2
@@ -1,6 +1,7 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
PRIVATE_LOCAL_CFLAGS := -O2 -g -W -Wall \
|
||||
-Wno-error=unused-parameter \
|
||||
-DSO_RXQ_OVFL=40 \
|
||||
-DPF_CAN=29 \
|
||||
-DAF_CAN=PF_CAN
|
||||
@@ -15,9 +16,104 @@ LOCAL_SRC_FILES := lib.c canframelen.c
|
||||
LOCAL_MODULE := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
#
|
||||
# j1939lib
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := libj1939.c
|
||||
LOCAL_MODULE := libj1939
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
#
|
||||
# j1939acd
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := j1939acd.c
|
||||
LOCAL_MODULE := j1939acd
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libj1939
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# j1939cat
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := j1939cat.c
|
||||
LOCAL_MODULE := j1939cat
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libj1939
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# j1939spy
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := j1939spy.c
|
||||
LOCAL_MODULE := j1939spy
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libj1939
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# j1939sr
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := j1939sr.c
|
||||
LOCAL_MODULE := j1939sr
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libj1939
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# testj1939
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := testj1939.c
|
||||
LOCAL_MODULE := testj1939
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libj1939
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# candump
|
||||
#
|
||||
@@ -30,6 +126,7 @@ LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -45,6 +142,21 @@ LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# cansequence
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := cansequence.c
|
||||
LOCAL_MODULE := cansequence
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -59,10 +171,10 @@ LOCAL_MODULE := bcmserver
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
|
||||
#
|
||||
# can-calc-bit-timing
|
||||
#
|
||||
@@ -74,6 +186,7 @@ LOCAL_MODULE := can-calc-bit-timing
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -89,6 +202,7 @@ LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -103,6 +217,7 @@ LOCAL_MODULE := canfdtest
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -118,6 +233,7 @@ LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -132,6 +248,7 @@ LOCAL_MODULE := cangw
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -147,6 +264,7 @@ LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -162,6 +280,7 @@ LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -176,6 +295,7 @@ LOCAL_MODULE := cansniffer
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -190,6 +310,7 @@ LOCAL_MODULE := isotpdump
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -204,6 +325,7 @@ LOCAL_MODULE := isotprecv
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -218,6 +340,7 @@ LOCAL_MODULE := isotpsend
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -232,6 +355,7 @@ LOCAL_MODULE := isotpserver
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -242,10 +366,11 @@ include $(BUILD_EXECUTABLE)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := isotpsniffer.c
|
||||
LOCAL_MODULE := isotpsniffer.c
|
||||
LOCAL_MODULE := isotpsniffer
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -260,6 +385,7 @@ LOCAL_MODULE := isotptun
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -274,6 +400,7 @@ LOCAL_MODULE := isotpperf
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -289,6 +416,23 @@ LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# asc2log
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := asc2log.c
|
||||
LOCAL_MODULE := asc2log
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -304,6 +448,7 @@ LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -318,6 +463,7 @@ LOCAL_MODULE := slcan_attach
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -332,6 +478,7 @@ LOCAL_MODULE := slcand
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -346,5 +493,6 @@ LOCAL_MODULE := slcanpty
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
cmake_minimum_required(VERSION 3.3)
|
||||
|
||||
project(can-utils LANGUAGES C)
|
||||
|
||||
include (CheckSymbolExists)
|
||||
include (GNUInstallDirs)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif()
|
||||
|
||||
check_symbol_exists(__GNU_LIBRARY__ "features.h" _GNU_SOURCE)
|
||||
if(_GNU_SOURCE)
|
||||
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
|
||||
cansequence
|
||||
log2asc
|
||||
log2long
|
||||
)
|
||||
|
||||
set(PROGRAMS_J1939
|
||||
j1939acd
|
||||
j1939cat
|
||||
j1939spy
|
||||
j1939sr
|
||||
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")
|
||||
+15
-10
@@ -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 \
|
||||
@@ -48,6 +50,7 @@ bin_PROGRAMS = \
|
||||
canlogserver \
|
||||
canplayer \
|
||||
cansend \
|
||||
cansequence \
|
||||
cansniffer \
|
||||
isotpdump \
|
||||
isotpperf \
|
||||
@@ -56,9 +59,10 @@ bin_PROGRAMS = \
|
||||
isotpserver \
|
||||
isotpsniffer \
|
||||
isotptun \
|
||||
jacd \
|
||||
jspy \
|
||||
jsr \
|
||||
j1939acd \
|
||||
j1939cat \
|
||||
j1939spy \
|
||||
j1939sr \
|
||||
log2asc \
|
||||
log2long \
|
||||
slcan_attach \
|
||||
@@ -66,9 +70,10 @@ bin_PROGRAMS = \
|
||||
slcanpty \
|
||||
testj1939
|
||||
|
||||
jacd_LDADD = libj1939.la
|
||||
jspy_LDADD = libj1939.la
|
||||
jsr_LDADD = libj1939.la
|
||||
j1939acd_LDADD = libj1939.la
|
||||
j1939cat_LDADD = libj1939.la
|
||||
j1939spy_LDADD = libj1939.la
|
||||
j1939sr_LDADD = libj1939.la
|
||||
testj1939_LDADD = libj1939.la
|
||||
|
||||
EXTRA_DIST = \
|
||||
@@ -76,7 +81,7 @@ EXTRA_DIST = \
|
||||
Android.mk \
|
||||
README.md \
|
||||
autogen.sh \
|
||||
can-j1939-kickstart.md
|
||||
can-j1939-kickstart.md \
|
||||
can-j1939.md
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -41,29 +41,62 @@
|
||||
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 := \
|
||||
j1939acd \
|
||||
j1939cat \
|
||||
j1939spy \
|
||||
j1939sr \
|
||||
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 \
|
||||
cansequence \
|
||||
canlogserver \
|
||||
canplayer \
|
||||
cansend \
|
||||
cansniffer \
|
||||
log2asc \
|
||||
log2long \
|
||||
slcanpty
|
||||
|
||||
all: $(PROGRAMS)
|
||||
|
||||
@@ -77,31 +110,35 @@ 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
|
||||
jacd.o: libj1939.h
|
||||
jspy.o: libj1939.h
|
||||
jsr.o: libj1939.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
|
||||
cansequence.o: lib.h
|
||||
log2asc.o: lib.h
|
||||
log2long.o: lib.h
|
||||
j1939acd.o: libj1939.h
|
||||
j1939cat.o: libj1939.h
|
||||
j1939spy.o: libj1939.h
|
||||
j1939sr.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
|
||||
jacd: jacd.o libj1939.o
|
||||
jspy: jspy.o libj1939.o
|
||||
jsr: jsr.o libj1939.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
|
||||
cansequence: cansequence.o lib.o
|
||||
log2asc: log2asc.o lib.o
|
||||
log2long: log2long.o lib.o
|
||||
j1939acd: j1939acd.o libj1939.o
|
||||
j1939cat: j1939cat.o libj1939.o
|
||||
j1939spy: j1939spy.o libj1939.o
|
||||
j1939sr: j1939sr.o libj1939.o
|
||||
testj1939: testj1939.o libj1939.o
|
||||
canbusload: canbusload.o canframelen.o
|
||||
|
||||
@@ -13,15 +13,17 @@ subsystem (aka SocketCAN):
|
||||
* canplayer : replay CAN logfiles
|
||||
* cansend : send a single frame
|
||||
* cangen : generate (random) CAN traffic
|
||||
* cansniffer : display CAN data content differences (just 11bit CAN IDs)
|
||||
* cansequence : send and check sequence of CAN frames with incrementing payload
|
||||
* cansniffer : display CAN data content differences
|
||||
|
||||
#### 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
|
||||
@@ -37,6 +39,16 @@ subsystem (aka SocketCAN):
|
||||
* isotpperf : ISO15765-2 protocol performance visualisation
|
||||
* isotptun : create a bi-directional IP tunnel on CAN via ISO-TP
|
||||
|
||||
#### J1939/ISOBus tools
|
||||
* j1939acd : address claim daemon
|
||||
* j1939cat : take a file and send and receive it over CAN
|
||||
* j1939spy : spy on J1939 messages using SOC_J1939
|
||||
* j1939sr : send/recv from stdin or to stdout
|
||||
* testj1939 : send/receive test packet
|
||||
|
||||
Follow the link to see examples on how this tools can be used:
|
||||
[Kickstart guide to can-j1939 on linux](https://github.com/linux-can/can-utils/blob/master/can-j1939-kickstart.md)
|
||||
|
||||
#### Log file converters
|
||||
* asc2log : convert ASC logfile to compact CAN frame logfile
|
||||
* log2asc : convert compact CAN frame logfile to ASC logfile
|
||||
@@ -47,6 +59,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,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* asc2log.c - convert ASC logfile to compact CAN frame logfile
|
||||
*
|
||||
@@ -41,44 +42,47 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <libgen.h>
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <libgen.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/error.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#define BUFLEN 400 /* CAN FD mode lines can be pretty long */
|
||||
|
||||
extern int optind, opterr, optopt;
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - convert ASC logfile to compact CAN frame logfile.\n", prg);
|
||||
fprintf(stderr, "Usage: %s\n", prg);
|
||||
fprintf(stderr, "Options: -I <infile> (default stdin)\n");
|
||||
fprintf(stderr, " -O <outfile> (default stdout)\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, "\t-I <infile>\t(default stdin)\n");
|
||||
fprintf(stderr, "\t-O <outfile>\t(default stdout)\n");
|
||||
}
|
||||
|
||||
void prframe(FILE *file, struct timeval *tv, int dev, struct can_frame *cf) {
|
||||
void prframe(FILE *file, struct timeval *tv, int dev, struct canfd_frame *cf, unsigned int max_dlen, char *extra_info) {
|
||||
|
||||
fprintf(file, "(%ld.%06ld) ", tv->tv_sec, tv->tv_usec);
|
||||
fprintf(file, "(%lu.%06lu) ", tv->tv_sec, tv->tv_usec);
|
||||
|
||||
if (dev > 0)
|
||||
fprintf(file, "can%d ", dev-1);
|
||||
else
|
||||
fprintf(file, "canX ");
|
||||
|
||||
/* no CAN FD support so far */
|
||||
fprint_canframe(file, (struct canfd_frame *)cf, "\n", 0, CAN_MAX_DLEN);
|
||||
fprint_canframe(file, cf, extra_info, 0, max_dlen);
|
||||
}
|
||||
|
||||
void get_can_id(struct can_frame *cf, char *idstring, int base) {
|
||||
void get_can_id(struct canfd_frame *cf, char *idstring, int base) {
|
||||
|
||||
if (idstring[strlen(idstring)-1] == 'x') {
|
||||
cf->can_id = CAN_EFF_FLAG;
|
||||
@@ -121,14 +125,224 @@ void calc_tv(struct timeval *tv, struct timeval *read_tv,
|
||||
}
|
||||
}
|
||||
|
||||
void eval_can(char* buf, struct timeval *date_tvp, char timestamps, char base, int dplace, FILE *outfile) {
|
||||
|
||||
int interface;
|
||||
static struct timeval tv; /* current frame timestamp */
|
||||
static struct timeval read_tv; /* frame timestamp from ASC file */
|
||||
struct canfd_frame cf;
|
||||
char rtr;
|
||||
int dlc = 0;
|
||||
int data[8];
|
||||
char tmp1[BUFLEN];
|
||||
char dir[3]; /* 'Rx' or 'Tx' plus terminating zero */
|
||||
char *extra_info;
|
||||
int i, items, found;
|
||||
|
||||
/* 0.002367 1 390x Rx d 8 17 00 14 00 C0 00 08 00 */
|
||||
|
||||
found = 0; /* found valid CAN frame ? */
|
||||
|
||||
if (base == 'h') { /* check for CAN frames with hexadecimal values */
|
||||
|
||||
items = sscanf(buf, "%lu.%lu %d %s %2s %c %d %x %x %x %x %x %x %x %x",
|
||||
&read_tv.tv_sec, &read_tv.tv_usec, &interface,
|
||||
tmp1, dir, &rtr, &dlc,
|
||||
&data[0], &data[1], &data[2], &data[3],
|
||||
&data[4], &data[5], &data[6], &data[7]);
|
||||
|
||||
if ((items == dlc + 7 ) || /* data frame */
|
||||
((items == 6) && (rtr == 'r')) || /* RTR without DLC */
|
||||
((items == 7) && (rtr == 'r'))) { /* RTR with DLC */
|
||||
found = 1;
|
||||
get_can_id(&cf, tmp1, 16);
|
||||
}
|
||||
|
||||
} else { /* check for CAN frames with decimal values */
|
||||
|
||||
items = sscanf(buf, "%lu.%lu %d %s %2s %c %d %d %d %d %d %d %d %d %d",
|
||||
&read_tv.tv_sec, &read_tv.tv_usec, &interface,
|
||||
tmp1, dir, &rtr, &dlc,
|
||||
&data[0], &data[1], &data[2], &data[3],
|
||||
&data[4], &data[5], &data[6], &data[7]);
|
||||
|
||||
if ((items == dlc + 7 ) || /* data frame */
|
||||
((items == 6) && (rtr == 'r')) || /* RTR without DLC */
|
||||
((items == 7) && (rtr == 'r'))) { /* RTR with DLC */
|
||||
found = 1;
|
||||
get_can_id(&cf, tmp1, 10);
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
|
||||
if (dlc > CAN_MAX_DLC)
|
||||
return;
|
||||
|
||||
if (strlen(dir) != 2) /* "Rx" or "Tx" */
|
||||
return;
|
||||
|
||||
if (dir[0] == 'R')
|
||||
extra_info = " R\n";
|
||||
else
|
||||
extra_info = " T\n";
|
||||
|
||||
cf.len = dlc;
|
||||
if (rtr == 'r')
|
||||
cf.can_id |= CAN_RTR_FLAG;
|
||||
else
|
||||
for (i = 0; i < dlc; i++)
|
||||
cf.data[i] = data[i] & 0xFFU;
|
||||
|
||||
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
|
||||
prframe(outfile, &tv, interface, &cf, CAN_MAX_DLEN, extra_info);
|
||||
fflush(outfile);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check for ErrorFrames */
|
||||
if (sscanf(buf, "%lu.%lu %d %s",
|
||||
&read_tv.tv_sec, &read_tv.tv_usec,
|
||||
&interface, tmp1) == 4) {
|
||||
|
||||
if (!strncmp(tmp1, "ErrorFrame", strlen("ErrorFrame"))) {
|
||||
|
||||
memset(&cf, 0, sizeof(cf));
|
||||
/* do not know more than 'Error' */
|
||||
cf.can_id = (CAN_ERR_FLAG | CAN_ERR_BUSERROR);
|
||||
cf.len = CAN_ERR_DLC;
|
||||
|
||||
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
|
||||
prframe(outfile, &tv, interface, &cf, CAN_MAX_DLEN, "\n");
|
||||
fflush(outfile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps, int dplace, FILE *outfile) {
|
||||
|
||||
int interface;
|
||||
static struct timeval tv; /* current frame timestamp */
|
||||
static struct timeval read_tv; /* frame timestamp from ASC file */
|
||||
struct canfd_frame cf = { 0 };
|
||||
unsigned char brs, esi, ctmp;
|
||||
unsigned int flags;
|
||||
int dlc, dlen = 0;
|
||||
char tmp1[BUFLEN];
|
||||
char dir[3]; /* 'Rx' or 'Tx' plus terminating zero */
|
||||
char *extra_info;
|
||||
char *ptr;
|
||||
int i;
|
||||
|
||||
/* The CANFD format is mainly in hex representation but <DataLength>
|
||||
and probably some content we skip anyway. Don't trust the docs! */
|
||||
|
||||
/* 21.671796 CANFD 1 Tx 11 msgCanFdFr1 1 0 a 16 \
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 59 c0 \
|
||||
100000 214 223040 80000000 46500250 460a0250 20011736 20010205 */
|
||||
|
||||
/* check for valid line without symbolic name */
|
||||
if (sscanf(buf, "%lu.%lu %*s %d %2s %s %hhx %hhx %x %d ",
|
||||
&read_tv.tv_sec, &read_tv.tv_usec, &interface,
|
||||
dir, tmp1, &brs, &esi, &dlc, &dlen) != 9) {
|
||||
|
||||
/* check for valid line with a symbolic name */
|
||||
if (sscanf(buf, "%lu.%lu %*s %d %2s %s %*s %hhx %hhx %x %d ",
|
||||
&read_tv.tv_sec, &read_tv.tv_usec, &interface,
|
||||
dir, tmp1, &brs, &esi, &dlc, &dlen) != 9) {
|
||||
|
||||
/* no valid CANFD format pattern */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for allowed (unsigned) value ranges */
|
||||
if ((dlen > CANFD_MAX_DLEN) || (dlc > CANFD_MAX_DLC) ||
|
||||
(brs > 1) || (esi > 1))
|
||||
return;
|
||||
|
||||
if (strlen(dir) != 2) /* "Rx" or "Tx" */
|
||||
return;
|
||||
|
||||
if (dir[0] == 'R')
|
||||
extra_info = " R\n";
|
||||
else
|
||||
extra_info = " T\n";
|
||||
|
||||
/* don't trust ASCII content - sanitize data length */
|
||||
if (dlen != can_dlc2len(can_len2dlc(dlen)))
|
||||
return;
|
||||
|
||||
get_can_id(&cf, tmp1, 16);
|
||||
|
||||
/* now search for the beginning of the data[] content */
|
||||
sprintf(tmp1, " %x %x %x %2d ", brs, esi, dlc, dlen);
|
||||
|
||||
/* search for the pattern generated by real data */
|
||||
ptr = strcasestr(buf, tmp1);
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
|
||||
ptr += strlen(tmp1); /* start of ASCII hex frame data */
|
||||
|
||||
cf.len = dlen;
|
||||
|
||||
for (i = 0; i < dlen; i++) {
|
||||
ctmp = asc2nibble(ptr[0]);
|
||||
if (ctmp > 0x0F)
|
||||
return;
|
||||
|
||||
cf.data[i] = (ctmp << 4);
|
||||
|
||||
ctmp = asc2nibble(ptr[1]);
|
||||
if (ctmp > 0x0F)
|
||||
return;
|
||||
|
||||
cf.data[i] |= ctmp;
|
||||
|
||||
ptr += 3; /* start of next ASCII hex byte */
|
||||
}
|
||||
|
||||
/* skip MessageDuration and MessageLength to get Flags value */
|
||||
if (sscanf(ptr, " %*x %*x %x ", &flags) != 1)
|
||||
return;
|
||||
|
||||
/* relevant flags in Flags field */
|
||||
#define ASC_F_RTR 0x00000010
|
||||
#define ASC_F_FDF 0x00001000
|
||||
#define ASC_F_BRS 0x00002000
|
||||
#define ASC_F_ESI 0x00004000
|
||||
|
||||
if (flags & ASC_F_FDF) {
|
||||
dlen = CANFD_MAX_DLEN;
|
||||
if (flags & ASC_F_BRS)
|
||||
cf.flags |= CANFD_BRS;
|
||||
if (flags & ASC_F_ESI)
|
||||
cf.flags |= CANFD_ESI;
|
||||
} else {
|
||||
/* yes. The 'CANFD' format supports classic CAN content! */
|
||||
dlen = CAN_MAX_DLEN;
|
||||
if (flags & ASC_F_RTR) {
|
||||
cf.can_id |= CAN_RTR_FLAG;
|
||||
/* dlen is always 0 for classic CAN RTR frames
|
||||
but the DLC value is valid in RTR cases */
|
||||
cf.len = dlc;
|
||||
}
|
||||
}
|
||||
|
||||
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
|
||||
prframe(outfile, &tv, interface, &cf, dlen, extra_info);
|
||||
fflush(outfile);
|
||||
|
||||
/* No support for really strange CANFD ErrorFrames format m( */
|
||||
}
|
||||
|
||||
int get_date(struct timeval *tv, char *date) {
|
||||
|
||||
char ctmp[10];
|
||||
int itmp;
|
||||
|
||||
struct tm tms;
|
||||
unsigned int msecs = 0;
|
||||
|
||||
if (sscanf(date, "%9s %d %9s %9s %d", ctmp, &itmp, ctmp, ctmp, &itmp) == 5) {
|
||||
if (strcasestr(date, " pm ") != NULL) {
|
||||
/* assume EN/US date due to existing am/pm field */
|
||||
|
||||
if (!setlocale(LC_TIME, "en_US")) {
|
||||
@@ -136,29 +350,39 @@ int get_date(struct timeval *tv, char *date) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strptime(date, "%B %d %r %Y", &tms))
|
||||
return 1;
|
||||
if (!strptime(date, "%B %d %I:%M:%S %p %Y", &tms)) {
|
||||
/* The string might contain a milliseconds value which strptime()
|
||||
does not support. So we read the ms value into the year variable
|
||||
before parsing the real year value (hack) */
|
||||
if (!strptime(date, "%B %d %I:%M:%S.%Y %p %Y", &tms))
|
||||
return 1;
|
||||
sscanf(date, "%*s %*d %*d:%*d:%*d.%3u ", &msecs);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* assume DE date due to non existing am/pm field */
|
||||
|
||||
if (sscanf(date, "%9s %d %9s %d", ctmp, &itmp, ctmp, &itmp) != 4)
|
||||
return 1;
|
||||
|
||||
if (!setlocale(LC_TIME, "de_DE")) {
|
||||
fprintf(stderr, "Setting locale to 'de_DE' failed!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strptime(date, "%B %d %T %Y", &tms))
|
||||
return 1;
|
||||
if (!strptime(date, "%B %d %H:%M:%S %Y", &tms)) {
|
||||
/* The string might contain a milliseconds value which strptime()
|
||||
does not support. So we read the ms value into the year variable
|
||||
before parsing the real year value (hack) */
|
||||
if (!strptime(date, "%B %d %H:%M:%S.%Y %Y", &tms))
|
||||
return 1;
|
||||
sscanf(date, "%*s %*d %*d:%*d:%*d.%3u ", &msecs);
|
||||
}
|
||||
}
|
||||
|
||||
//printf("h %d m %d s %d d %d m %d y %d\n",
|
||||
//tms.tm_hour, tms.tm_min, tms.tm_sec,
|
||||
|
||||
//printf("h %d m %d s %d ms %03d d %d m %d y %d\n",
|
||||
//tms.tm_hour, tms.tm_min, tms.tm_sec, msecs,
|
||||
//tms.tm_mday, tms.tm_mon+1, tms.tm_year+1900);
|
||||
|
||||
tv->tv_sec = mktime(&tms);
|
||||
tv->tv_usec = msecs * 1000;
|
||||
|
||||
if (tv->tv_sec < 0)
|
||||
return 1;
|
||||
@@ -168,24 +392,17 @@ int get_date(struct timeval *tv, char *date) {
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char buf[100], tmp1[100], tmp2[100];
|
||||
char buf[BUFLEN], tmp1[BUFLEN], tmp2[BUFLEN];
|
||||
|
||||
FILE *infile = stdin;
|
||||
FILE *outfile = stdout;
|
||||
static int verbose;
|
||||
struct can_frame cf;
|
||||
static struct timeval tv; /* current frame timestamp */
|
||||
static struct timeval read_tv; /* frame timestamp from ASC file */
|
||||
static struct timeval tmp_tv; /* tmp frame timestamp from ASC file */
|
||||
static struct timeval date_tv; /* date of the ASC file */
|
||||
static int dplace; /* decimal place 4, 5 or 6 or uninitialized */
|
||||
static char base; /* 'd'ec or 'h'ex */
|
||||
static char timestamps; /* 'a'bsolute or 'r'elative */
|
||||
|
||||
int interface;
|
||||
char rtr;
|
||||
int dlc = 0;
|
||||
int data[8];
|
||||
int i, found, opt;
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt(argc, argv, "I:O:v?")) != -1) {
|
||||
switch (opt) {
|
||||
@@ -223,7 +440,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
|
||||
while (fgets(buf, 99, infile)) {
|
||||
while (fgets(buf, BUFLEN-1, infile)) {
|
||||
|
||||
if (!dplace) { /* the representation of a valid CAN frame not known */
|
||||
|
||||
@@ -258,87 +475,35 @@ int main(int argc, char **argv)
|
||||
gettimeofday(&date_tv, NULL);
|
||||
}
|
||||
if (verbose)
|
||||
printf("date %ld => %s", date_tv.tv_sec, ctime(&date_tv.tv_sec));
|
||||
printf("date %lu => %s", date_tv.tv_sec, ctime(&date_tv.tv_sec));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check for decimal places length in valid CAN frames */
|
||||
if (sscanf(buf, "%ld.%s %d ", &tv.tv_sec, tmp2, &i) == 3){
|
||||
dplace = strlen(tmp2);
|
||||
if (verbose)
|
||||
printf("decimal place %d, e.g. '%s'\n", dplace, tmp2);
|
||||
if (dplace < 4 || dplace > 6) {
|
||||
printf("invalid dplace %d (must be 4, 5 or 6)!\n", dplace);
|
||||
return 1;
|
||||
}
|
||||
} else
|
||||
if (sscanf(buf, "%lu.%s %s ", &tmp_tv.tv_sec, tmp2,
|
||||
tmp1) != 3)
|
||||
continue; /* dplace remains zero until first found CAN frame */
|
||||
}
|
||||
|
||||
dplace = strlen(tmp2);
|
||||
if (verbose)
|
||||
printf("decimal place %d, e.g. '%s'\n", dplace,
|
||||
tmp2);
|
||||
if (dplace < 4 || dplace > 6) {
|
||||
printf("invalid dplace %d (must be 4, 5 or 6)!\n",
|
||||
dplace);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* the representation of a valid CAN frame is known here */
|
||||
/* so try to get CAN frames and ErrorFrames and convert them */
|
||||
|
||||
/* 0.002367 1 390x Rx d 8 17 00 14 00 C0 00 08 00 */
|
||||
|
||||
found = 0; /* found valid CAN frame ? */
|
||||
|
||||
if (base == 'h') { /* check for CAN frames with hexadecimal values */
|
||||
|
||||
if (sscanf(buf, "%ld.%ld %d %s %*s %c %d %x %x %x %x %x %x %x %x",
|
||||
&read_tv.tv_sec, &read_tv.tv_usec, &interface,
|
||||
tmp1, &rtr, &dlc,
|
||||
&data[0], &data[1], &data[2], &data[3],
|
||||
&data[4], &data[5], &data[6], &data[7]
|
||||
) == dlc + 6 ) {
|
||||
|
||||
found = 1;
|
||||
get_can_id(&cf, tmp1, 16);
|
||||
}
|
||||
|
||||
} else { /* check for CAN frames with decimal values */
|
||||
|
||||
if (sscanf(buf, "%ld.%ld %d %s %*s %c %d %d %d %d %d %d %d %d %d",
|
||||
&read_tv.tv_sec, &read_tv.tv_usec, &interface,
|
||||
tmp1, &rtr, &dlc,
|
||||
&data[0], &data[1], &data[2], &data[3],
|
||||
&data[4], &data[5], &data[6], &data[7]
|
||||
) == dlc + 6 ) {
|
||||
|
||||
found = 1;
|
||||
get_can_id(&cf, tmp1, 10);
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
if (rtr == 'r')
|
||||
cf.can_id |= CAN_RTR_FLAG;
|
||||
|
||||
cf.can_dlc = dlc & 0x0FU;
|
||||
for (i=0; i<dlc; i++)
|
||||
cf.data[i] = data[i] & 0xFFU;
|
||||
|
||||
calc_tv(&tv, &read_tv, &date_tv, timestamps, dplace);
|
||||
prframe(outfile, &tv, interface, &cf);
|
||||
fflush(outfile);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check for ErrorFrames */
|
||||
if (sscanf(buf, "%ld.%ld %d %s",
|
||||
&read_tv.tv_sec, &read_tv.tv_usec,
|
||||
&interface, tmp1) == 4) {
|
||||
|
||||
if (!strncmp(tmp1, "ErrorFrame", strlen("ErrorFrame"))) {
|
||||
|
||||
memset(&cf, 0, sizeof(cf));
|
||||
/* do not know more than 'Error' */
|
||||
cf.can_id = (CAN_ERR_FLAG | CAN_ERR_BUSERROR);
|
||||
cf.can_dlc = CAN_ERR_DLC;
|
||||
|
||||
calc_tv(&tv, &read_tv, &date_tv, timestamps, dplace);
|
||||
prframe(outfile, &tv, interface, &cf);
|
||||
fflush(outfile);
|
||||
}
|
||||
/* check classic CAN format or the CANFD tag which can take both types */
|
||||
if (sscanf(buf, "%lu.%lu %s ", &tmp_tv.tv_sec, &tmp_tv.tv_usec, tmp1) == 3){
|
||||
if (!strncmp(tmp1, "CANFD", 5))
|
||||
eval_canfd(buf, &date_tv, timestamps, dplace, outfile);
|
||||
else
|
||||
eval_can(buf, &date_tv, timestamps, base, dplace, outfile);
|
||||
}
|
||||
}
|
||||
fclose(outfile);
|
||||
|
||||
+19
-15
@@ -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]* >
|
||||
@@ -107,20 +108,21 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/bcm.h>
|
||||
@@ -134,7 +136,7 @@ void childdied(int i)
|
||||
wait(NULL);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
int main(void)
|
||||
{
|
||||
|
||||
int sl, sa, sc;
|
||||
@@ -179,8 +181,12 @@ int main(int argc, char **argv)
|
||||
saddr.sin_port = htons(PORT);
|
||||
|
||||
while(bind(sl,(struct sockaddr*)&saddr, sizeof(saddr)) < 0) {
|
||||
struct timespec f = {
|
||||
.tv_nsec = 100 * 1000 * 1000,
|
||||
};
|
||||
|
||||
printf(".");fflush(NULL);
|
||||
usleep(100000);
|
||||
nanosleep(&f, NULL);
|
||||
}
|
||||
|
||||
if (listen(sl,3) != 0) {
|
||||
@@ -191,11 +197,9 @@ int main(int argc, char **argv)
|
||||
while (1) {
|
||||
sa = accept(sl,(struct sockaddr *)&clientaddr, &sin_size);
|
||||
if (sa > 0 ){
|
||||
|
||||
if (fork())
|
||||
close(sa);
|
||||
else
|
||||
if (!fork())
|
||||
break;
|
||||
close(sa);
|
||||
}
|
||||
else {
|
||||
if (errno != EINTR) {
|
||||
|
||||
+29
-18
@@ -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,13 +12,13 @@
|
||||
* 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>
|
||||
#include <getopt.h>
|
||||
#include <libgen.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
@@ -25,8 +26,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/can/netlink.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* imported from kernel */
|
||||
|
||||
@@ -131,17 +132,16 @@ static inline void *netdev_priv(const struct net_device *dev)
|
||||
|
||||
static void print_usage(char *cmd)
|
||||
{
|
||||
printf("%s - calculate CAN bit timing parameters.\n", cmd);
|
||||
printf("Usage: %s [options] [<CAN-contoller-name>]\n"
|
||||
"\tOptions:\n"
|
||||
"\t-q : don't print header line\n"
|
||||
"\t-l : list all support CAN controller names\n"
|
||||
"\t-b <bitrate> : bit-rate in bits/sec\n"
|
||||
"\t-s <samp_pt> : sample-point in one-tenth of a percent\n"
|
||||
"Options:\n"
|
||||
"\t-q don't print header line\n"
|
||||
"\t-l list all support CAN controller names\n"
|
||||
"\t-b <bitrate> bit-rate in bits/sec\n"
|
||||
"\t-s <samp_pt> sample-point in one-tenth of a percent\n"
|
||||
"\t or 0 for CIA recommended sample points\n"
|
||||
"\t-c <clock> : real CAN system clock in Hz\n",
|
||||
"\t-c <clock> real CAN system clock in Hz\n",
|
||||
cmd);
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void printf_btr_sja1000(struct can_bittiming *bt, bool hdr)
|
||||
@@ -444,7 +444,7 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
|
||||
unsigned int spt_nominal; /* nominal sample point */
|
||||
unsigned int best_tseg = 0; /* current best value for tseg */
|
||||
unsigned int best_brp = 0; /* current best value for brp */
|
||||
unsigned int brp, tsegall, tseg, tseg1, tseg2;
|
||||
unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0;
|
||||
u64 v64;
|
||||
|
||||
/* Use CiA recommended sample points */
|
||||
@@ -638,7 +638,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
const struct calc_bittiming_const *btc;
|
||||
|
||||
while ((opt = getopt(argc, argv, "b:c:lqs:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "b:c:lqs:?")) != -1) {
|
||||
switch (opt) {
|
||||
case 'b':
|
||||
bitrate_nominal = atoi(optarg);
|
||||
@@ -660,14 +660,22 @@ int main(int argc, char *argv[])
|
||||
spt_nominal = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case '?':
|
||||
print_usage(basename(argv[0]));
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
|
||||
default:
|
||||
print_usage(argv[0]);
|
||||
print_usage(basename(argv[0]));
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > optind + 1)
|
||||
if (argc > optind + 1) {
|
||||
print_usage(argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (argc == optind + 1)
|
||||
name = argv[optind];
|
||||
@@ -677,11 +685,14 @@ int main(int argc, char *argv[])
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (spt_nominal && (spt_nominal >= 1000 || spt_nominal < 100))
|
||||
if (spt_nominal && (spt_nominal >= 1000 || spt_nominal < 100)) {
|
||||
print_usage(argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(can_calc_consts); i++) {
|
||||
if (name && strcmp(can_calc_consts[i].bittiming_const.name, name))
|
||||
if (name &&
|
||||
strcmp(can_calc_consts[i].bittiming_const.name, name) != 0)
|
||||
continue;
|
||||
|
||||
found = true;
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
# can-j1939 kernel module installation #
|
||||
|
||||
|
||||
|
||||
### Problem
|
||||
|
||||
You already have **can0** or **vcan0** up and working, **can-utils** downloaded and compiled to **~/can/can-utils** and you can send and receive frames without problems. However, when you want to bring up **can-j1939** you get error like this:
|
||||
|
||||
```bash
|
||||
avra@vm-debian:~/can/can-utils$ sudo modprobe can-j1939
|
||||
modprobe: FATAL: Module can-j1939 not found in directory /lib/modules/5.7.0.0.bpo.2-amd64
|
||||
```
|
||||
|
||||
and also this:
|
||||
|
||||
```bash
|
||||
avra@vm-debian:~/can/can-utils$ testj1939
|
||||
testj1939: socket(j1939): Protocol not supported
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Solution
|
||||
|
||||
Above errors mean that **can-j1939** was not enabled in your kernel and you need to compile it manually. There are several ways to do it. Any Linux kernel since 5.4 has **can-j1939** module, but you will probably want to install fresher version, which leads to downloading kernel sources, enabling **can-j1939** module, recompiling kernel and installing it. I will be using Debian 10.5 x64 (buster testing) virtual machine.
|
||||
|
||||
|
||||
|
||||
#### 1. Download kernel source ####
|
||||
|
||||
We will download Debian patched kernel 5.8. First update your sources
|
||||
|
||||
```
|
||||
avra@vm-debian:~$ sudo apt update
|
||||
```
|
||||
|
||||
and then look at available Debian patched kernel source packages
|
||||
|
||||
```
|
||||
avra@vm-debian:~$ apt-cache search linux-source
|
||||
linux-source-4.19 - Linux kernel source for version 4.19 with Debian patches
|
||||
linux-source - Linux kernel source (meta-package)
|
||||
linux-source-5.4 - Linux kernel source for version 5.4 with Debian patches
|
||||
linux-source-5.5 - Linux kernel source for version 5.5 with Debian patches
|
||||
linux-source-5.6 - Linux kernel source for version 5.6 with Debian patches
|
||||
linux-source-5.7 - Linux kernel source for version 5.7 with Debian patches
|
||||
linux-source-5.8 - Linux kernel source for version 5.8 with Debian patches
|
||||
```
|
||||
|
||||
If kernel 5.8 does not show in your linux-sources list (it shows above in mine since I have already upgraded stock 4.19 kernel to backported 5.7), then you will need to add backports to your sources list. It is best to do it like this
|
||||
|
||||
```
|
||||
echo 'deb http://deb.debian.org/debian buster-backports main contrib' | sudo tee -a /etc/apt/sources.list.d/debian-backports.list
|
||||
```
|
||||
|
||||
Alternatively, or in case you have problems with installation of some packages, or you just want to have everything in a single list, here is what my **/etc/apt/sources.list** looks like (you will need to append at least last line to yours)
|
||||
|
||||
```
|
||||
deb http://security.debian.org/debian-security buster/updates main contrib
|
||||
deb-src http://security.debian.org/debian-security buster/updates main contrib
|
||||
|
||||
deb http://deb.debian.org/debian/ buster main contrib non-free
|
||||
deb-src http://deb.debian.org/debian/ buster main contrib non-free
|
||||
|
||||
deb http://deb.debian.org/debian buster-backports main contrib
|
||||
```
|
||||
|
||||
After adding backports in one way or another, try **sudo apt update** again, and after that **apt-cache search linux-source** should show kernel 5.8 in the list, so you can install it's source package
|
||||
|
||||
```
|
||||
sudo apt install linux-source-5.8
|
||||
```
|
||||
|
||||
and unpack it
|
||||
```
|
||||
avra@vm-debian:~$ cd /usr/src
|
||||
avra@vm-debian:/usr/src$ sudo tar -xaf linux-source-5.8.tar.xz
|
||||
avra@vm-debian:/usr/src$ cd linux-source-5.8
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 2. Add can-j1939 module to kernel ####
|
||||
|
||||
First we need some packages for **menuconfig**
|
||||
|
||||
```
|
||||
sudo apt-get install libncurses5 libncurses5-dev
|
||||
```
|
||||
|
||||
copy and use our old configuration to run **menuconfig**
|
||||
|
||||
```
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo cp /boot/config-$(uname -r) .config
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make menuconfig
|
||||
```
|
||||
|
||||
where we enable SAE J1939 kernel module as shown
|
||||
|
||||
```
|
||||
- Networking Support
|
||||
- Can bus subsystem support
|
||||
- <M> SAE J1939
|
||||
```
|
||||
|
||||
Now edit **/usr/src/linux-source-5.8/.config**, find CONFIG_SYSTEM_TRUSTED_KEYS, change it as following
|
||||
```
|
||||
CONFIG_SYSTEM_TRUSTED_KEYS=""
|
||||
```
|
||||
|
||||
and save the file.
|
||||
|
||||
|
||||
|
||||
#### 3. Compile and install kernel and modules
|
||||
|
||||
We will have to download necessary packages
|
||||
|
||||
```
|
||||
sudo apt install build-essential libssl-dev libelf-dev bison flex
|
||||
```
|
||||
|
||||
compile kernel (using threads to make it faster)
|
||||
|
||||
```
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make -j $(nproc)
|
||||
```
|
||||
|
||||
install
|
||||
|
||||
```
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make modules_install
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make install
|
||||
```
|
||||
|
||||
and update grub
|
||||
|
||||
```
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo update-grub
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo reboot
|
||||
```
|
||||
|
||||
Check if installation is correct with
|
||||
|
||||
```
|
||||
sudo modprobe can-j1939
|
||||
```
|
||||
|
||||
and if you get no error then you can enjoy **can-j1939**. If you get some error then you might check if this alternative command works:
|
||||
|
||||
```
|
||||
sudo insmod /lib/modules/5.8.10/kernel/net/can/j1939/can-j1939.ko
|
||||
```
|
||||
|
||||
If it does then all you need to do is
|
||||
|
||||
```
|
||||
sudo depmod -av
|
||||
```
|
||||
|
||||
reboot once, and **modprobe** command from the above should finally work.
|
||||
|
||||
|
||||
|
||||
#### 4. Install headers if needed
|
||||
|
||||
You might have a problem with headers not being updated. To check that open file **/usr/include/linux/can.h** with
|
||||
|
||||
```
|
||||
nano /usr/include/linux/can.h
|
||||
```
|
||||
|
||||
If in the struct **sockaddr_can** you don’t see **j1939**, then header files did not upgrade and you need to do it manually
|
||||
|
||||
```
|
||||
sudo cp /usr/src/linux-source-5.8/include/uapi/linux/can.h /usr/include/linux/can.h
|
||||
sudo cp /usr/src/linux-source-5.8/include/uapi/linux/can/j1939.h /usr/include/linux/can/
|
||||
```
|
||||
|
||||
That is the minimum for compiling some **J1939** C code, but you might want to upgrade other header files as well. That's up to you. Enjoy!
|
||||
+27
-45
@@ -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
|
||||
|
||||
@@ -44,7 +44,7 @@ You should have this output in terminal 1
|
||||
40 02300: 01 23
|
||||
|
||||
This means, from NAME 0, SA 40, PGN 02300 was received,
|
||||
with 2 databytes, *01* & *02*.
|
||||
with 2 databytes, *01* & *23*.
|
||||
|
||||
now emit this CAN message:
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
+24
-21
@@ -1,5 +1,6 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* canbusload.c
|
||||
* canbusload.c - monitor CAN bus load
|
||||
*
|
||||
* Copyright (c) 2002-2008 Volkswagen Group Electronic Research
|
||||
* All rights reserved.
|
||||
@@ -41,21 +42,21 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
#include <libgen.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
@@ -90,23 +91,25 @@ static char *prg;
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - monitor CAN bus load.\n", prg);
|
||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>+\n", prg);
|
||||
fprintf(stderr, " (use CTRL-C to terminate %s)\n\n", prg);
|
||||
fprintf(stderr, "Options: -t (show current time on the first line)\n");
|
||||
fprintf(stderr, " -c (colorize lines)\n");
|
||||
fprintf(stderr, " -b (show bargraph in %d%% resolution)\n", PERCENTRES);
|
||||
fprintf(stderr, " -r (redraw the terminal - similar to top)\n");
|
||||
fprintf(stderr, " -i (ignore bitstuffing in bandwidth calculation)\n");
|
||||
fprintf(stderr, " -e (exact calculation of stuffed bits)\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -t (show current time on the first line)\n");
|
||||
fprintf(stderr, " -c (colorize lines)\n");
|
||||
fprintf(stderr, " -b (show bargraph in %d%% resolution)\n", PERCENTRES);
|
||||
fprintf(stderr, " -r (redraw the terminal - similar to top)\n");
|
||||
fprintf(stderr, " -i (ignore bitstuffing in bandwidth calculation)\n");
|
||||
fprintf(stderr, " -e (exact calculation of stuffed bits)\n");
|
||||
fprintf(stderr, "\n");
|
||||
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");
|
||||
fprintf(stderr, "\nExample:\n");
|
||||
fprintf(stderr, "\nExamples:\n");
|
||||
fprintf(stderr, "\nuser$> canbusload can0@100000 can1@500000 can2@500000 can3@500000 -r -t -b -c\n\n");
|
||||
fprintf(stderr, "%s 2014-02-01 21:13:16 (worst case bitstuffing)\n", prg);
|
||||
fprintf(stderr, " can0@100000 805 74491 36656 74%% |XXXXXXXXXXXXXX......|\n");
|
||||
@@ -297,7 +300,7 @@ int main(int argc, char **argv)
|
||||
ptr = argv[optind+i];
|
||||
|
||||
nbytes = strlen(ptr);
|
||||
if (nbytes >= IFNAMSIZ+sizeof("@1000000")+1) {
|
||||
if (nbytes >= (int)(IFNAMSIZ+sizeof("@1000000")+1)) {
|
||||
printf("name of CAN device '%s' is too long!\n", ptr);
|
||||
return 1;
|
||||
}
|
||||
@@ -321,7 +324,7 @@ int main(int argc, char **argv)
|
||||
|
||||
nbytes = nptr - ptr; /* interface name is up the first '@' */
|
||||
|
||||
if (nbytes >= IFNAMSIZ) {
|
||||
if (nbytes >= (int)IFNAMSIZ) {
|
||||
printf("name of CAN device '%s' is too long!\n", ptr);
|
||||
return 1;
|
||||
}
|
||||
@@ -386,14 +389,14 @@ 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");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (nbytes < sizeof(struct can_frame)) {
|
||||
if (nbytes < (int)sizeof(struct can_frame)) {
|
||||
fprintf(stderr, "read: incomplete CAN frame\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* candump.c
|
||||
*
|
||||
@@ -41,23 +42,23 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
#include <libgen.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
@@ -115,21 +116,20 @@ static volatile int running = 1;
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - dump CAN bus traffic.\n", prg);
|
||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>+\n", prg);
|
||||
fprintf(stderr, " (use CTRL-C to terminate %s)\n\n", prg);
|
||||
fprintf(stderr, "Options: -t <type> (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -t <type> (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\n");
|
||||
fprintf(stderr, " -H (read hardware timestamps instead of system timestamps)\n");
|
||||
fprintf(stderr, " -c (increment color mode level)\n");
|
||||
fprintf(stderr, " -i (binary output - may exceed 80 chars/line)\n");
|
||||
fprintf(stderr, " -a (enable additional ASCII output)\n");
|
||||
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");
|
||||
@@ -139,22 +139,23 @@ void print_usage(char *prg)
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Up to %d CAN interfaces with optional filter sets can be specified\n", MAXSOCK);
|
||||
fprintf(stderr, "on the commandline in the form: <ifname>[,filter]*\n");
|
||||
fprintf(stderr, "\nComma separated filters can be specified for each given CAN interface:\n");
|
||||
fprintf(stderr, " <can_id>:<can_mask> (matches when <received_can_id> & mask == can_id & mask)\n");
|
||||
fprintf(stderr, " <can_id>~<can_mask> (matches when <received_can_id> & mask != can_id & mask)\n");
|
||||
fprintf(stderr, " #<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, "\nFilters:\n");
|
||||
fprintf(stderr, " Comma separated filters can be specified for each given CAN interface:\n");
|
||||
fprintf(stderr, " <can_id>:<can_mask>\n (matches when <received_can_id> & mask == can_id & mask)\n");
|
||||
fprintf(stderr, " <can_id>~<can_mask>\n (matches when <received_can_id> & mask != can_id & mask)\n");
|
||||
fprintf(stderr, " #<error_mask>\n (set error frame filter, see include/linux/can/error.h)\n");
|
||||
fprintf(stderr, " [j|J]\n (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,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, "%s -c -c -ta can0,123:7FF,400:700,#000000FF can2,400~7F0 can3 can8\n\n", prg);
|
||||
fprintf(stderr, "%s -l any,0~0,#FFFFFFFF\n (log only error frames but no(!) data frames)\n", prg);
|
||||
fprintf(stderr, "%s -l any,0:0,#FFFFFFFF\n (log error frames and also all data frames)\n", prg);
|
||||
fprintf(stderr, "%s vcan2,12345678:DFFFFFFF\n (match only for extended CAN ID 12345678)\n", prg);
|
||||
fprintf(stderr, "%s vcan2,123:7FF\n (matches CAN ID 123 - including EFF and RTR frames)\n", prg);
|
||||
fprintf(stderr, "%s vcan2,123:C00007FF\n (matches CAN ID 123 - only SFF and non-RTR frames)\n", prg);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
@@ -200,7 +201,7 @@ int idx2dindex(int ifidx, int socket) {
|
||||
if (ioctl(socket, SIOCGIFNAME, &ifr) < 0)
|
||||
perror("SIOCGIFNAME");
|
||||
|
||||
if (max_devname_len < strlen(ifr.ifr_name))
|
||||
if (max_devname_len < (int)strlen(ifr.ifr_name))
|
||||
max_devname_len = strlen(ifr.ifr_name);
|
||||
|
||||
strcpy(devname[i], ifr.ifr_name);
|
||||
@@ -216,8 +217,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 +255,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 +299,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;
|
||||
@@ -461,7 +417,7 @@ int main(int argc, char **argv)
|
||||
printf("using interface name '%s'.\n", ifr.ifr_name);
|
||||
#endif
|
||||
|
||||
if (strcmp(ANYDEV, ifr.ifr_name)) {
|
||||
if (strcmp(ANYDEV, ifr.ifr_name) != 0) {
|
||||
if (ioctl(s[i], SIOCGIFINDEX, &ifr) < 0) {
|
||||
perror("SIOCGIFINDEX");
|
||||
exit(1);
|
||||
@@ -502,12 +458,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 +572,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 +590,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) {
|
||||
@@ -668,6 +628,7 @@ int main(int argc, char **argv)
|
||||
if (FD_ISSET(s[i], &rdfs)) {
|
||||
|
||||
int idx;
|
||||
char *extra_info = "";
|
||||
|
||||
/* these settings may be modified by recvmsg() */
|
||||
iov.iov_len = sizeof(frame);
|
||||
@@ -698,20 +659,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);
|
||||
@@ -755,24 +702,33 @@ int main(int argc, char **argv)
|
||||
if (frame.can_id & CAN_EFF_FLAG)
|
||||
view |= CANLIB_VIEW_INDENT_SFF;
|
||||
|
||||
if (extra_msg_info) {
|
||||
if (msg.msg_flags & MSG_DONTROUTE)
|
||||
extra_info = " T";
|
||||
else
|
||||
extra_info = " R";
|
||||
}
|
||||
|
||||
if (log) {
|
||||
char buf[CL_CFSZ]; /* max length */
|
||||
|
||||
/* log CAN frame with absolute timestamp & device */
|
||||
sprint_canframe(buf, &frame, 0, maxdlen);
|
||||
fprintf(logfile, "(%010ld.%06ld) %*s %s\n",
|
||||
fprintf(logfile, "(%010lu.%06lu) %*s %s%s\n",
|
||||
tv.tv_sec, tv.tv_usec,
|
||||
max_devname_len, devname[idx], buf);
|
||||
max_devname_len, devname[idx], buf,
|
||||
extra_info);
|
||||
}
|
||||
|
||||
if (logfrmt) {
|
||||
if ((logfrmt) && (silent == SILENT_OFF)){
|
||||
char buf[CL_CFSZ]; /* max length */
|
||||
|
||||
/* print CAN frame in log file style to stdout */
|
||||
sprint_canframe(buf, &frame, 0, maxdlen);
|
||||
printf("(%010ld.%06ld) %*s %s\n",
|
||||
printf("(%010lu.%06lu) %*s %s%s\n",
|
||||
tv.tv_sec, tv.tv_usec,
|
||||
max_devname_len, devname[idx], buf);
|
||||
max_devname_len, devname[idx], buf,
|
||||
extra_info);
|
||||
goto out_fflush; /* no other output to stdout */
|
||||
}
|
||||
|
||||
@@ -789,7 +745,7 @@ int main(int argc, char **argv)
|
||||
switch (timestamp) {
|
||||
|
||||
case 'a': /* absolute with timestamp */
|
||||
printf("(%010ld.%06ld) ", tv.tv_sec, tv.tv_usec);
|
||||
printf("(%010lu.%06lu) ", tv.tv_sec, tv.tv_usec);
|
||||
break;
|
||||
|
||||
case 'A': /* absolute with date */
|
||||
@@ -799,7 +755,7 @@ int main(int argc, char **argv)
|
||||
|
||||
tm = *localtime(&tv.tv_sec);
|
||||
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
|
||||
printf("(%s.%06ld) ", timestring, tv.tv_usec);
|
||||
printf("(%s.%06lu) ", timestring, tv.tv_usec);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -816,7 +772,7 @@ int main(int argc, char **argv)
|
||||
diff.tv_sec--, diff.tv_usec += 1000000;
|
||||
if (diff.tv_sec < 0)
|
||||
diff.tv_sec = diff.tv_usec = 0;
|
||||
printf("(%03ld.%06ld) ", diff.tv_sec, diff.tv_usec);
|
||||
printf("(%03lu.%06lu) ", diff.tv_sec, diff.tv_usec);
|
||||
|
||||
if (timestamp == 'd')
|
||||
last_tv = tv; /* update for delta calculation */
|
||||
@@ -854,9 +810,6 @@ int main(int argc, char **argv)
|
||||
for (i=0; i<currmax; i++)
|
||||
close(s[i]);
|
||||
|
||||
if (bridge)
|
||||
close(bridge);
|
||||
|
||||
if (log)
|
||||
fclose(logfile);
|
||||
|
||||
|
||||
+169
-77
@@ -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
|
||||
@@ -17,23 +17,24 @@
|
||||
* Send feedback to <linux-can@vger.kernel.org>
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <libgen.h>
|
||||
#include <limits.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <libgen.h>
|
||||
#include <getopt.h>
|
||||
#include <time.h>
|
||||
#include <sched.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
@@ -47,71 +48,78 @@ static int running = 1;
|
||||
static int verbose;
|
||||
static int sockfd;
|
||||
static int test_loops;
|
||||
static int exit_sig;
|
||||
static int inflight_count = CAN_MSG_COUNT;
|
||||
|
||||
static void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"%s - Full-duplex test program (DUT and host part).\n"
|
||||
"Usage: %s [options] <can-interface>\n"
|
||||
"\n"
|
||||
"Options: -v (low verbosity)\n"
|
||||
"Options:\n"
|
||||
" -v (low verbosity)\n"
|
||||
" -vv (high verbosity)\n"
|
||||
" -g (generate messages)\n"
|
||||
" -l COUNT (test loop count)\n"
|
||||
" -f COUNT (number of frames in flight, default: %d)\n"
|
||||
"\n"
|
||||
"With the option '-g' CAN messages are generated and checked\n"
|
||||
"on <can-interface>, otherwise all messages received on the\n"
|
||||
"<can-interface> are sent back incrementing the CAN id and\n"
|
||||
"all data bytes. The program can be aborted with ^C.\n"
|
||||
"\n"
|
||||
"Example:\n"
|
||||
"\ton DUT : %s -v can0\n"
|
||||
"\ton Host: %s -g -v can2\n",
|
||||
prg, prg, prg);
|
||||
"Examples:\n"
|
||||
"\ton DUT:\n"
|
||||
"%s -v can0\n"
|
||||
"\ton Host:\n"
|
||||
"%s -g -v can2\n",
|
||||
prg, prg, CAN_MSG_COUNT, prg, prg);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void print_frame(struct can_frame *frame)
|
||||
static void print_frame(const 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", (uint8_t)(frame->data[i] + inc));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void print_compare(struct can_frame *exp, struct can_frame *rec)
|
||||
static void print_compare(const struct can_frame *exp, const 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]) {
|
||||
printf("Databyte %x mismatch !\n", i);
|
||||
if (rec->data[i] != (uint8_t)(exp->data[i] + inc)) {
|
||||
printf("Databyte %x mismatch!\n", i);
|
||||
print_compare(exp,
|
||||
rec);
|
||||
rec, inc);
|
||||
running = 0;
|
||||
}
|
||||
}
|
||||
@@ -149,6 +157,7 @@ static void signal_handler(int signo)
|
||||
{
|
||||
close(sockfd);
|
||||
running = 0;
|
||||
exit_sig = signo;
|
||||
}
|
||||
|
||||
static int recv_frame(struct can_frame *frame)
|
||||
@@ -172,29 +181,63 @@ static int send_frame(struct can_frame *frame)
|
||||
|
||||
while ((ret = send(sockfd, frame, sizeof(*frame), 0))
|
||||
!= sizeof(*frame)) {
|
||||
if (ret < 0) {
|
||||
if (errno != ENOBUFS) {
|
||||
perror("send failed");
|
||||
return -1;
|
||||
} else {
|
||||
if (verbose) {
|
||||
printf("N");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ret >= 0) {
|
||||
fprintf(stderr, "send returned %d", ret);
|
||||
return -1;
|
||||
}
|
||||
if (errno != ENOBUFS) {
|
||||
perror("send failed");
|
||||
return -1;
|
||||
}
|
||||
if (verbose) {
|
||||
printf("N");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_frame(const struct can_frame *frame)
|
||||
{
|
||||
int err = 0;
|
||||
int i;
|
||||
|
||||
if (frame->can_id != CAN_MSG_ID) {
|
||||
printf("unexpected Message ID 0x%04x!\n", frame->can_id);
|
||||
err = -1;
|
||||
}
|
||||
|
||||
if (frame->can_dlc != CAN_MSG_LEN) {
|
||||
printf("unexpected Message length %d!\n", frame->can_dlc);
|
||||
err = -1;
|
||||
}
|
||||
|
||||
for (i = 1; i < frame->can_dlc; i++) {
|
||||
if (frame->data[i] != (uint8_t)(frame->data[i-1] + 1)) {
|
||||
printf("Frame inconsistent!\n");
|
||||
print_frame(frame, 0);
|
||||
err = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void inc_frame(struct can_frame *frame)
|
||||
{
|
||||
int i;
|
||||
|
||||
frame->can_id++;
|
||||
for (i = 0; i < frame->can_dlc; i++)
|
||||
frame->data[i]++;
|
||||
}
|
||||
|
||||
static int can_echo_dut(void)
|
||||
{
|
||||
unsigned int frame_count = 0;
|
||||
struct can_frame frame;
|
||||
int i;
|
||||
|
||||
while (running) {
|
||||
if (recv_frame(&frame))
|
||||
@@ -203,19 +246,11 @@ static int can_echo_dut(void)
|
||||
if (verbose == 1) {
|
||||
echo_progress(frame.data[0]);
|
||||
} else if (verbose > 1) {
|
||||
printf("%04x: ", frame.can_id);
|
||||
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("\n");
|
||||
print_frame(&frame, 0);
|
||||
}
|
||||
frame.can_id++;
|
||||
for (i = 0; i < frame.can_dlc; i++)
|
||||
frame.data[i]++;
|
||||
|
||||
check_frame(&frame);
|
||||
inc_frame(&frame);
|
||||
if (send_frame(&frame))
|
||||
return -1;
|
||||
|
||||
@@ -234,29 +269,40 @@ static int can_echo_dut(void)
|
||||
|
||||
static int can_echo_gen(void)
|
||||
{
|
||||
struct can_frame tx_frames[CAN_MSG_COUNT];
|
||||
struct can_frame *tx_frames;
|
||||
int *recv_tx;
|
||||
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 err = 0;
|
||||
int i;
|
||||
|
||||
tx_frames = calloc(inflight_count, sizeof(* tx_frames));
|
||||
if (!tx_frames)
|
||||
return -1;
|
||||
|
||||
recv_tx = calloc(inflight_count, sizeof(* recv_tx));
|
||||
if (!recv_tx) {
|
||||
err = -1;
|
||||
goto out_free_tx_frames;
|
||||
}
|
||||
|
||||
while (running) {
|
||||
if (unprocessed < CAN_MSG_COUNT) {
|
||||
if (unprocessed < inflight_count) {
|
||||
/* 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]++;
|
||||
if (send_frame(&tx_frames[send_pos])) {
|
||||
err = -1;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
send_pos++;
|
||||
if (send_pos == CAN_MSG_COUNT)
|
||||
if (send_pos == inflight_count)
|
||||
send_pos = 0;
|
||||
unprocessed++;
|
||||
if (verbose == 1)
|
||||
@@ -268,29 +314,51 @@ static int can_echo_gen(void)
|
||||
else
|
||||
millisleep(1);
|
||||
} else {
|
||||
if (recv_frame(&rx_frame))
|
||||
return -1;
|
||||
if (recv_frame(&rx_frame)) {
|
||||
err = -1;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (verbose > 1)
|
||||
print_frame(&rx_frame);
|
||||
print_frame(&rx_frame, 0);
|
||||
|
||||
/* 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 == inflight_count)
|
||||
recv_tx_pos = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!recv_tx[recv_rx_pos]) {
|
||||
printf("RX before TX!\n");
|
||||
print_frame(&rx_frame, 0);
|
||||
running = 0;
|
||||
}
|
||||
/* compare with expected */
|
||||
compare_frame(&tx_frames[recv_pos], &rx_frame);
|
||||
compare_frame(&tx_frames[recv_rx_pos], &rx_frame, 1);
|
||||
recv_rx_pos++;
|
||||
if (recv_rx_pos == inflight_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--;
|
||||
}
|
||||
}
|
||||
|
||||
printf("\nTest messages sent and received: %d\n", loops);
|
||||
|
||||
return 0;
|
||||
out_free:
|
||||
free(recv_tx);
|
||||
out_free_tx_frames:
|
||||
free(tx_frames);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@@ -300,25 +368,30 @@ 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);
|
||||
signal(SIGINT, signal_handler);
|
||||
|
||||
while ((opt = getopt(argc, argv, "gl:v")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "f:gl:v?")) != -1) {
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
case 'f':
|
||||
inflight_count = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
test_loops = atoi(optarg);;
|
||||
test_loops = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
echo_gen = 1;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
default:
|
||||
print_usage(basename(argv[0]));
|
||||
break;
|
||||
@@ -337,8 +410,21 @@ 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);
|
||||
if (!addr.can_ifindex) {
|
||||
perror("if_nametoindex");
|
||||
close(sockfd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("bind");
|
||||
@@ -355,5 +441,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;
|
||||
}
|
||||
|
||||
+8
-6
@@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* canframelen.c
|
||||
*
|
||||
@@ -43,13 +44,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "canframelen.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "canframelen.h"
|
||||
|
||||
/**
|
||||
* Functions and types for CRC checks.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* canframelen.h
|
||||
*
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* cangen.c - CAN frames generator for testing purposes
|
||||
* cangen.c - CAN frames generator
|
||||
*
|
||||
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research
|
||||
* All rights reserved.
|
||||
@@ -41,30 +42,32 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <poll.h>
|
||||
#include <ctype.h>
|
||||
#include <libgen.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#define DEFAULT_GAP 200 /* ms */
|
||||
#define DEFAULT_BURST_COUNT 1
|
||||
|
||||
#define MODE_RANDOM 0
|
||||
#define MODE_INCREMENT 1
|
||||
@@ -77,17 +80,20 @@ static unsigned long long enobufs_count;
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "\n%s: generate CAN frames\n\n", prg);
|
||||
fprintf(stderr, "%s - CAN frames generator.\n\n", prg);
|
||||
fprintf(stderr, "Usage: %s [options] <CAN interface>\n", prg);
|
||||
fprintf(stderr, "Options: -g <ms> (gap in milli seconds "
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -g <ms> (gap in milli seconds "
|
||||
"- default: %d ms)\n", DEFAULT_GAP);
|
||||
fprintf(stderr, " -e (generate extended frame mode "
|
||||
"(EFF) CAN frames)\n");
|
||||
fprintf(stderr, " -f (generate CAN FD CAN frames)\n");
|
||||
fprintf(stderr, " -b (generate CAN FD CAN frames"
|
||||
" with bitrate switch (BRS))\n");
|
||||
fprintf(stderr, " -E (generate CAN FD CAN frames"
|
||||
" with error state (ESI))\n");
|
||||
fprintf(stderr, " -R (send RTR frame)\n");
|
||||
fprintf(stderr, " -m (mix -e -f -b -R frames)\n");
|
||||
fprintf(stderr, " -m (mix -e -f -b -E -R frames)\n");
|
||||
fprintf(stderr, " -I <mode> (CAN ID"
|
||||
" generation mode - see below)\n");
|
||||
fprintf(stderr, " -L <mode> (CAN data length code (dlc)"
|
||||
@@ -102,28 +108,30 @@ void print_usage(char *prg)
|
||||
" write() syscalls)\n");
|
||||
fprintf(stderr, " -x (disable local loopback of "
|
||||
"generated CAN frames)\n");
|
||||
fprintf(stderr, " -c (number of messages to send in burst, "
|
||||
"default 1)\n");
|
||||
fprintf(stderr, " -v (increment verbose level for "
|
||||
"printing sent CAN frames)\n\n");
|
||||
fprintf(stderr, "Generation modes:\n");
|
||||
fprintf(stderr, "'r' => random values (default)\n");
|
||||
fprintf(stderr, "'i' => increment values\n");
|
||||
fprintf(stderr, "<hexvalue> => fix value using <hexvalue>\n\n");
|
||||
fprintf(stderr, " 'r' => random values (default)\n");
|
||||
fprintf(stderr, " 'i' => increment values\n");
|
||||
fprintf(stderr, " <hexvalue> => fix value using <hexvalue>\n\n");
|
||||
fprintf(stderr, "When incrementing the CAN data the data length code "
|
||||
"minimum is set to 1.\n");
|
||||
fprintf(stderr, "CAN IDs and data content are given and expected in hexadecimal values.\n\n");
|
||||
fprintf(stderr, "Examples:\n");
|
||||
fprintf(stderr, "%s vcan0 -g 4 -I 42A -L 1 -D i -v -v ", prg);
|
||||
fprintf(stderr, "(fixed CAN ID and length, inc. data)\n");
|
||||
fprintf(stderr, "%s vcan0 -e -L i -v -v -v ", prg);
|
||||
fprintf(stderr, "(generate EFF frames, incr. length)\n");
|
||||
fprintf(stderr, "%s vcan0 -D 11223344DEADBEEF -L 8 ", prg);
|
||||
fprintf(stderr, "(fixed CAN data payload and length)\n");
|
||||
fprintf(stderr, "%s vcan0 -g 0 -i -x ", prg);
|
||||
fprintf(stderr, "(full load test ignoring -ENOBUFS)\n");
|
||||
fprintf(stderr, "%s vcan0 -g 0 -p 10 -x ", prg);
|
||||
fprintf(stderr, "(full load test with polling, 10ms timeout)\n");
|
||||
fprintf(stderr, "%s vcan0 ", prg);
|
||||
fprintf(stderr, "(my favourite default :)\n\n");
|
||||
fprintf(stderr, "%s vcan0 -g 4 -I 42A -L 1 -D i -v -v\n", prg);
|
||||
fprintf(stderr, "\t(fixed CAN ID and length, inc. data)\n");
|
||||
fprintf(stderr, "%s vcan0 -e -L i -v -v -v\n", prg);
|
||||
fprintf(stderr, "\t(generate EFF frames, incr. length)\n");
|
||||
fprintf(stderr, "%s vcan0 -D 11223344DEADBEEF -L 8\n", prg);
|
||||
fprintf(stderr, "\t(fixed CAN data payload and length)\n");
|
||||
fprintf(stderr, "%s vcan0 -g 0 -i -x\n", prg);
|
||||
fprintf(stderr, "\t(full load test ignoring -ENOBUFS)\n");
|
||||
fprintf(stderr, "%s vcan0 -g 0 -p 10 -x\n", prg);
|
||||
fprintf(stderr, "\t(full load test with polling, 10ms timeout)\n");
|
||||
fprintf(stderr, "%s vcan0\n", prg);
|
||||
fprintf(stderr, "\t(my favourite default :)\n\n");
|
||||
}
|
||||
|
||||
void sigterm(int signo)
|
||||
@@ -134,11 +142,13 @@ void sigterm(int signo)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
double gap = DEFAULT_GAP;
|
||||
unsigned long burst_count = DEFAULT_BURST_COUNT;
|
||||
unsigned long polltimeout = 0;
|
||||
unsigned char ignore_enobufs = 0;
|
||||
unsigned char extended = 0;
|
||||
unsigned char canfd = 0;
|
||||
unsigned char brs = 0;
|
||||
unsigned char esi = 0;
|
||||
unsigned char mix = 0;
|
||||
unsigned char id_mode = MODE_RANDOM;
|
||||
unsigned char data_mode = MODE_RANDOM;
|
||||
@@ -147,6 +157,7 @@ int main(int argc, char **argv)
|
||||
unsigned char verbose = 0;
|
||||
unsigned char rtr_frame = 0;
|
||||
int count = 0;
|
||||
unsigned long burst_sent_count = 0;
|
||||
int mtu, maxdlen;
|
||||
uint64_t incdata = 0;
|
||||
int incdlc = 0;
|
||||
@@ -174,7 +185,7 @@ int main(int argc, char **argv)
|
||||
signal(SIGHUP, sigterm);
|
||||
signal(SIGINT, sigterm);
|
||||
|
||||
while ((opt = getopt(argc, argv, "ig:ebfmI:L:D:xp:n:vRh?")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "ig:ebEfmI:L:D:xp:n:c:vRh?")) != -1) {
|
||||
switch (opt) {
|
||||
|
||||
case 'i':
|
||||
@@ -198,6 +209,11 @@ int main(int argc, char **argv)
|
||||
canfd = 1;
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
esi = 1; /* error state indicator implies CAN FD */
|
||||
canfd = 1;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
mix = 1;
|
||||
canfd = 1; /* to switch the socket into CAN FD mode */
|
||||
@@ -239,6 +255,10 @@ int main(int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
burst_count = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
@@ -278,7 +298,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
ts.tv_sec = gap / 1000;
|
||||
ts.tv_nsec = (long)(((long long)(gap * 1000000)) % 1000000000ll);
|
||||
ts.tv_nsec = (long)(((long long)(gap * 1000000)) % 1000000000LL);
|
||||
|
||||
/* recognize obviously missing commandline option */
|
||||
if (id_mode == MODE_FIX && frame.can_id > 0x7FF && !extended) {
|
||||
@@ -368,6 +388,8 @@ int main(int argc, char **argv)
|
||||
maxdlen = CANFD_MAX_DLEN;
|
||||
if (brs)
|
||||
frame.flags |= CANFD_BRS;
|
||||
if (esi)
|
||||
frame.flags |= CANFD_ESI;
|
||||
} else {
|
||||
mtu = CAN_MTU;
|
||||
maxdlen = CAN_MAX_DLEN;
|
||||
@@ -447,8 +469,8 @@ resend:
|
||||
if (poll(&fds, 1, polltimeout) < 0) {
|
||||
perror("poll");
|
||||
return 1;
|
||||
} else
|
||||
goto resend;
|
||||
}
|
||||
goto resend;
|
||||
} else
|
||||
enobufs_count++;
|
||||
|
||||
@@ -457,10 +479,14 @@ resend:
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (gap) /* gap == 0 => performance test :-] */
|
||||
burst_sent_count++;
|
||||
if (gap && burst_sent_count >= burst_count) /* gap == 0 => performance test :-] */
|
||||
if (nanosleep(&ts, NULL))
|
||||
return 1;
|
||||
|
||||
if (burst_sent_count >= burst_count)
|
||||
burst_sent_count = 0;
|
||||
|
||||
if (id_mode == MODE_INCREMENT)
|
||||
frame.can_id++;
|
||||
|
||||
@@ -489,8 +515,10 @@ resend:
|
||||
i = random();
|
||||
extended = i&1;
|
||||
canfd = i&2;
|
||||
if (canfd)
|
||||
if (canfd) {
|
||||
brs = i&4;
|
||||
esi = i&8;
|
||||
}
|
||||
rtr_frame = ((i&24) == 24); /* reduce RTR frames to 1/4 */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* cangw.c - manage PF_CAN netlink gateway
|
||||
*
|
||||
@@ -41,17 +42,17 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <libgen.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <libgen.h>
|
||||
#include <linux/can/gw.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/can/gw.h>
|
||||
#include <net/if.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
enum {
|
||||
UNSPEC,
|
||||
@@ -67,13 +68,19 @@ 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))
|
||||
|
||||
/* some netlink helpers stolen from iproute2 package */
|
||||
#define NLMSG_TAIL(nmsg) \
|
||||
((struct rtattr *)(((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
|
||||
((struct rtattr *)(((char *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
|
||||
|
||||
int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
|
||||
int alen)
|
||||
@@ -81,7 +88,7 @@ int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
|
||||
int len = RTA_LENGTH(alen);
|
||||
struct rtattr *rta;
|
||||
|
||||
if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
|
||||
if ((int)(NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len)) > maxlen) {
|
||||
fprintf(stderr, "addattr_l: message exceeded bound of %d\n",
|
||||
maxlen);
|
||||
return -1;
|
||||
@@ -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(" ");
|
||||
@@ -186,45 +222,60 @@ void print_cs_crc8(struct cgw_csum_crc8 *cs_crc8)
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - manage PF_CAN netlink gateway.\n", prg);
|
||||
fprintf(stderr, "\nUsage: %s [options]\n\n", prg);
|
||||
fprintf(stderr, "Commands: -A (add a new rule)\n");
|
||||
fprintf(stderr, " -D (delete a rule)\n");
|
||||
fprintf(stderr, " -F (flush / delete all rules)\n");
|
||||
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, " -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, " -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");
|
||||
fprintf(stderr, "Commands:\n");
|
||||
fprintf(stderr, " -A (add a new rule)\n");
|
||||
fprintf(stderr, " -D (delete a rule)\n");
|
||||
fprintf(stderr, " -F (flush / delete all rules)\n");
|
||||
fprintf(stderr, " -L (list all rules)\n");
|
||||
fprintf(stderr, "Mandatory:\n");
|
||||
fprintf(stderr, " -s <src_dev> (source netdevice)\n");
|
||||
fprintf(stderr, " -d <dst_dev> (destination netdevice)\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -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 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");
|
||||
fprintf(stderr, "\nValues are given and expected in hexadecimal values. Leading 0s can be omitted.\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "<filter> is a <value><mask> CAN identifier filter\n");
|
||||
fprintf(stderr, " <can_id>:<can_mask> (matches when <received_can_id> & mask == can_id & mask)\n");
|
||||
fprintf(stderr, " <can_id>~<can_mask> (matches when <received_can_id> & mask != can_id & mask)\n");
|
||||
fprintf(stderr, "<filter> is a <value><mask> CAN identifier filter:\n");
|
||||
fprintf(stderr, " <can_id>:<can_mask> (matches when <received_can_id> & mask == can_id & mask)\n");
|
||||
fprintf(stderr, " <can_id>~<can_mask> (matches when <received_can_id> & mask != can_id & mask)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "<mod> is a CAN frame modification instruction consisting of\n");
|
||||
fprintf(stderr, "<instruction>:<can_frame-elements>:<can_id>.<can_dlc>.<can_data>\n");
|
||||
fprintf(stderr, " - <instruction> is one of 'AND' 'OR' 'XOR' 'SET'\n");
|
||||
fprintf(stderr, " - <can_frame-elements> is _one_ or _more_ of 'I'dentifier 'L'ength 'D'ata\n");
|
||||
fprintf(stderr, " - <can_id> is an u32 value containing the CAN Identifier\n");
|
||||
fprintf(stderr, " - <can_dlc> is an u8 value containing the data length code (0 .. 8)\n");
|
||||
fprintf(stderr, " - <can_data> is always eight(!) u8 values containing the CAN frames data\n");
|
||||
fprintf(stderr, " <instruction> is one of 'AND' 'OR' 'XOR' 'SET'\n");
|
||||
fprintf(stderr, " <can_frame-elements> is _one_ or _more_ of 'I'dentifier 'L'ength 'D'ata\n");
|
||||
fprintf(stderr, " <can_id> is an u32 value containing the CAN Identifier\n");
|
||||
fprintf(stderr, " <can_dlc> is an u8 value containing the data length code (0 .. 8)\n");
|
||||
fprintf(stderr, " <can_data> is always eight(!) u8 values containing the CAN frames data\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "<MOD> is a CAN FD frame modification instruction consisting of\n");
|
||||
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");
|
||||
fprintf(stderr, "%s -A -s can0 -d vcan3 -e -f 123:C00007FF -m SET:IL:333.4.1122334455667788\n", prg);
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Supported CRC 8 profiles:\n");
|
||||
fprintf(stderr, "Profile '%d' (1U8) - add one additional u8 value\n", CGW_CRC8PRF_1U8);
|
||||
fprintf(stderr, "Profile '%d' (16U8) - add u8 value from table[16] indexed by (data[1] & 0xF)\n", CGW_CRC8PRF_16U8);
|
||||
fprintf(stderr, "Profile '%d' (SFFID_XOR) - add u8 value (can_id & 0xFF) ^ (can_id >> 8 & 0xFF)\n", CGW_CRC8PRF_SFFID_XOR);
|
||||
fprintf(stderr, " Profile '%d' (1U8) add one additional u8 value\n", CGW_CRC8PRF_1U8);
|
||||
fprintf(stderr, " Profile '%d' (16U8) add u8 value from table[16] indexed by (data[1] & 0xF)\n", CGW_CRC8PRF_16U8);
|
||||
fprintf(stderr, " Profile '%d' (SFFID_XOR) add u8 value (can_id & 0xFF) ^ (can_id >> 8 & 0xFF)\n", CGW_CRC8PRF_SFFID_XOR);
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Examples:\n");
|
||||
fprintf(stderr, "%s -A -s can0 -d vcan3 -e -f 123:C00007FF -m SET:IL:333.4.1122334455667788\n", prg);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
@@ -244,14 +295,14 @@ int parse_crc8_profile(char *optarg, struct cgw_csum_crc8 *crc8)
|
||||
int ret = 1;
|
||||
char *ptr;
|
||||
|
||||
if (sscanf(optarg, "%hhd:", &crc8->profile) != 1)
|
||||
if (sscanf(optarg, "%hhu:", &crc8->profile) != 1)
|
||||
return ret;
|
||||
|
||||
switch (crc8->profile) {
|
||||
|
||||
case CGW_CRC8PRF_1U8:
|
||||
|
||||
if (sscanf(optarg, "%hhd:%2hhx", &crc8->profile, &crc8->profile_data[0]) == 2)
|
||||
if (sscanf(optarg, "%hhu:%2hhx", &crc8->profile, &crc8->profile_data[0]) == 2)
|
||||
ret = 0;
|
||||
|
||||
break;
|
||||
@@ -281,7 +332,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 +382,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 +538,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 +579,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 +619,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 +690,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 */
|
||||
@@ -565,19 +706,19 @@ int main(int argc, char **argv)
|
||||
struct can_filter filter;
|
||||
struct sockaddr_nl nladdr;
|
||||
|
||||
struct cgw_csum_xor cs_xor;
|
||||
struct cgw_csum_crc8 cs_crc8;
|
||||
struct cgw_csum_xor cs_xor = { 0 };
|
||||
struct cgw_csum_crc8 cs_crc8 = { 0 };
|
||||
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 +749,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;
|
||||
@@ -625,7 +770,7 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
if (sscanf(optarg, "%hhd", &limit_hops) != 1 || !(limit_hops)) {
|
||||
if (sscanf(optarg, "%hhu", &limit_hops) != 1 || !(limit_hops)) {
|
||||
printf("Bad hop limit definition '%s'.\n", optarg);
|
||||
exit(1);
|
||||
}
|
||||
@@ -685,6 +830,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 +862,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 +949,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;
|
||||
|
||||
+28
-23
@@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* canlogserver.c
|
||||
*
|
||||
@@ -41,28 +42,29 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
#include <libgen.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
@@ -87,7 +89,8 @@ void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>+\n", prg);
|
||||
fprintf(stderr, " (use CTRL-C to terminate %s)\n\n", prg);
|
||||
fprintf(stderr, "Options: -m <mask> (ID filter mask. Default 0x00000000) *\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -m <mask> (ID filter mask. Default 0x00000000) *\n");
|
||||
fprintf(stderr, " -v <value> (ID filter value. Default 0x00000000) *\n");
|
||||
fprintf(stderr, " -i <0|1> (invert the specified ID filter) *\n");
|
||||
fprintf(stderr, " -e <emask> (mask for error frames)\n");
|
||||
@@ -137,7 +140,7 @@ int idx2dindex(int ifidx, int socket)
|
||||
if (ioctl(socket, SIOCGIFNAME, &ifr) < 0)
|
||||
perror("SIOCGIFNAME");
|
||||
|
||||
if (max_devname_len < strlen(ifr.ifr_name))
|
||||
if (max_devname_len < (int)strlen(ifr.ifr_name))
|
||||
max_devname_len = strlen(ifr.ifr_name);
|
||||
|
||||
strcpy(devname[i], ifr.ifr_name);
|
||||
@@ -278,8 +281,12 @@ int main(int argc, char **argv)
|
||||
inaddr.sin_port = htons(port);
|
||||
|
||||
while(bind(socki, (struct sockaddr*)&inaddr, sizeof(inaddr)) < 0) {
|
||||
struct timespec f = {
|
||||
.tv_nsec = 100 * 1000 * 1000,
|
||||
};
|
||||
|
||||
printf(".");fflush(NULL);
|
||||
usleep(100000);
|
||||
nanosleep(&f, NULL);
|
||||
}
|
||||
|
||||
if (listen(socki, 3) != 0) {
|
||||
@@ -293,15 +300,14 @@ int main(int argc, char **argv)
|
||||
//printf("accepted\n");
|
||||
if (!fork())
|
||||
break;
|
||||
else
|
||||
close(accsocket);
|
||||
close(accsocket);
|
||||
}
|
||||
else if (errno != EINTR) {
|
||||
perror("accept");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (i=0; i<currmax; i++) {
|
||||
|
||||
#ifdef DEBUG
|
||||
@@ -350,15 +356,14 @@ int main(int argc, char **argv)
|
||||
|
||||
addr.can_family = AF_CAN;
|
||||
|
||||
if (strcmp(ANYDEV, argv[optind+i])) {
|
||||
if (strcmp(ANYDEV, argv[optind + i]) != 0) {
|
||||
strcpy(ifr.ifr_name, argv[optind+i]);
|
||||
if (ioctl(s[i], SIOCGIFINDEX, &ifr) < 0) {
|
||||
perror("SIOCGIFINDEX");
|
||||
exit(1);
|
||||
}
|
||||
addr.can_ifindex = ifr.ifr_ifindex;
|
||||
}
|
||||
else
|
||||
} else
|
||||
addr.can_ifindex = 0; /* any can interface */
|
||||
|
||||
if (bind(s[i], (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
@@ -407,7 +412,7 @@ int main(int argc, char **argv)
|
||||
|
||||
idx = idx2dindex(addr.can_ifindex, s[i]);
|
||||
|
||||
sprintf(temp, "(%ld.%06ld) %*s ",
|
||||
sprintf(temp, "(%lu.%06lu) %*s ",
|
||||
tv.tv_sec, tv.tv_usec, max_devname_len, devname[idx]);
|
||||
sprint_canframe(temp+strlen(temp), &frame, 0, maxdlen);
|
||||
strcat(temp, "\n");
|
||||
@@ -419,7 +424,7 @@ int main(int argc, char **argv)
|
||||
|
||||
#if 0
|
||||
/* print CAN frame in log file style to stdout */
|
||||
printf("(%ld.%06ld) ", tv.tv_sec, tv.tv_usec);
|
||||
printf("(%lu.%06lu) ", tv.tv_sec, tv.tv_usec);
|
||||
printf("%*s ", max_devname_len, devname[idx]);
|
||||
fprint_canframe(stdout, &frame, "\n", 0, maxdlen);
|
||||
#endif
|
||||
|
||||
+38
-35
@@ -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
|
||||
*
|
||||
@@ -41,19 +42,19 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <libgen.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
@@ -76,30 +77,32 @@ extern int optind, opterr, optopt;
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - replay a compact CAN frame logfile to CAN devices.\n", prg);
|
||||
fprintf(stderr, "\nUsage: %s <options> [interface assignment]*\n\n", prg);
|
||||
fprintf(stderr, "Options: -I <infile> (default stdin)\n");
|
||||
fprintf(stderr, " -l <num> "
|
||||
"(process input file <num> times)\n"
|
||||
" "
|
||||
"(Use 'i' for infinite loop - default: %d)\n", DEFAULT_LOOPS);
|
||||
fprintf(stderr, " -t (ignore timestamps: "
|
||||
"send frames immediately)\n");
|
||||
fprintf(stderr, " -g <ms> (gap in milli "
|
||||
"seconds - default: %d ms)\n", DEFAULT_GAP);
|
||||
fprintf(stderr, " -s <s> (skip gaps in "
|
||||
"timestamps > 's' seconds)\n");
|
||||
fprintf(stderr, " -x (disable local "
|
||||
"loopback of sent CAN frames)\n");
|
||||
fprintf(stderr, " -v (verbose: print "
|
||||
"sent CAN frames)\n\n");
|
||||
fprintf(stderr, "Interface assignment: 0..n assignments like "
|
||||
"<write-if>=<log-if>\n");
|
||||
fprintf(stderr, "e.g. vcan2=can0 ( send frames received from can0 on "
|
||||
"vcan2 )\n");
|
||||
fprintf(stderr, "extra hook: stdout=can0 ( print logfile line marked with can0 on "
|
||||
"stdout )\n");
|
||||
fprintf(stderr, "No assignments => send frames to the interface(s) they "
|
||||
"had been received from.\n\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -I <infile> (default stdin)\n");
|
||||
fprintf(stderr, " -l <num> "
|
||||
"(process input file <num> times)\n"
|
||||
" "
|
||||
"(Use 'i' for infinite loop - default: %d)\n", DEFAULT_LOOPS);
|
||||
fprintf(stderr, " -t (ignore timestamps: "
|
||||
"send frames immediately)\n");
|
||||
fprintf(stderr, " -g <ms> (gap in milli "
|
||||
"seconds - default: %d ms)\n", DEFAULT_GAP);
|
||||
fprintf(stderr, " -s <s> (skip gaps in "
|
||||
"timestamps > 's' seconds)\n");
|
||||
fprintf(stderr, " -x (disable local "
|
||||
"loopback of sent CAN frames)\n");
|
||||
fprintf(stderr, " -v (verbose: print "
|
||||
"sent CAN frames)\n\n");
|
||||
fprintf(stderr, "Interface assignment:\n");
|
||||
fprintf(stderr, " 0..n assignments like <write-if>=<log-if>\n\n");
|
||||
fprintf(stderr, " e.g. vcan2=can0 (send frames received from can0 on "
|
||||
"vcan2)\n");
|
||||
fprintf(stderr, " extra hook: stdout=can0 (print logfile line marked with can0 on "
|
||||
"stdout)\n");
|
||||
fprintf(stderr, " No assignments => send frames to the interface(s) they "
|
||||
"had been received from\n\n");
|
||||
fprintf(stderr, "Lines in the logfile not beginning with '(' (start of "
|
||||
"timestamp) are ignored.\n\n");
|
||||
}
|
||||
@@ -212,7 +215,7 @@ int add_assignment(char *mode, int socket, char *txname, char *rxname,
|
||||
}
|
||||
strcpy(asgn[i].rxif, rxname);
|
||||
|
||||
if (strcmp(txname, "stdout")) {
|
||||
if (strcmp(txname, "stdout") != 0) {
|
||||
strcpy(ifr.ifr_name, txname);
|
||||
if (ioctl(socket, SIOCGIFINDEX, &ifr) < 0) {
|
||||
perror("SIOCGIFINDEX");
|
||||
@@ -348,7 +351,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");
|
||||
@@ -356,7 +359,7 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
strcpy(buf, argv[optind+i]);
|
||||
for (j=0; j<BUFSZ; j++) { /* find '=' in assignment */
|
||||
for (j=0; j<(int)BUFSZ; j++) { /* find '=' in assignment */
|
||||
if (buf[j] == '=')
|
||||
break;
|
||||
}
|
||||
@@ -392,7 +395,7 @@ int main(int argc, char **argv)
|
||||
|
||||
eof = 0;
|
||||
|
||||
if (sscanf(buf, "(%ld.%ld) %s %s", &log_tv.tv_sec, &log_tv.tv_usec,
|
||||
if (sscanf(buf, "(%lu.%lu) %s %s", &log_tv.tv_sec, &log_tv.tv_usec,
|
||||
device, ascframe) != 4) {
|
||||
fprintf(stderr, "incorrect line format in logfile\n");
|
||||
return 1;
|
||||
@@ -471,7 +474,7 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
|
||||
if (sscanf(buf, "(%ld.%ld) %s %s", &log_tv.tv_sec, &log_tv.tv_usec,
|
||||
if (sscanf(buf, "(%lu.%lu) %s %s", &log_tv.tv_sec, &log_tv.tv_usec,
|
||||
device, ascframe) != 4) {
|
||||
fprintf(stderr, "incorrect line format in logfile\n");
|
||||
return 1;
|
||||
@@ -492,7 +495,7 @@ int main(int argc, char **argv)
|
||||
/* test for logfile timestamps jumping backwards OR */
|
||||
/* if the user likes to skip long gaps in the timestamps */
|
||||
if ((last_log_tv.tv_sec > log_tv.tv_sec) ||
|
||||
(skipgap && labs(last_log_tv.tv_sec - log_tv.tv_sec) > skipgap))
|
||||
(skipgap && labs(last_log_tv.tv_sec - log_tv.tv_sec) > (long)skipgap))
|
||||
create_diff_tv(&today_tv, &diff_tv, &log_tv);
|
||||
|
||||
last_log_tv = log_tv;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* 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
|
||||
* cansend.c - send CAN-frames via CAN_RAW sockets
|
||||
*
|
||||
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research
|
||||
* All rights reserved.
|
||||
@@ -55,6 +56,29 @@
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - send CAN-frames via CAN_RAW sockets.\n", prg);
|
||||
fprintf(stderr, "\nUsage: %s <device> <can_frame>.\n", prg);
|
||||
fprintf(stderr, "\n<can_frame>:\n");
|
||||
fprintf(stderr, " <can_id>#{data} for 'classic' CAN 2.0 data frames\n");
|
||||
fprintf(stderr, " <can_id>#R{len} for 'classic' CAN 2.0 data frames\n");
|
||||
fprintf(stderr, " <can_id>##<flags>{data} for CAN FD frames\n\n");
|
||||
fprintf(stderr, "<can_id>:\n"
|
||||
" 3 (SFF) or 8 (EFF) hex chars\n");
|
||||
fprintf(stderr, "{data}:\n"
|
||||
" 0..8 (0..64 CAN FD) ASCII hex-values (optionally separated by '.')\n");
|
||||
fprintf(stderr, "{len}:\n"
|
||||
" an optional 0..8 value as RTR frames can contain a valid dlc field\n");
|
||||
fprintf(stderr, "<flags>:\n"
|
||||
" a single ASCII Hex value (0 .. F) which defines canfd_frame.flags\n\n");
|
||||
fprintf(stderr, "Examples:\n");
|
||||
fprintf(stderr, " 5A1#11.2233.44556677.88 / 123#DEADBEEF / 5AA# / 123##1 / 213##311223344 /\n"
|
||||
" 1F334455#1122334455667788 / 123#R / 00000123#R3\n\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int s; /* can raw socket */
|
||||
@@ -67,24 +91,15 @@ int main(int argc, char **argv)
|
||||
|
||||
/* check command line options */
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Usage: %s <device> <can_frame>.\n", argv[0]);
|
||||
print_usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* parse CAN frame */
|
||||
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>##<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, "<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, "\nWrong CAN-frame format!\n\n");
|
||||
print_usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -102,10 +117,11 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.can_family = AF_CAN;
|
||||
addr.can_ifindex = ifr.ifr_ifindex;
|
||||
|
||||
if (required_mtu > CAN_MTU) {
|
||||
if (required_mtu > (int)CAN_MTU) {
|
||||
|
||||
/* check if the frame fits into the CAN netdevice */
|
||||
if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
|
||||
|
||||
+367
@@ -0,0 +1,367 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
// Copyright (c) 2007, 2008, 2009, 2010, 2014, 2015, 2019 Pengutronix,
|
||||
// Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
// Copyright (c) 2005 Pengutronix,
|
||||
// Sascha Hauer <kernel@pengutronix.de>
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <libgen.h>
|
||||
#include <limits.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
|
||||
#define CAN_ID_DEFAULT (2)
|
||||
|
||||
extern int optind, opterr, optopt;
|
||||
|
||||
static int s = -1;
|
||||
static bool running = true;
|
||||
static bool infinite = true;
|
||||
static unsigned int drop_until_quit;
|
||||
static unsigned int drop_count;
|
||||
static bool use_poll = false;
|
||||
|
||||
static unsigned int loopcount = 1;
|
||||
static int verbose;
|
||||
|
||||
static struct can_frame frame = {
|
||||
.can_dlc = 1,
|
||||
};
|
||||
static struct can_filter filter[] = {
|
||||
{ .can_id = CAN_ID_DEFAULT, },
|
||||
};
|
||||
|
||||
static void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [<can-interface>] [Options]\n"
|
||||
"\n"
|
||||
"cansequence sends CAN messages with a rising sequence number as payload.\n"
|
||||
"When the -r option is given, cansequence expects to receive these messages\n"
|
||||
"and prints an error message if a wrong sequence number is encountered.\n"
|
||||
"The main purpose of this program is to test the reliability of CAN links.\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -e, --extended send extended frame\n"
|
||||
" -i, --identifier=ID CAN Identifier (default = %u)\n"
|
||||
" --loop=COUNT send message COUNT times\n"
|
||||
" -p, --poll use poll(2) to wait for buffer space while sending\n"
|
||||
" -q, --quit <num> quit if <num> wrong sequences are encountered\n"
|
||||
" -r, --receive work as receiver\n"
|
||||
" -v, --verbose be verbose (twice to be even more verbose\n"
|
||||
" -h, --help this help\n"
|
||||
" --version print version information and exit\n",
|
||||
prg, CAN_ID_DEFAULT);
|
||||
}
|
||||
|
||||
static void sig_handler(int signo)
|
||||
{
|
||||
running = false;
|
||||
}
|
||||
|
||||
|
||||
static void do_receive()
|
||||
{
|
||||
uint8_t ctrlmsg[CMSG_SPACE(sizeof(struct timeval)) + CMSG_SPACE(sizeof(__u32))];
|
||||
struct iovec iov = {
|
||||
.iov_base = &frame,
|
||||
};
|
||||
struct msghdr msg = {
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = &ctrlmsg,
|
||||
};
|
||||
const int dropmonitor_on = 1;
|
||||
bool sequence_init = true;
|
||||
unsigned int sequence_wrap = 0;
|
||||
uint32_t sequence_mask = 0xff;
|
||||
uint32_t sequence_rx = 0;
|
||||
uint32_t sequence_delta = 0;
|
||||
uint32_t sequence = 0;
|
||||
unsigned int overflow_old = 0;
|
||||
can_err_mask_t err_mask = CAN_ERR_MASK;
|
||||
|
||||
if (setsockopt(s, SOL_SOCKET, SO_RXQ_OVFL,
|
||||
&dropmonitor_on, sizeof(dropmonitor_on)) < 0) {
|
||||
perror("setsockopt() SO_RXQ_OVFL not supported by your Linux Kernel");
|
||||
}
|
||||
|
||||
/* enable recv. of error messages */
|
||||
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &err_mask, sizeof(err_mask))) {
|
||||
perror("setsockopt()");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* enable recv. now */
|
||||
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, filter, sizeof(filter))) {
|
||||
perror("setsockopt()");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
while ((infinite || loopcount--) && running) {
|
||||
ssize_t nbytes;
|
||||
|
||||
msg.msg_iov[0].iov_len = sizeof(frame);
|
||||
msg.msg_controllen = sizeof(ctrlmsg);
|
||||
msg.msg_flags = 0;
|
||||
|
||||
nbytes = recvmsg(s, &msg, 0);
|
||||
if (nbytes < 0) {
|
||||
perror("read()");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (frame.can_id & CAN_ERR_FLAG) {
|
||||
fprintf(stderr,
|
||||
"sequence CNT: %6u, ERRORFRAME %7x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
sequence, frame.can_id,
|
||||
frame.data[0], frame.data[1], frame.data[2], frame.data[3],
|
||||
frame.data[4], frame.data[5], frame.data[6], frame.data[7]);
|
||||
continue;
|
||||
}
|
||||
|
||||
sequence_rx = frame.data[0];
|
||||
|
||||
if (sequence_init) {
|
||||
sequence_init = false;
|
||||
sequence = sequence_rx;
|
||||
}
|
||||
|
||||
sequence_delta = (sequence_rx - sequence) & sequence_mask;
|
||||
if (sequence_delta) {
|
||||
struct cmsghdr *cmsg;
|
||||
uint32_t overflow = 0;
|
||||
uint32_t overflow_delta;
|
||||
|
||||
drop_count++;
|
||||
|
||||
for (cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg && (cmsg->cmsg_level == SOL_SOCKET);
|
||||
cmsg = CMSG_NXTHDR(&msg,cmsg)) {
|
||||
if (cmsg->cmsg_type == SO_RXQ_OVFL) {
|
||||
memcpy(&overflow, CMSG_DATA(cmsg), sizeof(overflow));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
overflow_delta = overflow - overflow_old;
|
||||
|
||||
fprintf(stderr,
|
||||
"sequence CNT: %6u, RX: %6u expected: %3u missing: %4u skt overfl d: %4u a: %4u delta: %3u incident: %u\n",
|
||||
sequence, sequence_rx,
|
||||
sequence & sequence_mask, sequence_delta,
|
||||
overflow_delta, overflow,
|
||||
sequence_delta - overflow_delta,
|
||||
drop_count);
|
||||
|
||||
if (drop_count == drop_until_quit)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
sequence = sequence_rx;
|
||||
overflow_old = overflow;
|
||||
} else if (verbose > 1) {
|
||||
printf("sequence CNT: %6u, RX: %6u\n", sequence, sequence_rx);
|
||||
}
|
||||
|
||||
sequence++;
|
||||
if (verbose && !(sequence & sequence_mask))
|
||||
printf("sequence wrap around (%d)\n", sequence_wrap++);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void do_send()
|
||||
{
|
||||
unsigned int seq_wrap = 0;
|
||||
uint8_t sequence = 0;
|
||||
|
||||
while ((infinite || loopcount--) && running) {
|
||||
ssize_t len;
|
||||
|
||||
if (verbose > 1)
|
||||
printf("sending frame. sequence number: %d\n", sequence);
|
||||
|
||||
again:
|
||||
len = write(s, &frame, sizeof(frame));
|
||||
if (len == -1) {
|
||||
switch (errno) {
|
||||
case ENOBUFS: {
|
||||
int err;
|
||||
struct pollfd fds[] = {
|
||||
{
|
||||
.fd = s,
|
||||
.events = POLLOUT,
|
||||
},
|
||||
};
|
||||
|
||||
if (!use_poll) {
|
||||
perror("write");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
err = poll(fds, 1, 1000);
|
||||
if (err == -1 && errno != -EINTR) {
|
||||
perror("poll()");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
case EINTR: /* fallthrough */
|
||||
goto again;
|
||||
default:
|
||||
perror("write");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
frame.data[0]++;
|
||||
sequence++;
|
||||
|
||||
if (verbose && !sequence)
|
||||
printf("sequence wrap around (%d)\n", seq_wrap++);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct sigaction act = {
|
||||
.sa_handler = sig_handler,
|
||||
};
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_can addr;
|
||||
char *interface = "can0";
|
||||
int family = PF_CAN, type = SOCK_RAW, proto = CAN_RAW;
|
||||
int extended = 0;
|
||||
int receive = 0;
|
||||
int opt;
|
||||
|
||||
sigaction(SIGINT, &act, NULL);
|
||||
sigaction(SIGTERM, &act, NULL);
|
||||
sigaction(SIGHUP, &act, NULL);
|
||||
|
||||
struct option long_options[] = {
|
||||
{ "extended", no_argument, 0, 'e' },
|
||||
{ "identifier", required_argument, 0, 'i' },
|
||||
{ "loop", required_argument, 0, 'l' },
|
||||
{ "poll", no_argument, 0, 'p' },
|
||||
{ "quit", optional_argument, 0, 'q' },
|
||||
{ "receive", no_argument, 0, 'r' },
|
||||
{ "verbose", no_argument, 0, 'v' },
|
||||
{ "help", no_argument, 0, 'h' },
|
||||
{ 0, 0, 0, 0},
|
||||
};
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "ei:pq::rvh", long_options, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'e':
|
||||
extended = true;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
filter->can_id = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
receive = true;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
if (optarg) {
|
||||
loopcount = strtoul(optarg, NULL, 0);
|
||||
infinite = false;
|
||||
} else {
|
||||
infinite = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
use_poll = true;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
if (optarg)
|
||||
drop_until_quit = strtoul(optarg, NULL, 0);
|
||||
else
|
||||
drop_until_quit = 1;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
print_usage(basename(argv[0]));
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
|
||||
default:
|
||||
print_usage(basename(argv[0]));
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argv[optind] != NULL)
|
||||
interface = argv[optind];
|
||||
|
||||
if (extended) {
|
||||
filter->can_mask = CAN_EFF_MASK;
|
||||
filter->can_id &= CAN_EFF_MASK;
|
||||
filter->can_id |= CAN_EFF_FLAG;
|
||||
} else {
|
||||
filter->can_mask = CAN_SFF_MASK;
|
||||
filter->can_id &= CAN_SFF_MASK;
|
||||
}
|
||||
frame.can_id = filter->can_id;
|
||||
filter->can_mask |= CAN_EFF_FLAG;
|
||||
|
||||
printf("interface = %s, family = %d, type = %d, proto = %d\n",
|
||||
interface, family, type, proto);
|
||||
|
||||
s = socket(family, type, proto);
|
||||
if (s < 0) {
|
||||
perror("socket()");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
addr.can_family = family;
|
||||
strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
|
||||
if (ioctl(s, SIOCGIFINDEX, &ifr)) {
|
||||
perror("ioctl()");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
addr.can_ifindex = ifr.ifr_ifindex;
|
||||
|
||||
/* first don't recv. any msgs */
|
||||
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0)) {
|
||||
perror("setsockopt()");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("bind()");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (receive)
|
||||
do_receive();
|
||||
else
|
||||
do_send();
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
+393
-297
File diff suppressed because it is too large
Load Diff
@@ -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()
|
||||
@@ -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
@@ -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,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,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
@@ -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;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* SPDX-License-Identifier: ((GPL-2.0-only WITH Linux-syscall-note) OR BSD-3-Clause) */
|
||||
/*
|
||||
* linux/can/isotp.h
|
||||
*
|
||||
* Definitions for isotp CAN sockets
|
||||
* Definitions for isotp CAN sockets (ISO 15765-2:2016)
|
||||
*
|
||||
* Author: Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
|
||||
* Copyright (c) 2008 Volkswagen Group Electronic Research
|
||||
* Copyright (c) 2020 Volkswagen Group Electronic Research
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -39,13 +39,12 @@
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* Send feedback to <linux-can@vger.kernel.org>
|
||||
*/
|
||||
|
||||
#ifndef CAN_ISOTP_H
|
||||
#define CAN_ISOTP_H
|
||||
#ifndef _UAPI_CAN_ISOTP_H
|
||||
#define _UAPI_CAN_ISOTP_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/can.h>
|
||||
|
||||
#define SOL_CAN_ISOTP (SOL_CAN_BASE + CAN_ISOTP)
|
||||
@@ -123,7 +122,6 @@ struct can_isotp_ll_options {
|
||||
/* by the CAN netdriver configuration */
|
||||
};
|
||||
|
||||
|
||||
/* flags for isotp behaviour */
|
||||
|
||||
#define CAN_ISOTP_LISTEN_MODE 0x001 /* listen only (do not send FC) */
|
||||
@@ -136,6 +134,7 @@ struct can_isotp_ll_options {
|
||||
#define CAN_ISOTP_FORCE_TXSTMIN 0x080 /* ignore stmin from received FC */
|
||||
#define CAN_ISOTP_FORCE_RXSTMIN 0x100 /* ignore CFs depending on rx stmin */
|
||||
#define CAN_ISOTP_RX_EXT_ADDR 0x200 /* different rx extended addressing */
|
||||
#define CAN_ISOTP_WAIT_TX_DONE 0x400 /* wait for tx completion */
|
||||
|
||||
|
||||
/* default values */
|
||||
@@ -161,7 +160,6 @@ struct can_isotp_ll_options {
|
||||
* these default settings can be changed via sockopts.
|
||||
* For that reason the STmin value is intentionally _not_ checked for
|
||||
* consistency and copied directly into the flow control (FC) frame.
|
||||
*
|
||||
*/
|
||||
|
||||
#endif
|
||||
#endif /* !_UAPI_CAN_ISOTP_H */
|
||||
|
||||
@@ -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() */
|
||||
|
||||
@@ -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,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
|
||||
*
|
||||
@@ -49,6 +49,9 @@
|
||||
#include <linux/can.h>
|
||||
|
||||
#define SOL_CAN_RAW (SOL_CAN_BASE + CAN_RAW)
|
||||
enum {
|
||||
SCM_CAN_RAW_ERRQUEUE = 1,
|
||||
};
|
||||
|
||||
/* for socket options affecting the socket (not the global system) */
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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) && \
|
||||
(int)((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 */
|
||||
+195
-61
@@ -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
|
||||
*
|
||||
@@ -41,20 +42,23 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
#include <strings.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
#include <linux/sockios.h>
|
||||
|
||||
#include "terminal.h"
|
||||
|
||||
#define NO_CAN_ID 0xFFFFFFFFU
|
||||
@@ -65,17 +69,130 @@ const int canfd_on = 1;
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>\n", prg);
|
||||
fprintf(stderr, "Options: -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> (extended addressing mode. Use 'any' for all addresses)\n");
|
||||
fprintf(stderr, " -X <addr> (extended addressing mode (rx addr). Use 'any' for all)\n");
|
||||
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, "Options:\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> (extended addressing mode. Use 'any' for all addresses)\n");
|
||||
fprintf(stderr, " -X <addr> (extended addressing mode (rx addr). Use 'any' for all)\n");
|
||||
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 \n");
|
||||
fprintf(stderr, "message.\n\n");
|
||||
fprintf(stderr, "Flags:\n");
|
||||
fprintf(stderr, " [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 +210,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 +222,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 +270,10 @@ int main(int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
uds_output = 1;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
@@ -213,65 +336,66 @@ int main(int argc, char **argv)
|
||||
if (nbytes < 0) {
|
||||
perror("read");
|
||||
return 1;
|
||||
} else if (nbytes != CAN_MTU && nbytes != CANFD_MTU) {
|
||||
}
|
||||
if (nbytes != CAN_MTU && nbytes != CANFD_MTU) {
|
||||
fprintf(stderr, "read: incomplete CAN frame %zu %d\n", sizeof(frame), nbytes);
|
||||
return 1;
|
||||
} else {
|
||||
}
|
||||
if (frame.can_id == src && ext && !extany &&
|
||||
extaddr != frame.data[0])
|
||||
continue;
|
||||
|
||||
if (frame.can_id == src && ext && !extany && extaddr != frame.data[0])
|
||||
continue;
|
||||
if (frame.can_id == dst && rx_ext && !rx_extany &&
|
||||
rx_extaddr != frame.data[0])
|
||||
continue;
|
||||
|
||||
if (frame.can_id == dst && rx_ext && !rx_extany && rx_extaddr != frame.data[0])
|
||||
continue;
|
||||
if (color)
|
||||
printf("%s", (frame.can_id == src) ? FGRED : FGBLUE);
|
||||
|
||||
if (color)
|
||||
printf("%s", (frame.can_id == src)? FGRED:FGBLUE);
|
||||
if (timestamp) {
|
||||
ioctl(s, SIOCGSTAMP, &tv);
|
||||
|
||||
if (timestamp) {
|
||||
ioctl(s, SIOCGSTAMP, &tv);
|
||||
|
||||
|
||||
switch (timestamp) {
|
||||
|
||||
case 'a': /* absolute with timestamp */
|
||||
printf("(%ld.%06ld) ", tv.tv_sec, tv.tv_usec);
|
||||
break;
|
||||
|
||||
case 'A': /* absolute with date */
|
||||
{
|
||||
struct tm tm;
|
||||
char timestring[25];
|
||||
|
||||
tm = *localtime(&tv.tv_sec);
|
||||
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
|
||||
printf("(%s.%06ld) ", timestring, tv.tv_usec);
|
||||
}
|
||||
switch (timestamp) {
|
||||
case 'a': /* absolute with timestamp */
|
||||
printf("(%lu.%06lu) ", tv.tv_sec, tv.tv_usec);
|
||||
break;
|
||||
|
||||
case 'd': /* delta */
|
||||
case 'z': /* starting with zero */
|
||||
{
|
||||
struct timeval diff;
|
||||
case 'A': /* absolute with date */
|
||||
{
|
||||
struct tm tm;
|
||||
char timestring[25];
|
||||
|
||||
if (last_tv.tv_sec == 0) /* first init */
|
||||
last_tv = tv;
|
||||
diff.tv_sec = tv.tv_sec - last_tv.tv_sec;
|
||||
diff.tv_usec = tv.tv_usec - last_tv.tv_usec;
|
||||
if (diff.tv_usec < 0)
|
||||
diff.tv_sec--, diff.tv_usec += 1000000;
|
||||
if (diff.tv_sec < 0)
|
||||
diff.tv_sec = diff.tv_usec = 0;
|
||||
printf("(%ld.%06ld) ", diff.tv_sec, diff.tv_usec);
|
||||
tm = *localtime(&tv.tv_sec);
|
||||
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S",
|
||||
&tm);
|
||||
printf("(%s.%06lu) ", timestring, tv.tv_usec);
|
||||
} break;
|
||||
|
||||
if (timestamp == 'd')
|
||||
last_tv = tv; /* update for delta calculation */
|
||||
}
|
||||
case 'd': /* delta */
|
||||
case 'z': /* starting with zero */
|
||||
{
|
||||
struct timeval diff;
|
||||
|
||||
if (last_tv.tv_sec == 0) /* first init */
|
||||
last_tv = tv;
|
||||
diff.tv_sec = tv.tv_sec - last_tv.tv_sec;
|
||||
diff.tv_usec = tv.tv_usec - last_tv.tv_usec;
|
||||
if (diff.tv_usec < 0)
|
||||
diff.tv_sec--, diff.tv_usec += 1000000;
|
||||
if (diff.tv_sec < 0)
|
||||
diff.tv_sec = diff.tv_usec = 0;
|
||||
printf("(%lu.%06lu) ", diff.tv_sec,
|
||||
diff.tv_usec);
|
||||
|
||||
if (timestamp == 'd')
|
||||
last_tv =
|
||||
tv; /* update for delta calculation */
|
||||
} break;
|
||||
|
||||
default: /* no timestamp output */
|
||||
break;
|
||||
|
||||
default: /* no timestamp output */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (frame.can_id & CAN_EFF_FLAG)
|
||||
printf(" %s %8X", argv[optind], frame.can_id & CAN_EFF_MASK);
|
||||
@@ -288,9 +412,10 @@ int main(int argc, char **argv)
|
||||
|
||||
datidx = 0;
|
||||
n_pci = frame.data[ext];
|
||||
|
||||
|
||||
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 +426,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,13 +488,21 @@ 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)
|
||||
printf("%s", ATTRESET);
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
close(s);
|
||||
|
||||
+32
-27
@@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* isotpperf.c - ISO15765-2 protocol performance visualisation
|
||||
*
|
||||
@@ -41,21 +42,22 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <libgen.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#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 */
|
||||
@@ -63,11 +65,13 @@
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - ISO15765-2 protocol performance visualisation.\n", prg);
|
||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>\n", prg);
|
||||
fprintf(stderr, "Options: -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> (extended addressing mode)\n");
|
||||
fprintf(stderr, " -X <addr> (extended addressing mode (rx addr))\n");
|
||||
fprintf(stderr, "Options:\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> (extended addressing mode)\n");
|
||||
fprintf(stderr, " -X <addr> (extended addressing mode (rx addr))\n");
|
||||
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
@@ -219,19 +223,21 @@ int main(int argc, char **argv)
|
||||
ret = nbytes;
|
||||
running = 0;
|
||||
continue;
|
||||
} else if (nbytes != CAN_MTU && nbytes != CANFD_MTU) {
|
||||
}
|
||||
if (nbytes != CAN_MTU && nbytes != CANFD_MTU) {
|
||||
fprintf(stderr, "read: incomplete CAN frame %zu %d\n", sizeof(frame), nbytes);
|
||||
ret = nbytes;
|
||||
running = 0;
|
||||
continue;
|
||||
} else {
|
||||
if (rcvlen) {
|
||||
/* make sure to process only the detected PDU CAN frame type */
|
||||
if (canfd_on && (nbytes != CANFD_MTU))
|
||||
continue;
|
||||
if (!canfd_on && (nbytes != CAN_MTU))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (rcvlen) {
|
||||
/* make sure to process only the detected PDU CAN frame type */
|
||||
if (canfd_on && (nbytes != CANFD_MTU))
|
||||
continue;
|
||||
if (!canfd_on && (nbytes != CAN_MTU))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check extended address if provided */
|
||||
if (ext && extaddr != frame.data[0])
|
||||
@@ -245,13 +251,13 @@ int main(int argc, char **argv)
|
||||
|
||||
n_pci = frame.data[rx_ext];
|
||||
/* check flow control PCI only */
|
||||
if ((n_pci & 0xF0) == 0x30) {
|
||||
bs = frame.data[rx_ext+1];
|
||||
stmin = frame.data[rx_ext+2];
|
||||
} else
|
||||
if ((n_pci & 0xF0) != 0x30)
|
||||
continue;
|
||||
|
||||
bs = frame.data[rx_ext + 1];
|
||||
stmin = frame.data[rx_ext + 2];
|
||||
}
|
||||
|
||||
|
||||
/* data content starts and index datidx */
|
||||
datidx = 0;
|
||||
|
||||
@@ -351,7 +357,7 @@ int main(int argc, char **argv)
|
||||
if (rcvlen) {
|
||||
if (rcvlen > fflen)
|
||||
rcvlen = fflen;
|
||||
|
||||
|
||||
percent = (rcvlen * 100 / fflen);
|
||||
printf("\r %3lu%% ", percent);
|
||||
|
||||
@@ -361,7 +367,7 @@ int main(int argc, char **argv)
|
||||
percent = 100;
|
||||
|
||||
for (i=0; i < NUMBAR; i++){
|
||||
if (i < percent/PERCENTRES)
|
||||
if (i < (int)(percent/PERCENTRES))
|
||||
printf("X");
|
||||
else
|
||||
printf(".");
|
||||
@@ -393,7 +399,7 @@ int main(int argc, char **argv)
|
||||
|
||||
/* check devisor to be not zero */
|
||||
if (diff_tv.tv_sec * 1000 + diff_tv.tv_usec / 1000){
|
||||
printf("%ld.%06lds ", diff_tv.tv_sec, diff_tv.tv_usec);
|
||||
printf("%lu.%06lus ", diff_tv.tv_sec, diff_tv.tv_usec);
|
||||
printf("=> %lu byte/s", (fflen * 1000) /
|
||||
(diff_tv.tv_sec * 1000 + diff_tv.tv_usec / 1000));
|
||||
} else
|
||||
@@ -404,7 +410,6 @@ int main(int argc, char **argv)
|
||||
fflen = rcvlen = 0;
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
close(s);
|
||||
|
||||
+17
-15
@@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* isotprecv.c
|
||||
*
|
||||
@@ -41,16 +42,16 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/isotp.h>
|
||||
@@ -61,17 +62,18 @@
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>\n", prg);
|
||||
fprintf(stderr, "Options: -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");
|
||||
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
|
||||
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
|
||||
fprintf(stderr, " -b <bs> (blocksize. 0 = off)\n");
|
||||
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 <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
|
||||
fprintf(stderr, "Options:\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");
|
||||
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
|
||||
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
|
||||
fprintf(stderr, " -b <bs> (blocksize. 0 = off)\n");
|
||||
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 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");
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
+20
-13
@@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* isotpsend.c
|
||||
*
|
||||
@@ -41,16 +42,16 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/isotp.h>
|
||||
@@ -61,15 +62,17 @@
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>\n", prg);
|
||||
fprintf(stderr, "Options: -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
|
||||
fprintf(stderr, "Options:\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");
|
||||
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
|
||||
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
|
||||
fprintf(stderr, " -t <time ns> (frame transmit time (N_As) in nanosecs)\n");
|
||||
fprintf(stderr, " -f <time ns> (ignore FC and force local tx stmin value in nanosecs)\n");
|
||||
fprintf(stderr, " -D <len> (send a fixed PDU with len bytes - no STDIN data)\n");
|
||||
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
|
||||
fprintf(stderr, " -x <addr>[:<rxaddr>] (extended addressing / opt. separate rxaddr)\n");
|
||||
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
|
||||
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
|
||||
fprintf(stderr, " -t <time ns> (frame transmit time (N_As) in nanosecs)\n");
|
||||
fprintf(stderr, " -f <time ns> (ignore FC and force local tx stmin value in nanosecs)\n");
|
||||
fprintf(stderr, " -D <len> (send a fixed PDU with len bytes - no STDIN data)\n");
|
||||
fprintf(stderr, " -b (block until the PDU transmission is completed)\n");
|
||||
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
|
||||
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
|
||||
fprintf(stderr, "The pdu data is expected on STDIN in space separated ASCII hex values.\n");
|
||||
fprintf(stderr, "\n");
|
||||
@@ -91,7 +94,7 @@ int main(int argc, char **argv)
|
||||
|
||||
addr.can_addr.tp.tx_id = addr.can_addr.tp.rx_id = NO_CAN_ID;
|
||||
|
||||
while ((opt = getopt(argc, argv, "s:d:x:p:P:t:f:D:L:?")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "s:d:x:p:P:t:f:D:bL:?")) != -1) {
|
||||
switch (opt) {
|
||||
case 's':
|
||||
addr.can_addr.tp.tx_id = strtoul(optarg, (char **)NULL, 16);
|
||||
@@ -174,6 +177,10 @@ int main(int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
opts.flags |= CAN_ISOTP_WAIT_TX_DONE;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
if (sscanf(optarg, "%hhu:%hhu:%hhu",
|
||||
&llopts.mtu,
|
||||
|
||||
+36
-31
@@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* isotpserver.c
|
||||
*
|
||||
@@ -56,21 +57,22 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <libgen.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/isotp.h>
|
||||
@@ -99,28 +101,29 @@ void childdied(int i)
|
||||
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, "Options:\n");
|
||||
fprintf(stderr, "ip addressing:\n");
|
||||
fprintf(stderr, " -l <port> * (local port for the server)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "ip adressing:\n");
|
||||
fprintf(stderr, " * -l <port> (local port for the server)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "isotp adressing:\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");
|
||||
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\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");
|
||||
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "padding:\n");
|
||||
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
|
||||
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
|
||||
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
|
||||
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "rx path: (config, which is sent to the sender / data source)\n");
|
||||
fprintf(stderr, " -b <bs> (blocksize. 0 = off)\n");
|
||||
fprintf(stderr, " -m <val> (STmin in ms/ns. See spec.)\n");
|
||||
fprintf(stderr, " -w <num> (max. wait frame transmissions)\n");
|
||||
fprintf(stderr, "rx path:\n (config, which is sent to the sender / data source)\n");
|
||||
fprintf(stderr, " -b <bs> (blocksize. 0 = off)\n");
|
||||
fprintf(stderr, " -m <val> (STmin in ms/ns. See spec.)\n");
|
||||
fprintf(stderr, " -w <num> (max. wait frame transmissions)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "tx path: (config, which changes local tx settings)\n");
|
||||
fprintf(stderr, " -t <time ns> (transmit time in nanosecs)\n");
|
||||
fprintf(stderr, "tx path:\n (config, which changes local tx settings)\n");
|
||||
fprintf(stderr, " -t <time ns> (transmit time in nanosecs)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "(* = mandatory option)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "All values except for '-l' and '-t' are expected in hexadecimal values.\n");
|
||||
fprintf(stderr, "\n");
|
||||
@@ -297,9 +300,13 @@ int main(int argc, char **argv)
|
||||
saddr.sin_port = htons(local_port);
|
||||
|
||||
while(bind(sl,(struct sockaddr*)&saddr, sizeof(saddr)) < 0) {
|
||||
struct timespec f = {
|
||||
.tv_nsec = 100 * 1000 * 1000,
|
||||
};
|
||||
|
||||
printf(".");
|
||||
fflush(NULL);
|
||||
usleep(100000);
|
||||
nanosleep(&f, NULL);
|
||||
}
|
||||
|
||||
if (listen(sl, 3) != 0) {
|
||||
@@ -310,11 +317,9 @@ int main(int argc, char **argv)
|
||||
while (1) {
|
||||
sa = accept(sl,(struct sockaddr *)&clientaddr, &sin_size);
|
||||
if (sa > 0 ){
|
||||
|
||||
if (fork())
|
||||
close(sa);
|
||||
else
|
||||
if (!fork())
|
||||
break;
|
||||
close(sa);
|
||||
}
|
||||
else {
|
||||
if (errno != EINTR) {
|
||||
|
||||
+80
-40
@@ -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
|
||||
*
|
||||
@@ -41,21 +42,23 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "terminal.h"
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/isotp.h>
|
||||
#include "terminal.h"
|
||||
#include <linux/sockios.h>
|
||||
|
||||
#define NO_CAN_ID 0xFFFFFFFFU
|
||||
|
||||
@@ -66,13 +69,15 @@
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>\n", prg);
|
||||
fprintf(stderr, "Options: -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> (extended addressing mode)\n");
|
||||
fprintf(stderr, " -X <addr> (extended addressing mode - rx addr)\n");
|
||||
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, "Options:\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> (extended addressing mode)\n");
|
||||
fprintf(stderr, " -X <addr> (extended addressing mode - rx addr)\n");
|
||||
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");
|
||||
@@ -96,7 +101,7 @@ void printbuf(unsigned char *buffer, int nbytes, int color, int timestamp,
|
||||
switch (timestamp) {
|
||||
|
||||
case 'a': /* absolute with timestamp */
|
||||
printf("(%ld.%06ld) ", tv->tv_sec, tv->tv_usec);
|
||||
printf("(%lu.%06lu) ", tv->tv_sec, tv->tv_usec);
|
||||
break;
|
||||
|
||||
case 'A': /* absolute with date */
|
||||
@@ -106,7 +111,7 @@ void printbuf(unsigned char *buffer, int nbytes, int color, int timestamp,
|
||||
|
||||
tm = *localtime(&tv->tv_sec);
|
||||
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
|
||||
printf("(%s.%06ld) ", timestring, tv->tv_usec);
|
||||
printf("(%s.%06lu) ", timestring, tv->tv_usec);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -123,7 +128,7 @@ void printbuf(unsigned char *buffer, int nbytes, int color, int timestamp,
|
||||
diff.tv_sec--, diff.tv_usec += 1000000;
|
||||
if (diff.tv_sec < 0)
|
||||
diff.tv_sec = diff.tv_usec = 0;
|
||||
printf("(%ld.%06ld) ", diff.tv_sec, diff.tv_usec);
|
||||
printf("(%lu.%06lu) ", diff.tv_sec, diff.tv_usec);
|
||||
|
||||
if (timestamp == 'd')
|
||||
*last_tv = *tv; /* update for delta calculation */
|
||||
@@ -135,7 +140,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 +156,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 +178,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 +197,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 +225,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 +256,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 +304,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 +317,25 @@ 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 ((llopts.mtu) && (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 +360,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 +375,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;
|
||||
}
|
||||
|
||||
+38
-32
@@ -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
|
||||
*
|
||||
@@ -47,21 +48,21 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/isotp.h>
|
||||
@@ -101,23 +102,25 @@ void perror_syslog(const char *s)
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - IP over CAN ISO-TP (ISO15765-2) tunnel / proof-of-concept.\n", prg);
|
||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>\n\n", prg);
|
||||
fprintf(stderr, "This program creates a Linux tunnel netdevice 'ctunX' and transfers the\n");
|
||||
fprintf(stderr, "ethernet frames inside ISO15765-2 (unreliable) datagrams on CAN.\n\n");
|
||||
fprintf(stderr, "Options: -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, " -n <name> (name of created IP netdevice. Default: '%s')\n", DEFAULT_NAME);
|
||||
fprintf(stderr, " -x <addr>[:<rxaddr>] (extended addressing / opt. separate rxaddr)\n");
|
||||
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
|
||||
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
|
||||
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
|
||||
fprintf(stderr, " -t <time ns> (transmit time in nanosecs)\n");
|
||||
fprintf(stderr, " -b <bs> (blocksize. 0 = off)\n");
|
||||
fprintf(stderr, " -m <val> (STmin in ms/ns. See spec.)\n");
|
||||
fprintf(stderr, " -w <num> (max. wait frame transmissions.)\n");
|
||||
fprintf(stderr, " -D (daemonize to background when tun device created)\n");
|
||||
fprintf(stderr, " -h (half duplex mode.)\n");
|
||||
fprintf(stderr, " -v (verbose mode. Print symbols for tunneled msgs.)\n");
|
||||
fprintf(stderr, "Options:\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, " -n <name> (name of created IP netdevice. Default: '%s')\n", DEFAULT_NAME);
|
||||
fprintf(stderr, " -x <addr>[:<rxaddr>] (extended addressing / opt. separate rxaddr)\n");
|
||||
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
|
||||
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
|
||||
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
|
||||
fprintf(stderr, " -t <time ns> (transmit time in nanosecs)\n");
|
||||
fprintf(stderr, " -b <bs> (blocksize. 0 = off)\n");
|
||||
fprintf(stderr, " -m <val> (STmin in ms/ns. See spec.)\n");
|
||||
fprintf(stderr, " -w <num> (max. wait frame transmissions.)\n");
|
||||
fprintf(stderr, " -D (daemonize to background when tun device created)\n");
|
||||
fprintf(stderr, " -h (half duplex mode.)\n");
|
||||
fprintf(stderr, " -v (verbose mode. Print symbols for tunneled msgs.)\n");
|
||||
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
|
||||
fprintf(stderr, "Use e.g. 'ifconfig ctun0 123.123.123.1 pointopoint 123.123.123.2 up'\n");
|
||||
fprintf(stderr, "to create a point-to-point IP connection on CAN.\n");
|
||||
@@ -142,7 +145,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 +166,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 +307,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 +330,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");
|
||||
|
||||
+99
-93
@@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2011 EIA Electronics
|
||||
*
|
||||
@@ -9,29 +10,29 @@
|
||||
* as published by the Free Software Foundation
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <inttypes.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <err.h>
|
||||
#include <getopt.h>
|
||||
#include <error.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/j1939.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "libj1939.h"
|
||||
|
||||
static const char help_msg[] =
|
||||
"jacd: An SAE J1939 address claiming daemon" "\n"
|
||||
"Usage: jacd [options] NAME [INTF]" "\n"
|
||||
"\n"
|
||||
"j1939acd: An SAE J1939 address claiming daemon" "\n"
|
||||
"Usage: j1939acd [options] NAME [INTF]" "\n"
|
||||
"Options:\n"
|
||||
" -v, --verbose Increase verbosity" "\n"
|
||||
" -r, --range=RANGE Ranges of source addresses" "\n"
|
||||
" e.g. 80,50-100,200-210 (defaults to 0-253)" "\n"
|
||||
@@ -41,8 +42,9 @@ static const char help_msg[] =
|
||||
"\n"
|
||||
"NAME is the 64bit nodename" "\n"
|
||||
"\n"
|
||||
"Example:" "\n"
|
||||
"jacd -r 100,80-120 -c /tmp/1122334455667788.jacd 1122334455667788" "\n"
|
||||
"Examples:" "\n"
|
||||
"j1939acd -r 100,80-120 -c /tmp/1122334455667788.jacd 1122334455667788" "\n"
|
||||
"j1939acd -r 100,80-120 -c /tmp/1122334455667788.jacd 1122334455667788 vcan0" "\n"
|
||||
;
|
||||
|
||||
#ifdef _GNU_SOURCE
|
||||
@@ -154,12 +156,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 +177,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 = J1939_PGN_ADDRESS_COMMANDED,
|
||||
.pgn_mask = J1939_PGN_MAX,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -195,44 +197,37 @@ 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),
|
||||
.can_ifindex = if_nametoindex(device),
|
||||
};
|
||||
|
||||
if (s.verbose)
|
||||
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 +236,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);
|
||||
fprintf(stderr, "send address claim for 0x%02x\n", s.last_sa);
|
||||
return ret;
|
||||
}
|
||||
static int claim_address(int sock, uint64_t name, int sa)
|
||||
@@ -260,7 +263,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 +272,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 +283,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 +291,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");
|
||||
fprintf(stdout, "send request for address claims");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -356,13 +359,13 @@ 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)
|
||||
{
|
||||
int ret;
|
||||
struct itimerval val = {};
|
||||
struct itimerval val = { 0 };
|
||||
|
||||
val.it_value.tv_sec = msec / 1000;
|
||||
val.it_value.tv_usec = (msec % 1000) * 1000;
|
||||
@@ -372,7 +375,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 */
|
||||
@@ -380,10 +383,9 @@ static inline int addr_status_mine(int sa)
|
||||
{
|
||||
if (sa == s.current_sa)
|
||||
return '*';
|
||||
else if (addr[sa].flags & F_USE)
|
||||
if (addr[sa].flags & F_USE)
|
||||
return '+';
|
||||
else
|
||||
return '-';
|
||||
return '-';
|
||||
}
|
||||
|
||||
static void dump_status(void)
|
||||
@@ -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;
|
||||
@@ -469,31 +471,34 @@ int main(int argc, char *argv[])
|
||||
#endif
|
||||
/* argument parsing */
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1)
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
++s.verbose;
|
||||
break;
|
||||
case 'c':
|
||||
s.cachefile = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
s.ranges = optarg;
|
||||
break;
|
||||
case 'a':
|
||||
s.current_sa = strtoul(optarg, 0, 0);
|
||||
break;
|
||||
case 'p':
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
++s.verbose;
|
||||
break;
|
||||
case 'c':
|
||||
s.cachefile = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
s.ranges = optarg;
|
||||
break;
|
||||
case 'a':
|
||||
s.current_sa = strtoul(optarg, 0, 0);
|
||||
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:
|
||||
fputs(help_msg, stderr);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fputs(help_msg, stderr);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (argv[optind])
|
||||
s.name = strtoull(argv[optind++], 0, 16);
|
||||
if (argv[optind])
|
||||
@@ -505,19 +510,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);
|
||||
fprintf(stderr, "- forget saved address 0x%02x\n", 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);
|
||||
fprintf(stderr, "- ready for %s:%016llx\n", 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 +540,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 +550,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 +567,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");
|
||||
fprintf(stderr, "- request sent, pending for 1250 ms\n");
|
||||
schedule_itimer(1250);
|
||||
s.state = STATE_REQ_PENDING;
|
||||
} else if (s.state == STATE_OPERATIONAL) {
|
||||
@@ -586,7 +592,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 +610,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);
|
||||
fprintf(stderr, "- claimed 0x%02x\n", sa);
|
||||
} else if (sa == s.current_sa) {
|
||||
if (s.verbose)
|
||||
error(0, 0, "address collision for 0x%02x", sa);
|
||||
fprintf(stderr, "- address collision for 0x%02x\n", 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");
|
||||
fprintf(stdout, "no address left");
|
||||
/* put J1939_IDLE_ADDR in cache file */
|
||||
s.current_sa = sa;
|
||||
goto done;
|
||||
@@ -625,7 +631,7 @@ int main(int argc, char *argv[])
|
||||
schedule_itimer(50);
|
||||
}
|
||||
break;
|
||||
case 0x0fed8:
|
||||
case J1939_PGN_ADDRESS_COMMANDED:
|
||||
if (!host_is_little_endian())
|
||||
bswap(dat, 8);
|
||||
memcpy(&cmd_name, dat, 8);
|
||||
@@ -639,7 +645,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
done:
|
||||
if (s.verbose)
|
||||
error(0, 0, "shutdown");
|
||||
fprintf(stderr, "- shutdown\n");
|
||||
claim_address(sock, s.name, J1939_IDLE_ADDR);
|
||||
save_cache();
|
||||
return 0;
|
||||
+698
@@ -0,0 +1,698 @@
|
||||
/* 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 <poll.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <linux/errqueue.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/netlink.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 j1939cat_stats {
|
||||
int err;
|
||||
uint32_t tskey;
|
||||
uint32_t send;
|
||||
};
|
||||
|
||||
struct j1939cat_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;
|
||||
int todo_broadcast;
|
||||
|
||||
unsigned long polltimeout;
|
||||
|
||||
struct sockaddr_can sockname;
|
||||
struct sockaddr_can peername;
|
||||
|
||||
struct sock_extended_err *serr;
|
||||
struct scm_timestamping *tss;
|
||||
struct j1939cat_stats stats;
|
||||
};
|
||||
|
||||
static const char help_msg[] =
|
||||
"j1939cat: netcat-like tool for j1939\n"
|
||||
"Usage: j1939cat [options] 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"
|
||||
" -B Allow to send and receive broadcast packets.\n"
|
||||
"\n"
|
||||
"Example:\n"
|
||||
"j1939cat -i some_file_to_send can0:0x80 :0x90,0x12300\n"
|
||||
"j1939cat can0:0x90 -r > /tmp/some_file_to_receive\n"
|
||||
"\n"
|
||||
;
|
||||
|
||||
static const char optstring[] = "?hi:vs:rp:P:R:B";
|
||||
|
||||
|
||||
static void j1939cat_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 j1939cat_send_one(struct j1939cat_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 > (ssize_t)buf_size) /* Should never happen */ {
|
||||
warn("%s: send more then read", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return num_sent;
|
||||
}
|
||||
|
||||
static void j1939cat_print_timestamp(struct j1939cat_priv *priv, const char *name,
|
||||
struct timespec *cur)
|
||||
{
|
||||
struct j1939cat_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 *j1939cat_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 j1939cat_scm_opt_stats(struct j1939cat_priv *priv, void *buf, int len)
|
||||
{
|
||||
struct j1939cat_stats *stats = &priv->stats;
|
||||
int offset = 0;
|
||||
|
||||
while (offset < len) {
|
||||
struct nlattr *nla = (struct nlattr *) ((char *)buf + offset);
|
||||
|
||||
switch (nla->nla_type) {
|
||||
case J1939_NLA_BYTES_ACKED:
|
||||
stats->send = *(uint32_t *)((char *)nla + NLA_HDRLEN);
|
||||
break;
|
||||
default:
|
||||
warnx("not supported J1939_NLA field\n");
|
||||
}
|
||||
|
||||
offset += NLA_ALIGN(nla->nla_len);
|
||||
}
|
||||
}
|
||||
|
||||
static int j1939cat_extract_serr(struct j1939cat_priv *priv)
|
||||
{
|
||||
struct j1939cat_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;
|
||||
|
||||
j1939cat_print_timestamp(priv, j1939cat_tstype_to_str(serr->ee_info),
|
||||
&tss->ts[0]);
|
||||
|
||||
if (serr->ee_info == SCM_TSTAMP_SCHED)
|
||||
return -EINTR;
|
||||
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);
|
||||
|
||||
j1939cat_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 j1939cat_parse_cm(struct j1939cat_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 */
|
||||
j1939cat_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 j1939cat_recv_err(struct j1939cat_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)) {
|
||||
j1939cat_parse_cm(priv, cm);
|
||||
if (priv->serr && priv->tss)
|
||||
return j1939cat_extract_serr(priv);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int j1939cat_send_loop(struct j1939cat_priv *priv, int out_fd, char *buf,
|
||||
size_t buf_size)
|
||||
{
|
||||
struct j1939cat_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;
|
||||
if (ret < 0)
|
||||
return -errno;
|
||||
if (!ret)
|
||||
return -ETIME;
|
||||
if (!(fds.revents & events)) {
|
||||
warn("%s: something else is wrong", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (fds.revents & POLLERR) {
|
||||
ret = j1939cat_recv_err(priv);
|
||||
if (ret == -EINTR)
|
||||
continue;
|
||||
if (ret)
|
||||
return ret;
|
||||
if ((priv->repeat - 1) == stats->tskey)
|
||||
tx_done = true;
|
||||
}
|
||||
|
||||
if (fds.revents & POLLOUT) {
|
||||
num_sent = j1939cat_send_one(priv, out_fd, tmp_buf, count);
|
||||
if (num_sent < 0)
|
||||
return num_sent;
|
||||
}
|
||||
} else {
|
||||
num_sent = j1939cat_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 j1939cat_sendfile(struct j1939cat_priv *priv, int out_fd, int in_fd,
|
||||
off_t *offset, size_t count)
|
||||
{
|
||||
int ret = EXIT_SUCCESS;
|
||||
off_t orig = 0;
|
||||
char *buf;
|
||||
ssize_t num_read;
|
||||
size_t to_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 = j1939cat_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 j1939cat_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 j1939cat_send(struct j1939cat_priv *priv)
|
||||
{
|
||||
unsigned int size = 0;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (priv->todo_filesize)
|
||||
size = j1939cat_get_file_size(priv->infile);
|
||||
|
||||
if (!size)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
for (i = 0; i < priv->repeat; i++) {
|
||||
priv->round++;
|
||||
ret = j1939cat_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 j1939cat_recv_one(struct j1939cat_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 j1939cat_recv(struct j1939cat_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 = j1939cat_recv_one(priv, buf, buf_size);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int j1939cat_sock_prepare(struct j1939cat_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");
|
||||
|
||||
if (priv->todo_broadcast) {
|
||||
ret = setsockopt(priv->sock, SOL_SOCKET, SO_BROADCAST,
|
||||
&priv->todo_broadcast,
|
||||
sizeof(priv->todo_broadcast));
|
||||
if (ret < 0) {
|
||||
warn("setsockopt: filed to set broadcast");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
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 j1939cat_parse_args(struct j1939cat_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;
|
||||
case 'B':
|
||||
priv->todo_broadcast = 1;
|
||||
break;
|
||||
case 'h': /*fallthrough*/
|
||||
default:
|
||||
fputs(help_msg, stderr);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (argv[optind]) {
|
||||
if (strcmp("-", argv[optind]) != 0)
|
||||
libj1939_parse_canaddr(argv[optind], &priv->sockname);
|
||||
optind++;
|
||||
}
|
||||
|
||||
if (argv[optind]) {
|
||||
if (strcmp("-", argv[optind]) != 0) {
|
||||
libj1939_parse_canaddr(argv[optind], &priv->peername);
|
||||
priv->valid_peername = 1;
|
||||
}
|
||||
optind++;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct j1939cat_priv *priv;
|
||||
int ret = 0;
|
||||
|
||||
priv = calloc(1, sizeof(*priv));
|
||||
if (!priv)
|
||||
err(EXIT_FAILURE, "can't allocate 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;
|
||||
|
||||
j1939cat_init_sockaddr_can(&priv->sockname);
|
||||
j1939cat_init_sockaddr_can(&priv->peername);
|
||||
|
||||
ret = j1939cat_parse_args(priv, argc, argv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = j1939cat_sock_prepare(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (priv->todo_recv)
|
||||
ret = j1939cat_recv(priv);
|
||||
else
|
||||
ret = j1939cat_send(priv);
|
||||
|
||||
close(priv->infile);
|
||||
close(priv->outfile);
|
||||
close(priv->sock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
+52
-52
@@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2011 EIA Electronics
|
||||
*
|
||||
@@ -9,19 +10,19 @@
|
||||
* as published by the Free Software Foundation
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <err.h>
|
||||
#include <getopt.h>
|
||||
#include <error.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "libj1939.h"
|
||||
|
||||
@@ -29,9 +30,9 @@
|
||||
* getopt
|
||||
*/
|
||||
static const char help_msg[] =
|
||||
"jspy: An SAE J1939 spy utility" "\n"
|
||||
"Usage: jspy [OPTION...] [[IFACE:][NAME|SA][,PGN]]" "\n"
|
||||
"\n"
|
||||
"j1939spy: An SAE J1939 spy utility" "\n"
|
||||
"Usage: j1939spy [OPTION...] [[IFACE:][NAME|SA][,PGN]]" "\n"
|
||||
"Options:\n"
|
||||
" -v, --verbose Increase verbosity" "\n"
|
||||
" -P, --promisc Run in promiscuous mode" "\n"
|
||||
" (= receive traffic not for this ECU)" "\n"
|
||||
@@ -74,7 +75,7 @@ static struct {
|
||||
};
|
||||
|
||||
/*
|
||||
* usefull buffers
|
||||
* useful buffers
|
||||
*/
|
||||
static const int ival_1 = 1;
|
||||
|
||||
@@ -94,8 +95,8 @@ static uint8_t *buf;
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret, sock, j, opt;
|
||||
unsigned int len;
|
||||
int ret, sock, opt;
|
||||
unsigned int j, len;
|
||||
struct timeval tref, tdut, ttmp;
|
||||
struct sockaddr_can src;
|
||||
struct j1939_filter filt;
|
||||
@@ -104,52 +105,51 @@ 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) {
|
||||
case 'v':
|
||||
++s.verbose;
|
||||
break;
|
||||
case 'b':
|
||||
s.pkt_len = strtoul(optarg, 0, 0);
|
||||
break;
|
||||
case 'P':
|
||||
++s.promisc;
|
||||
break;
|
||||
case 't':
|
||||
if (optarg) {
|
||||
if (!strchr("adzA", optarg[0]))
|
||||
error(1, 0, "unknown time option '%c'", optarg[0]);
|
||||
s.time = optarg[0];
|
||||
} else {
|
||||
s.time = 'z';
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
++s.verbose;
|
||||
break;
|
||||
case 'b':
|
||||
s.pkt_len = strtoul(optarg, 0, 0);
|
||||
break;
|
||||
case 'P':
|
||||
++s.promisc;
|
||||
break;
|
||||
case 't':
|
||||
if (optarg) {
|
||||
if (!strchr("adzA", optarg[0]))
|
||||
err(1, "unknown time option '%c'",
|
||||
optarg[0]);
|
||||
s.time = optarg[0];
|
||||
} else {
|
||||
s.time = 'z';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fputs(help_msg, stderr);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fputs(help_msg, stderr);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (argv[optind]) {
|
||||
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 +162,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 +170,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 +197,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 +208,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 +221,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;
|
||||
}
|
||||
}
|
||||
@@ -289,7 +289,7 @@ int main(int argc, char **argv)
|
||||
|
||||
printf("[%i%s]", len, (msg.msg_flags & MSG_TRUNC) ? "..." : "");
|
||||
for (j = 0; j < len; ) {
|
||||
int end = j + 4;
|
||||
unsigned int end = j + 4;
|
||||
if (end > len)
|
||||
end = len;
|
||||
printf(" ");
|
||||
+47
-46
@@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2011 EIA Electronics
|
||||
*
|
||||
@@ -9,20 +10,20 @@
|
||||
* as published by the Free Software Foundation
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <err.h>
|
||||
#include <getopt.h>
|
||||
#include <error.h>
|
||||
#include <poll.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "libj1939.h"
|
||||
|
||||
@@ -30,9 +31,9 @@
|
||||
* getopt
|
||||
*/
|
||||
static const char help_msg[] =
|
||||
"jsr: An SAE J1939 send/recv utility" "\n"
|
||||
"Usage: jsr [OPTION...] SOURCE [DEST]" "\n"
|
||||
"\n"
|
||||
"j1939sr: An SAE J1939 send/recv utility" "\n"
|
||||
"Usage: j1939sr [OPTION...] SOURCE [DEST]" "\n"
|
||||
"Options:\n"
|
||||
" -v, --verbose Increase verbosity" "\n"
|
||||
" -p, --priority=VAL J1939 priority (0..7, default 6)" "\n"
|
||||
" -S, --serialize Strictly serialize outgoing packets" "\n"
|
||||
@@ -98,40 +99,40 @@ int main(int argc, char **argv)
|
||||
#endif
|
||||
/* argument parsing */
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1)
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
++s.verbose;
|
||||
break;
|
||||
case 's':
|
||||
s.pkt_len = strtoul(optarg, 0, 0);
|
||||
if (!s.pkt_len)
|
||||
error(1, EINVAL, "packet size of %s", optarg);
|
||||
break;
|
||||
case 'p':
|
||||
s.priority = strtoul(optarg, 0, 0);
|
||||
s.defined |= DEF_PRIO;
|
||||
break;
|
||||
case 'S':
|
||||
s.sendflags |= MSG_SYN;
|
||||
break;
|
||||
default:
|
||||
fputs(help_msg, stderr);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
++s.verbose;
|
||||
break;
|
||||
case 's':
|
||||
s.pkt_len = strtoul(optarg, 0, 0);
|
||||
if (!s.pkt_len)
|
||||
err(1, "packet size of %s", optarg);
|
||||
break;
|
||||
case 'p':
|
||||
s.priority = strtoul(optarg, 0, 0);
|
||||
s.defined |= DEF_PRIO;
|
||||
break;
|
||||
case 'S':
|
||||
s.sendflags |= MSG_SYN;
|
||||
break;
|
||||
default:
|
||||
fputs(help_msg, stderr);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (argv[optind]) {
|
||||
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,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* lib.c - library for command line tools
|
||||
*
|
||||
@@ -41,13 +42,13 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <sys/socket.h> /* for sa_family_t */
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/error.h>
|
||||
#include <sys/socket.h> /* for sa_family_t */
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
@@ -582,12 +583,12 @@ void snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *c
|
||||
if (!sep)
|
||||
sep = defsep;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(error_classes); i++) {
|
||||
for (i = 0; i < (int)ARRAY_SIZE(error_classes); i++) {
|
||||
mask = 1 << i;
|
||||
if (class & mask) {
|
||||
if (classes)
|
||||
n += snprintf(buf + n, len - n, "%s", sep);
|
||||
n += snprintf(buf + n, len - n, "%s", error_classes[i]);
|
||||
n += snprintf(buf + n, len - n, "%s", error_classes[i]);
|
||||
if (mask == CAN_ERR_LOSTARB)
|
||||
n += snprintf_error_lostarb(buf + n, len - n,
|
||||
cf);
|
||||
|
||||
@@ -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}
|
||||
|
||||
+34
-13
@@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2011 EIA Electronics
|
||||
*
|
||||
@@ -9,17 +10,16 @@
|
||||
* as published by the Free Software Foundation
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <err.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <error.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.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()");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ static const char *libj1939_ifnam(int ifindex)
|
||||
fetch_names();
|
||||
|
||||
for (lp = saved; lp->if_index; ++lp) {
|
||||
if (lp->if_index == ifindex)
|
||||
if (lp->if_index == (unsigned int)ifindex)
|
||||
return lp->if_name;
|
||||
}
|
||||
if (cached) {
|
||||
@@ -64,8 +64,8 @@ static const char *libj1939_ifnam(int ifindex)
|
||||
*/
|
||||
libj1939_cleanup();
|
||||
return libj1939_ifnam(ifindex);
|
||||
} else
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* retrieve index */
|
||||
@@ -88,8 +88,29 @@ static int libj1939_ifindex(const char *str)
|
||||
if (cached) {
|
||||
libj1939_cleanup();
|
||||
return libj1939_ifindex(str);
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
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)
|
||||
@@ -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
@@ -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,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* log2asc.c - convert compact CAN frame logfile to ASC logfile
|
||||
*
|
||||
@@ -41,15 +42,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <libgen.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/time.h>
|
||||
#include <linux/can.h>
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
@@ -59,24 +60,119 @@ extern int optind, opterr, optopt;
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [can-interfaces]\n", prg);
|
||||
fprintf(stderr, "Options: -I <infile> (default stdin)\n");
|
||||
fprintf(stderr, " -O <outfile> (default stdout)\n");
|
||||
fprintf(stderr, " -4 (reduce decimal place to 4 digits)\n");
|
||||
fprintf(stderr, " -n (set newline to cr/lf - default lf)\n");
|
||||
fprintf(stderr, "%s - convert compact CAN frame logfile to ASC logfile.\n", prg);
|
||||
fprintf(stderr, "Usage: %s <options> [can-interfaces]\n", prg);
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -I <infile> (default stdin)\n");
|
||||
fprintf(stderr, " -O <outfile> (default stdout)\n");
|
||||
fprintf(stderr, " -4 (reduce decimal place to 4 digits)\n");
|
||||
fprintf(stderr, " -n (set newline to cr/lf - default lf)\n");
|
||||
fprintf(stderr, " -f (use CANFD format also for Classic CAN)\n");
|
||||
fprintf(stderr, " -r (suppress dlc for RTR frames - pre v8.5 tools)\n");
|
||||
}
|
||||
|
||||
void can_asc(struct canfd_frame *cf, int devno, int nortrdlc, char *extra_info, FILE *outfile)
|
||||
{
|
||||
int i;
|
||||
char id[10];
|
||||
char *dir = "Rx";
|
||||
|
||||
fprintf(outfile, "%-2d ", devno); /* channel number left aligned */
|
||||
|
||||
if (cf->can_id & CAN_ERR_FLAG)
|
||||
fprintf(outfile, "ErrorFrame");
|
||||
else {
|
||||
sprintf(id, "%X%c", cf->can_id & CAN_EFF_MASK,
|
||||
(cf->can_id & CAN_EFF_FLAG)?'x':' ');
|
||||
|
||||
/* check for extra info */
|
||||
if (strlen(extra_info) > 0) {
|
||||
/* only the first char is defined so far */
|
||||
if (extra_info[0] == 'T')
|
||||
dir = "Tx";
|
||||
}
|
||||
|
||||
fprintf(outfile, "%-15s %s ", id, dir);
|
||||
|
||||
if (cf->can_id & CAN_RTR_FLAG) {
|
||||
if (nortrdlc)
|
||||
fprintf(outfile, "r"); /* RTR frame */
|
||||
else
|
||||
fprintf(outfile, "r %d", cf->len); /* RTR frame */
|
||||
} else {
|
||||
fprintf(outfile, "d %d", cf->len); /* data frame */
|
||||
|
||||
for (i = 0; i < cf->len; i++) {
|
||||
fprintf(outfile, " %02X", cf->data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void canfd_asc(struct canfd_frame *cf, int devno, int mtu, char *extra_info, FILE *outfile)
|
||||
{
|
||||
int i;
|
||||
char id[10];
|
||||
char *dir = "Rx";
|
||||
unsigned int flags = 0;
|
||||
unsigned int dlen = cf->len;
|
||||
|
||||
/* relevant flags in Flags field */
|
||||
#define ASC_F_RTR 0x00000010
|
||||
#define ASC_F_FDF 0x00001000
|
||||
#define ASC_F_BRS 0x00002000
|
||||
#define ASC_F_ESI 0x00004000
|
||||
|
||||
/* check for extra info */
|
||||
if (strlen(extra_info) > 0) {
|
||||
/* only the first char is defined so far */
|
||||
if (extra_info[0] == 'T')
|
||||
dir = "Tx";
|
||||
}
|
||||
|
||||
fprintf(outfile, "CANFD %3d %s ", devno, dir); /* 3 column channel number right aligned */
|
||||
|
||||
sprintf(id, "%X%c", cf->can_id & CAN_EFF_MASK,
|
||||
(cf->can_id & CAN_EFF_FLAG)?'x':' ');
|
||||
fprintf(outfile, "%11s ", id);
|
||||
fprintf(outfile, "%c ", (cf->flags & CANFD_BRS)?'1':'0');
|
||||
fprintf(outfile, "%c ", (cf->flags & CANFD_ESI)?'1':'0');
|
||||
fprintf(outfile, "%x ", can_len2dlc(dlen));
|
||||
|
||||
if (mtu == CAN_MTU) {
|
||||
if (cf->can_id & CAN_RTR_FLAG) {
|
||||
/* no data length but dlc for RTR frames */
|
||||
dlen = 0;
|
||||
flags = ASC_F_RTR;
|
||||
}
|
||||
} else {
|
||||
flags = ASC_F_FDF;
|
||||
if (cf->flags & CANFD_BRS)
|
||||
flags |= ASC_F_BRS;
|
||||
if (cf->flags & CANFD_ESI)
|
||||
flags |= ASC_F_ESI;
|
||||
}
|
||||
|
||||
fprintf(outfile, "%2d", dlen);
|
||||
|
||||
for (i = 0; i < (int)dlen; i++) {
|
||||
fprintf(outfile, " %02X", cf->data[i]);
|
||||
}
|
||||
|
||||
fprintf(outfile, " %8d %4d %8X 0 0 0 0 0", 130000, 130, flags);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
static char buf[BUFSZ], device[BUFSZ], ascframe[BUFSZ], id[10];
|
||||
static char buf[BUFSZ], device[BUFSZ], ascframe[BUFSZ], extra_info[BUFSZ];
|
||||
|
||||
struct canfd_frame cf;
|
||||
static struct timeval tv, start_tv;
|
||||
FILE *infile = stdin;
|
||||
FILE *outfile = stdout;
|
||||
static int maxdev, devno, i, crlf, d4, opt;
|
||||
static int maxdev, devno, i, crlf, fdfmt, nortrdlc, d4, opt, mtu;
|
||||
|
||||
while ((opt = getopt(argc, argv, "I:O:4n?")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "I:O:4nfr?")) != -1) {
|
||||
switch (opt) {
|
||||
case 'I':
|
||||
infile = fopen(optarg, "r");
|
||||
@@ -98,6 +194,14 @@ int main(int argc, char **argv)
|
||||
crlf = 1;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
fdfmt = 1;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
nortrdlc = 1;
|
||||
break;
|
||||
|
||||
case '4':
|
||||
d4 = 1;
|
||||
break;
|
||||
@@ -136,10 +240,17 @@ int main(int argc, char **argv)
|
||||
if (buf[0] != '(')
|
||||
continue;
|
||||
|
||||
if (sscanf(buf, "(%ld.%ld) %s %s", &tv.tv_sec, &tv.tv_usec,
|
||||
device, ascframe) != 4) {
|
||||
fprintf(stderr, "incorrect line format in logfile\n");
|
||||
return 1;
|
||||
if (sscanf(buf, "(%lu.%lu) %s %s %s", &tv.tv_sec, &tv.tv_usec,
|
||||
device, ascframe, extra_info) != 5) {
|
||||
|
||||
/* do not evaluate the extra info */
|
||||
extra_info[0] = 0;
|
||||
|
||||
if (sscanf(buf, "(%lu.%lu) %s %s", &tv.tv_sec, &tv.tv_usec,
|
||||
device, ascframe) != 4) {
|
||||
fprintf(stderr, "incorrect line format in logfile\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!start_tv.tv_sec) { /* print banner */
|
||||
@@ -159,9 +270,14 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
if (devno) { /* only convert for selected CAN devices */
|
||||
if (parse_canframe(ascframe, &cf) != CAN_MTU) /* no CAN FD support so far */
|
||||
mtu = parse_canframe(ascframe, &cf);
|
||||
if ((mtu != CAN_MTU) && (mtu != CANFD_MTU))
|
||||
return 1;
|
||||
|
||||
/* we don't support error message frames in CAN FD */
|
||||
if ((mtu == CANFD_MTU) && (cf.can_id & CAN_ERR_FLAG))
|
||||
continue;
|
||||
|
||||
tv.tv_sec = tv.tv_sec - start_tv.tv_sec;
|
||||
tv.tv_usec = tv.tv_usec - start_tv.tv_usec;
|
||||
if (tv.tv_usec < 0)
|
||||
@@ -170,29 +286,15 @@ int main(int argc, char **argv)
|
||||
tv.tv_sec = tv.tv_usec = 0;
|
||||
|
||||
if (d4)
|
||||
fprintf(outfile, "%4ld.%04ld ", tv.tv_sec, tv.tv_usec/100);
|
||||
fprintf(outfile, "%4lu.%04lu ", tv.tv_sec, tv.tv_usec/100);
|
||||
else
|
||||
fprintf(outfile, "%4ld.%06ld ", tv.tv_sec, tv.tv_usec);
|
||||
fprintf(outfile, "%4lu.%06lu ", tv.tv_sec, tv.tv_usec);
|
||||
|
||||
fprintf(outfile, "%-2d ", devno); /* channel number left aligned */
|
||||
if ((mtu == CAN_MTU) && (fdfmt == 0))
|
||||
can_asc(&cf, devno, nortrdlc, extra_info, outfile);
|
||||
else
|
||||
canfd_asc(&cf, devno, mtu, extra_info, outfile);
|
||||
|
||||
if (cf.can_id & CAN_ERR_FLAG)
|
||||
fprintf(outfile, "ErrorFrame");
|
||||
else {
|
||||
sprintf(id, "%X%c", cf.can_id & CAN_EFF_MASK,
|
||||
(cf.can_id & CAN_EFF_FLAG)?'x':' ');
|
||||
fprintf(outfile, "%-15s Rx ", id);
|
||||
|
||||
if (cf.can_id & CAN_RTR_FLAG)
|
||||
fprintf(outfile, "r"); /* RTR frame */
|
||||
else {
|
||||
fprintf(outfile, "d %d", cf.len); /* data frame */
|
||||
|
||||
for (i = 0; i < cf.len; i++) {
|
||||
fprintf(outfile, " %02X", cf.data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (crlf)
|
||||
fprintf(outfile, "\r");
|
||||
fprintf(outfile, "\n");
|
||||
|
||||
+3
-2
@@ -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
|
||||
*
|
||||
@@ -43,15 +44,15 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <linux/can.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#define COMMENTSZ 200
|
||||
#define BUFSZ (sizeof("(1345212884.318850)") + IFNAMSIZ + 4 + CL_CFSZ + COMMENTSZ) /* for one line in the logfile */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
int main(void)
|
||||
{
|
||||
char buf[BUFSZ], timestamp[BUFSZ], device[BUFSZ], ascframe[BUFSZ];
|
||||
struct canfd_frame cf;
|
||||
|
||||
+55
-34
@@ -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
|
||||
*
|
||||
@@ -41,37 +42,38 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/tty.h>
|
||||
#include <net/if.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/socket.h>
|
||||
#include <termios.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - userspace tool for serial line CAN interface driver SLCAN.\n", prg);
|
||||
fprintf(stderr, "\nUsage: %s [options] tty\n\n", prg);
|
||||
fprintf(stderr, "Options: -o (send open command 'O\\r')\n");
|
||||
fprintf(stderr, " -l (send listen only command 'L\\r', overrides -o)\n");
|
||||
fprintf(stderr, " -c (send close command 'C\\r')\n");
|
||||
fprintf(stderr, " -f (read status flags with 'F\\r' to reset error states)\n");
|
||||
fprintf(stderr, " -s <speed> (set CAN speed 0..8)\n");
|
||||
fprintf(stderr, " -b <btr> (set bit time register value)\n");
|
||||
fprintf(stderr, " -d (only detach line discipline)\n");
|
||||
fprintf(stderr, " -w (attach - wait for keypess - detach)\n");
|
||||
fprintf(stderr, " -n <name> (assign created netdevice name)\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -o (send open command 'O\\r')\n");
|
||||
fprintf(stderr, " -l (send listen only command 'L\\r', overrides -o)\n");
|
||||
fprintf(stderr, " -c (send close command 'C\\r')\n");
|
||||
fprintf(stderr, " -f (read status flags with 'F\\r' to reset error states)\n");
|
||||
fprintf(stderr, " -s <speed> (set CAN speed 0..8)\n");
|
||||
fprintf(stderr, " -b <btr> (set bit time register value)\n");
|
||||
fprintf(stderr, " -d (only detach line discipline)\n");
|
||||
fprintf(stderr, " -w (attach - wait for keypess - detach)\n");
|
||||
fprintf(stderr, " -n <name> (assign created netdevice name)\n");
|
||||
fprintf(stderr, "\nExamples:\n");
|
||||
fprintf(stderr, "slcan_attach -w -o -f -s6 -c /dev/ttyS1\n");
|
||||
fprintf(stderr, "slcan_attach /dev/ttyS1\n");
|
||||
fprintf(stderr, "slcan_attach -d /dev/ttyS1\n");
|
||||
fprintf(stderr, "slcan_attach -w -n can15 /dev/ttyS1\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "slcan_attach -w -o -f -s6 -c /dev/ttyS1\n\n");
|
||||
fprintf(stderr, "slcan_attach /dev/ttyS1\n\n");
|
||||
fprintf(stderr, "slcan_attach -d /dev/ttyS1\n\n");
|
||||
fprintf(stderr, "slcan_attach -w -n can15 /dev/ttyS1\n\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -87,7 +89,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 +135,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 +160,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 +203,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 +219,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 +247,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -22,25 +22,25 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/tty.h>
|
||||
#include <net/if.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <fcntl.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <syslog.h>
|
||||
#include <termios.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/serial.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Change this to whatever your daemon is called */
|
||||
#define DAEMON_NAME "slcand"
|
||||
@@ -72,22 +72,23 @@ static syslog_t syslogger = syslog;
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - userspace daemon for serial line CAN interface driver SLCAN.\n", prg);
|
||||
fprintf(stderr, "\nUsage: %s [options] <tty> [canif-name]\n\n", prg);
|
||||
fprintf(stderr, "Options: -o (send open command 'O\\r')\n");
|
||||
fprintf(stderr, " -c (send close command 'C\\r')\n");
|
||||
fprintf(stderr, " -f (read status flags with 'F\\r' to reset error states)\n");
|
||||
fprintf(stderr, " -l (send listen only command 'L\\r', overrides -o)\n");
|
||||
fprintf(stderr, " -s <speed> (set CAN speed 0..8)\n");
|
||||
fprintf(stderr, " -S <speed> (set UART speed in baud)\n");
|
||||
fprintf(stderr, " -t <type> (set UART flow control type 'hw' or 'sw')\n");
|
||||
fprintf(stderr, " -b <btr> (set bit time register value)\n");
|
||||
fprintf(stderr, " -F (stay in foreground; no daemonize)\n");
|
||||
fprintf(stderr, " -h (show this help page)\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -o (send open command 'O\\r')\n");
|
||||
fprintf(stderr, " -c (send close command 'C\\r')\n");
|
||||
fprintf(stderr, " -f (read status flags with 'F\\r' to reset error states)\n");
|
||||
fprintf(stderr, " -l (send listen only command 'L\\r', overrides -o)\n");
|
||||
fprintf(stderr, " -s <speed> (set CAN speed 0..8)\n");
|
||||
fprintf(stderr, " -S <speed> (set UART speed in baud)\n");
|
||||
fprintf(stderr, " -t <type> (set UART flow control type 'hw' or 'sw')\n");
|
||||
fprintf(stderr, " -b <btr> (set bit time register value)\n");
|
||||
fprintf(stderr, " -F (stay in foreground; no daemonize)\n");
|
||||
fprintf(stderr, " -h (show this help page)\n");
|
||||
fprintf(stderr, "\nExamples:\n");
|
||||
fprintf(stderr, "slcand -o -c -f -s6 ttyUSB0\n");
|
||||
fprintf(stderr, "slcand -o -c -f -s6 ttyUSB0 can0\n");
|
||||
fprintf(stderr, "slcand -o -c -f -s6 /dev/ttyUSB0\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "slcand -o -c -f -s6 ttyUSB0\n\n");
|
||||
fprintf(stderr, "slcand -o -c -f -s6 ttyUSB0 can0\n\n");
|
||||
fprintf(stderr, "slcand -o -c -f -s6 /dev/ttyUSB0\n\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -180,7 +181,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 +272,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 +284,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 +292,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 +330,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 +373,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 +402,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 +431,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 */
|
||||
|
||||
+22
-15
@@ -1,13 +1,15 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* slcanpty.c - creates a pty for applications using the slcan ASCII protocol
|
||||
* slcanpty: adapter for applications using the slcan ASCII protocol
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
* 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
|
||||
@@ -22,21 +24,24 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#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 +79,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");
|
||||
|
||||
@@ -427,16 +432,18 @@ int main(int argc, char **argv)
|
||||
|
||||
/* check command line options */
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "%s creates a pty for applications using"
|
||||
" the slcan ASCII protocol and\n", argv[0]);
|
||||
fprintf(stderr, "%s: adapter for applications using"
|
||||
" the slcan ASCII protocol.\n", basename(argv[0]));
|
||||
fprintf(stderr, "\n%s creates a pty for applications using"
|
||||
" the slcan ASCII protocol and\n", basename(argv[0]));
|
||||
fprintf(stderr, "converts the ASCII data to a CAN network"
|
||||
" interface (and vice versa)\n\n");
|
||||
fprintf(stderr, "Usage: %s <pty> <can interface>\n", argv[0]);
|
||||
fprintf(stderr, "e.g. '%s /dev/ptyc0 can0' creates"
|
||||
" /dev/ttyc0 for the slcan application\n", argv[0]);
|
||||
fprintf(stderr, "Usage: %s <pty> <can interface>\n", basename(argv[0]));
|
||||
fprintf(stderr, "\nExamples:\n");
|
||||
fprintf(stderr, "%s /dev/ptyc0 can0 - creates /dev/ttyc0 for the slcan application\n\n",
|
||||
basename(argv[0]));
|
||||
fprintf(stderr, "e.g. for pseudo-terminal '%s %s can0' creates"
|
||||
" /dev/pts/N\n", argv[0], DEVICE_NAME_PTMX);
|
||||
" /dev/pts/N\n", basename(argv[0]), DEVICE_NAME_PTMX);
|
||||
fprintf(stderr, "\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
+136
-89
@@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2013 EIA Electronics
|
||||
*
|
||||
@@ -9,26 +10,26 @@
|
||||
* as published by the Free Software Foundation
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <inttypes.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <err.h>
|
||||
#include <getopt.h>
|
||||
#include <error.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "libj1939.h"
|
||||
|
||||
static const char help_msg[] =
|
||||
"testj1939: demonstrate j1939 use\n"
|
||||
"Usage: testj1939 FROM TO\n"
|
||||
"Usage: testj1939 [OPTIONS] FROM TO\n"
|
||||
" FROM / TO - or [IFACE][:[SA][,[PGN][,NAME]]]\n"
|
||||
"Options:\n"
|
||||
" -v Print relevant API calls\n"
|
||||
@@ -38,57 +39,41 @@ 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"
|
||||
"Example:\n"
|
||||
"Examples:\n"
|
||||
"testj1939 can1 20\n"
|
||||
"\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);
|
||||
}
|
||||
|
||||
static void schedule_oneshot_itimer(double delay)
|
||||
{
|
||||
struct itimerval it = {};
|
||||
struct itimerval it = { 0 };
|
||||
|
||||
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 */
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret, sock, opt, j;
|
||||
int ret, sock, opt;
|
||||
unsigned int j;
|
||||
int verbose = 0;
|
||||
socklen_t peernamelen;
|
||||
struct sockaddr_can sockname = {
|
||||
@@ -108,53 +93,74 @@ 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;
|
||||
unsigned int todo_send = 0;
|
||||
int todo_recv = 0, todo_echo = 0, todo_prio = -1;
|
||||
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)
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
case 's':
|
||||
todo_send = strtoul(optarg ?: "8", NULL, 0);
|
||||
break;
|
||||
case 'r':
|
||||
todo_recv = 1;
|
||||
break;
|
||||
case 'e':
|
||||
todo_echo = 1;
|
||||
break;
|
||||
case 'p':
|
||||
todo_prio = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'c':
|
||||
todo_connect = 1;
|
||||
break;
|
||||
case 'n':
|
||||
todo_names = 1;
|
||||
break;
|
||||
case 'w':
|
||||
schedule_oneshot_itimer(strtod(optarg ?: "1", NULL));
|
||||
signal(SIGALRM, onsigalrm);
|
||||
todo_wait = 1;
|
||||
break;
|
||||
default:
|
||||
fputs(help_msg, stderr);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
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;
|
||||
break;
|
||||
case 'e':
|
||||
todo_echo = 1;
|
||||
break;
|
||||
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);
|
||||
todo_wait = 1;
|
||||
break;
|
||||
default:
|
||||
fputs(help_msg, stderr);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (argv[optind]) {
|
||||
if (strcmp("-", argv[optind]))
|
||||
parse_canaddr(argv[optind], &sockname);
|
||||
if (strcmp("-", argv[optind]) != 0)
|
||||
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);
|
||||
if (strcmp("-", argv[optind]) != 0) {
|
||||
libj1939_parse_canaddr(argv[optind], &peername);
|
||||
valid_peername = 1;
|
||||
}
|
||||
++optind;
|
||||
@@ -165,7 +171,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 +199,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 +258,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
error(1, errno, "sendto");
|
||||
err(1, "sendto");
|
||||
}
|
||||
|
||||
/* main loop */
|
||||
@@ -240,7 +280,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 +289,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;
|
||||
|
||||
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)
|
||||
printf(" %02x", dat[j]);
|
||||
for (i = 0, j = 0; i < ret; ++i, j++) {
|
||||
if (j == 8) {
|
||||
printf("\n%05x ", i);
|
||||
j = 0;
|
||||
}
|
||||
printf(" %02x", dat[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user