Hi Tom,
On 12/21/18 5:52 AM, Tom Evans wrote:
We've just found the cause of an intermittent CAN problem. It may be
instructive to others.
Our CAN code looks something like:
1) int skt = socket( PF_CAN, SOCK_RAW | SOCK_NONBLOCK, CAN_RAW );
...
2) int rc=ioctl(skt, SIOCGIFINDEX, &ifr); /* ifr.ifr_ifindex filled
... */
...
3) rc = bind(skt, (struct sockaddr*)&addr, sizeof(addr));
Here you introduce the problem :-)
...
4) rc = setsockopt(skt, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter,
sizeof(rfilter));
...
5) rc = recv(skt, &frame, sizeof(frame), MSG_DONTWAIT);
The Receive path assumes the Filter that was applied to the socket is
working.
That was a rookie mistake. It isn't.
We're receiving all sorts of garbage on the first few reads of the
socket. Messages that are being misinterpreted to make very bright
warning lights flash in all sorts of worrying and unexpected ways.
This is because the thread performing the above can get suspended
between when the socket is bound at (3), and when the filter is applied
at (4).
You are just using the wrong order on the syscalls!
When you created a socket you *first* apply the filters and other
options by setsockopt() and *then* bind the socket.
An example:
https://github.com/linux-can/can-utils/blob/master/cansend.c#L134
You can find that in candump.c too - but it's harder to find ;-)
It is also possible to change the filters on a bound socket - but you
always have to cope with some fall-out then.
When you bind the socket without setting a filter you get the default
filter == everything passes. Which finally creates the fall-out until
you set the new filter in your example above.
And during this time it is WIDE OPEN and will receive every message on
the CAN bus, every ID, Standard and Extended.
Just swap bind() & setsockopt() and you get what you wanted.
Have fun,
Oliver