libcsp icon indicating copy to clipboard operation
libcsp copied to clipboard

SocketCAN does not work outside of promiscuous mode

Open ghvisser opened this issue 2 years ago • 9 comments

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

ghvisser avatar Oct 27 '22 13:10 ghvisser

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 :)

johandc avatar Oct 29 '22 13:10 johandc

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                        '.'

Zosoworld avatar May 26 '23 17:05 Zosoworld

Try setting the promisc flag to 1 That should work for vcan

johandc avatar Jun 01 '23 05:06 johandc

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

marckleinebudde avatar Jun 15 '23 09:06 marckleinebudde

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

Zosoworld avatar Jun 15 '23 16:06 Zosoworld

Start the application that should be receiving things with strace: strace -ff -o /tmp/log <APPLICATION> <APPLICATION_ARGS>. Post the logfiles here.

marckleinebudde avatar Jun 28 '23 14:06 marckleinebudde

I apologize for the delay, here are the logs for both the client and server, just in case. logs.tar.gz

Zosoworld avatar Jul 04 '23 01:07 Zosoworld

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.

marckleinebudde avatar Jul 04 '23 06:07 marckleinebudde

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.

marckleinebudde avatar Jul 04 '23 06:07 marckleinebudde