libcsp
libcsp copied to clipboard
SocketCAN does not work outside of promiscuous mode
Description
When using csp_can_socketcan_open_and_add_interface to create a CAN interface there is no option to specify the interface address. The filter then defaults to address 0 (through calloc). Receiving messages is then stuck at the "read" function in socketcan_rx_thread, as this thread is started immediately. The thread then gets stuck as no message is received sent to address 0. Modifying the iface.addr after the call to csp_can_socketcan_open_and_add_interface therefore has no effect.
To Reproduce
Open a csp socket through csp_can_socketcan_open_and_add_interface, without promiscuous mode. Try to modify the address through modifying the iface. Observe no packets are received and that execution of the socketcan_rx_thread is stuck.
Expected behavior
In addition to the promiscuous mode flag, the function should have an address as its arguments.
Additional context
N/A
Yes, we have this support for the embeded drivers. See the example driver for atmel ASF in the examples folder. So far no-one has cared to implement filtered version for linux. Since linux usually is mostly used on PC's and laptops in the lab. And has enough ressources to do software based filtering.
I will mark this as a feature request. Which you are welcome to work on if you wish :)
In my case, I am also working in development with SocketCAN and Linux on an amd64 computer, for software which will later be cross-compiled to ARM Linux.
I've tried the client-server example using the vcan0
interface:
ip link add dev vcan0 type vcan
ip link set vcan0 up
and no packet is received at all:
Initialising CSPINIT CAN: device: [vcan0], bitrate: 0, promisc: 0
Connection table
[00 0x562dbe683960] S:0, 0 -> 0, 0 -> 0 (17) fl 0
[01 0x562dbe683a70] S:0, 0 -> 0, 0 -> 0 (18) fl 0
[02 0x562dbe683b80] S:0, 0 -> 0, 0 -> 0 (19) fl 0
[03 0x562dbe683c90] S:0, 0 -> 0, 0 -> 0 (20) fl 0
[04 0x562dbe683da0] S:0, 0 -> 0, 0 -> 0 (21) fl 0
[05 0x562dbe683eb0] S:0, 0 -> 0, 0 -> 0 (22) fl 0
[06 0x562dbe683fc0] S:0, 0 -> 0, 0 -> 0 (23) fl 0
[07 0x562dbe6840d0] S:0, 0 -> 0, 0 -> 0 (24) fl 0
Interfaces
LOOP addr: 0 netmask: 14 mtu: 0
tx: 00000 rx: 00000 txe: 00000 rxe: 00000
drop: 00000 autherr: 00000 frame: 00000
txb: 0 (0B) rxb: 0 (0B)
CAN addr: 0 netmask: 0 mtu: 248
tx: 00000 rx: 00000 txe: 00000 rxe: 00000
drop: 00000 autherr: 00000 frame: 00000
txb: 0 (0B) rxb: 0 (0B)
Route table
0/0 CAN
Server task started
whereas using loopback it works as expected.
Even though I've tried in my own code with promiscuous mode in the server
, I have not been able to establish communication through vcan0
, even though I can see the packets being sent with candump
:
$ candump -a vcan0
vcan0 101FE022 [8] 00 00 14 C0 00 01 02 03 '........'
vcan0 101FE025 [1] 04 '.'
vcan0 101FE042 [8] 00 00 15 00 00 01 02 03 '........'
vcan0 101FE045 [1] 04 '.'
Try setting the promisc flag to 1 That should work for vcan
The promisc
flag [1] doesn't have any effect on CAN. If you see CAN frames with candump
on vcan0
your application should see them, too.
[1] edit: the Linux per network interface promisc
flag
I have tried with promisc
to true to no avail. While testing, I have seen that when compiling with pure CMake, the CSP_HAVE_LIBSOCKETCAN
variable is not properly set and so I had to do it in the code. I am running the csp_server_client
example, with just a #define CSP_HAVE_LIBSOCKETCAN 1
and promisc = true
, and compiled with the following CMakeLists.txt
:
cmake_minimum_required(VERSION 3.9)
project(libcsp-vcan-test CXX C)
include(FetchContent)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
FetchContent_Declare(libcsp
GIT_REPOSITORY https://github.com/libcsp/libcsp.git
GIT_TAG 9114bbd
)
FetchContent_GetProperties(libcsp)
if(NOT libcsp_POPULATED)
FetchContent_Populate(libcsp)
add_subdirectory(${libcsp_SOURCE_DIR} ${libcsp_BINARY_DIR} EXCLUDE_FROM_ALL)
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Wno-psabi -Wall -Wextra -O3 -fno-exceptions")
add_executable(libcsp-vcan-test csp_server_client.c csp_server_client_posix.c)
target_link_libraries(libcsp-vcan-test PRIVATE libcsp)
The result is still the same, that I can see the frames with candump
, but not with the software:
./libcsp-vcan-test -c vcan0 -a 10
Initialising CSP
INIT CAN CSP
Connection table
Interfaces
Route table
Server task started
^C
./libcsp-vcan-test -c vcan0 -r 10
Initialising CSP
INIT CAN CSP
Connection table
Interfaces
Route table
Client task startedPing address: 10, result -1 [mS]
reboot system request sent to address: 10
Ping address: 10, result -1 [mS]
reboot system request sent to address: 10
^C
Start the application that should be receiving things with strace: strace -ff -o /tmp/log <APPLICATION> <APPLICATION_ARGS>
. Post the logfiles here.
I apologize for the delay, here are the logs for both the client and server, just in case. logs.tar.gz
Both application set up a CAN_RAW_FILTER
, see lines 74 of logsrv.36060
and logcli.36146
:
write(1, "INIT CAN CSP\n", 13) = 13
socket(AF_CAN, SOCK_RAW, CAN_RAW) = 3
ioctl(3, SIOCGIFINDEX, {ifr_name="vcan0", ifr_ifindex=5}) = 0
bind(3, {sa_family=AF_CAN, sa_data="\0\0\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"}, 24) = 0
setsockopt(3, SOL_CAN_RAW, CAN_RAW_FILTER, "\0\0\0\0\0\0\0\0", 8) = 0
This means they should receive everything on the CAN bus. Further we see that the CAN socket is fd 3
. Now we look at the log files for writes of 16 bytes to fd 3
, the last 8 bytes are the CAN data:
$ grep 'write(3, .*) = 16' *
logcli.36149:write(3, "\2@\1\220\10\0\0\0\0\0\24\200\0\1\2\3", 16) = 16
logcli.36149:write(3, "\4@\1\220\10\0\0\0\4\5\6\7\10\t\n\v", 16) = 16
logcli.36149:write(3, "\10@\1\220\10\0\0\0\f\r\16\17\20\21\22\23", 16) = 16
logcli.36149:write(3, "\f@\1\220\10\0\0\0\24\25\26\27\30\31\32\33", 16) = 16
logcli.36149:write(3, "\20@\1\220\10\0\0\0\34\35\36\37 !\"#", 16) = 16
logcli.36149:write(3, "\24@\1\220\10\0\0\0$%&'()*+", 16) = 16
logcli.36149:write(3, "\30@\1\220\10\0\0\0,-./0123", 16) = 16
logcli.36149:write(3, "\34@\1\220\10\0\0\000456789:;", 16) = 16
logcli.36149:write(3, "\0@\1\220\10\0\0\0<=>?@ABC", 16) = 16
logcli.36149:write(3, "\4@\1\220\10\0\0\0DEFGHIJK", 16) = 16
logcli.36149:write(3, "\10@\1\220\10\0\0\0LMNOPQRS", 16) = 16
logcli.36149:write(3, "\f@\1\220\10\0\0\0TUVWXYZ[", 16) = 16
logcli.36149:write(3, "\21@\1\220\10\0\0\0\\]^_`abc", 16) = 16
logcli.36149:write(3, "#@\1\220\10\0\0\0\0\0D\300\200\7\200\7", 16) = 16
logcli.36149:write(3, "B@\1\220\10\0\0\0\0\0\245\0Hell", 16) = 16
logcli.36149:write(3, "D@\1\220\10\0\0\0o world ", 16) = 16
logcli.36149:write(3, "I@\1\220\2\0\0\0A\0\0\0\0\0\0\0", 16) = 16
logcli.36149:write(3, "b@\1\220\10\0\0\0\0\0\25@\0\1\2\3", 16) = 16
logcli.36149:write(3, "d@\1\220\10\0\0\0\4\5\6\7\10\t\n\v", 16) = 16
logcli.36149:write(3, "h@\1\220\10\0\0\0\f\r\16\17\20\21\22\23", 16) = 16
logcli.36149:write(3, "l@\1\220\10\0\0\0\24\25\26\27\30\31\32\33", 16) = 16
logcli.36149:write(3, "p@\1\220\10\0\0\0\34\35\36\37 !\"#", 16) = 16
logcli.36149:write(3, "t@\1\220\10\0\0\0$%&'()*+", 16) = 16
logcli.36149:write(3, "x@\1\220\10\0\0\0,-./0123", 16) = 16
logcli.36149:write(3, "|@\1\220\10\0\0\000456789:;", 16) = 16
logcli.36149:write(3, "`@\1\220\10\0\0\0<=>?@ABC", 16) = 16
logcli.36149:write(3, "d@\1\220\10\0\0\0DEFGHIJK", 16) = 16
logcli.36149:write(3, "h@\1\220\10\0\0\0LMNOPQRS", 16) = 16
logcli.36149:write(3, "l@\1\220\10\0\0\0TUVWXYZ[", 16) = 16
logcli.36149:write(3, "q@\1\220\10\0\0\0\\]^_`abc", 16) = 16
logcli.36149:write(3, "\3@\1\220\10\0\0\0\0\0E\200\200\7\200\7", 16) = 16
logcli.36149:write(3, "\"@\1\220\10\0\0\0\0\0\245\300Hell", 16) = 16
logcli.36149:write(3, "$@\1\220\10\0\0\0o world ", 16) = 16
logcli.36149:write(3, ")@\1\220\2\0\0\0B\0\0\0\0\0\0\0", 16) = 16
logcli.36149:write(3, "B@\1\220\10\0\0\0\0\0\26\0\0\1\2\3", 16) = 16
logcli.36149:write(3, "D@\1\220\10\0\0\0\4\5\6\7\10\t\n\v", 16) = 16
logcli.36149:write(3, "H@\1\220\10\0\0\0\f\r\16\17\20\21\22\23", 16) = 16
logcli.36149:write(3, "L@\1\220\10\0\0\0\24\25\26\27\30\31\32\33", 16) = 16
logcli.36149:write(3, "P@\1\220\10\0\0\0\34\35\36\37 !\"#", 16) = 16
logcli.36149:write(3, "T@\1\220\10\0\0\0$%&'()*+", 16) = 16
logcli.36149:write(3, "X@\1\220\10\0\0\0,-./0123", 16) = 16
logcli.36149:write(3, "\\@\1\220\10\0\0\000456789:;", 16) = 16
logcli.36149:write(3, "@@\1\220\10\0\0\0<=>?@ABC", 16) = 16
logcli.36149:write(3, "D@\1\220\10\0\0\0DEFGHIJK", 16) = 16
logcli.36149:write(3, "H@\1\220\10\0\0\0LMNOPQRS", 16) = 16
logcli.36149:write(3, "L@\1\220\10\0\0\0TUVWXYZ[", 16) = 16
logcli.36149:write(3, "Q@\1\220\10\0\0\0\\]^_`abc", 16) = 16
logcli.36149:write(3, "c@\1\220\10\0\0\0\0\0D@\200\7\200\7", 16) = 16
logcli.36149:write(3, "\2@\1\220\10\0\0\0\0\0\244\200Hell", 16) = 16
logcli.36149:write(3, "\4@\1\220\10\0\0\0o world ", 16) = 16
logcli.36149:write(3, "\t@\1\220\2\0\0\0C\0\0\0\0\0\0\0", 16) = 16
Now let's look for the corresponding reads (not limited to 16 bytes to see pending read calls):
$ grep 'read(3, .*)' *
logcli.36146:read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
logcli.36146:read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832
This read on fd 3
is some library, so not of interest.
logcli.36148:read(3, <unfinished ...>) = ?
This read(3, )
call is blocking in the kernel. This means it's waiting for data and has not received any yet. By default an application doesn't receive the data from a CAN interface it has send to it. Here it's logcli
that's waiting for data and in the first log we see that logcli
was writing to the CAN bus, it will not receive its own messages.
The rest of the log is about logsrv
:
logsrv.36060:read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
logsrv.36060:read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832
Again reading of some library. After this logsrv
reads the CAN messages send by logcli
:
logsrv.36065:read(3, "\2@\1\220\10\0\0\0\0\0\24\200\0\1\2\3", 16) = 16
logsrv.36065:read(3, "\4@\1\220\10\0\0\0\4\5\6\7\10\t\n\v", 16) = 16
logsrv.36065:read(3, "\10@\1\220\10\0\0\0\f\r\16\17\20\21\22\23", 16) = 16
logsrv.36065:read(3, "\f@\1\220\10\0\0\0\24\25\26\27\30\31\32\33", 16) = 16
logsrv.36065:read(3, "\20@\1\220\10\0\0\0\34\35\36\37 !\"#", 16) = 16
logsrv.36065:read(3, "\24@\1\220\10\0\0\0$%&'()*+", 16) = 16
logsrv.36065:read(3, "\30@\1\220\10\0\0\0,-./0123", 16) = 16
logsrv.36065:read(3, "\34@\1\220\10\0\0\000456789:;", 16) = 16
logsrv.36065:read(3, "\0@\1\220\10\0\0\0<=>?@ABC", 16) = 16
logsrv.36065:read(3, "\4@\1\220\10\0\0\0DEFGHIJK", 16) = 16
logsrv.36065:read(3, "\10@\1\220\10\0\0\0LMNOPQRS", 16) = 16
logsrv.36065:read(3, "\f@\1\220\10\0\0\0TUVWXYZ[", 16) = 16
logsrv.36065:read(3, "\21@\1\220\10\0\0\0\\]^_`abc", 16) = 16
logsrv.36065:read(3, "#@\1\220\10\0\0\0\0\0D\300\200\7\200\7", 16) = 16
logsrv.36065:read(3, "B@\1\220\10\0\0\0\0\0\245\0Hell", 16) = 16
logsrv.36065:read(3, "D@\1\220\10\0\0\0o world ", 16) = 16
logsrv.36065:read(3, "I@\1\220\2\0\0\0A\0\0\0\0\0\0\0", 16) = 16
logsrv.36065:read(3, "b@\1\220\10\0\0\0\0\0\25@\0\1\2\3", 16) = 16
logsrv.36065:read(3, "d@\1\220\10\0\0\0\4\5\6\7\10\t\n\v", 16) = 16
logsrv.36065:read(3, "h@\1\220\10\0\0\0\f\r\16\17\20\21\22\23", 16) = 16
logsrv.36065:read(3, "l@\1\220\10\0\0\0\24\25\26\27\30\31\32\33", 16) = 16
logsrv.36065:read(3, "p@\1\220\10\0\0\0\34\35\36\37 !\"#", 16) = 16
logsrv.36065:read(3, "t@\1\220\10\0\0\0$%&'()*+", 16) = 16
logsrv.36065:read(3, "x@\1\220\10\0\0\0,-./0123", 16) = 16
logsrv.36065:read(3, "|@\1\220\10\0\0\000456789:;", 16) = 16
logsrv.36065:read(3, "`@\1\220\10\0\0\0<=>?@ABC", 16) = 16
logsrv.36065:read(3, "d@\1\220\10\0\0\0DEFGHIJK", 16) = 16
logsrv.36065:read(3, "h@\1\220\10\0\0\0LMNOPQRS", 16) = 16
logsrv.36065:read(3, "l@\1\220\10\0\0\0TUVWXYZ[", 16) = 16
logsrv.36065:read(3, "q@\1\220\10\0\0\0\\]^_`abc", 16) = 16
logsrv.36065:read(3, "\3@\1\220\10\0\0\0\0\0E\200\200\7\200\7", 16) = 16
logsrv.36065:read(3, "\"@\1\220\10\0\0\0\0\0\245\300Hell", 16) = 16
logsrv.36065:read(3, "$@\1\220\10\0\0\0o world ", 16) = 16
logsrv.36065:read(3, ")@\1\220\2\0\0\0B\0\0\0\0\0\0\0", 16) = 16
logsrv.36065:read(3, "B@\1\220\10\0\0\0\0\0\26\0\0\1\2\3", 16) = 16
logsrv.36065:read(3, "D@\1\220\10\0\0\0\4\5\6\7\10\t\n\v", 16) = 16
logsrv.36065:read(3, "H@\1\220\10\0\0\0\f\r\16\17\20\21\22\23", 16) = 16
logsrv.36065:read(3, "L@\1\220\10\0\0\0\24\25\26\27\30\31\32\33", 16) = 16
logsrv.36065:read(3, "P@\1\220\10\0\0\0\34\35\36\37 !\"#", 16) = 16
logsrv.36065:read(3, "T@\1\220\10\0\0\0$%&'()*+", 16) = 16
logsrv.36065:read(3, "X@\1\220\10\0\0\0,-./0123", 16) = 16
logsrv.36065:read(3, "\\@\1\220\10\0\0\000456789:;", 16) = 16
logsrv.36065:read(3, "@@\1\220\10\0\0\0<=>?@ABC", 16) = 16
logsrv.36065:read(3, "D@\1\220\10\0\0\0DEFGHIJK", 16) = 16
logsrv.36065:read(3, "H@\1\220\10\0\0\0LMNOPQRS", 16) = 16
logsrv.36065:read(3, "L@\1\220\10\0\0\0TUVWXYZ[", 16) = 16
logsrv.36065:read(3, "Q@\1\220\10\0\0\0\\]^_`abc", 16) = 16
logsrv.36065:read(3, "c@\1\220\10\0\0\0\0\0D@\200\7\200\7", 16) = 16
logsrv.36065:read(3, "\2@\1\220\10\0\0\0\0\0\244\200Hell", 16) = 16
logsrv.36065:read(3, "\4@\1\220\10\0\0\0o world ", 16) = 16
logsrv.36065:read(3, "\t@\1\220\2\0\0\0C\0\0\0\0\0\0\0", 16) = 16
logsrv.36065:read(3, <unfinished ...>) = ?
The last entry is the last read(3,
waiting for data. So from the application <-> Linux point of view, everything looks as expected.
Looking at the code:
https://github.com/libcsp/libcsp/blob/12326d109e32672e83a95e728b9579a66ee47802/src/drivers/can/can_socketcan.c#L103-L129
we see that libcsp
has the concept of promisc
mode, too. I updated https://github.com/libcsp/libcsp/issues/388#issuecomment-1592724580 to clarify my confusion.