SocketCAN: read() function never returns - socketcan

I am working on a custom embedded Linux system that needs to read and write messages on a CAN bus. SocketCAN is being used to accomplish this.
The CAN interface can0 is brought up on boot with a baudrate set to 500 kbps. I am using CANoe, cangen, and candump to test reception and transmission of messages. When CANoe is set to send messages to the embedded system, candump has no problem reading these messages on the embedded system. When cangen is set to send messages, CANoe has no problem reading the messages from the embedded system.
I wrote a small program to read messages from the can0 interface using the read() function. When the read() function is called to read a single CAN message, the function blocks and then never returns. I am certain that the CAN interface is receiving data since the number of received bytes reported by ifconfig increases as expected. Running candump concurrently with my program also shows that the interface is receiving CAN messages from the bus. Below is the relevant code for opening and reading the CAN interface. Error checking has been omitted.
Opening the socket:
int socketNum = 0;
char interface[10] = "can0";
struct sockaddr_can addr;
struct ifreq ifr;
memset(&addr, 0, sizeof(addr));
memset(&ifr, 0, sizeof(ifr));
socketNum = socket(PF_CAN, SOCK_RAW, CAN_RAW);
addr.can_family = AF_CAN;
strncpy(ifr.ifr_name, interface, sizeof(interface));
ioctl(socketNum, SIOCGIFINDEX, &ifr);
addr.can_ifindex = ifr.ifr_ifindex;
bind(socketNum, (struct sockaddr *)&addr, sizeof(addr));
Reading the socket:
struct can_frame frame;
int nbytes = 0;
memset(&frame, 0, sizeof(frame));
/* Never returns despite interface receiving messages */
nbytes = read(socketNum, &frame, sizeof(frame));
Am I missing something in my code or doing something wrong? Has anyone else encountered this issue and found a solution?

I have found a work-around for my issue.
The embedded platform I am working on uses an IMX 8 and an NXP driver for the FLEXCAN IP. My device tree is setup with the disable-fd-mode option. Even though FD mode should be disabled, I am required to "enable" FD mode with setsockopt:
canfd_enabled = 1;
error_code = setsockopt(socketNum, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_enabled, sizeof(int));
After adding these lines of code I can read and write from the socket as expected. I also read and write up to sizeof(canfd_frame) bytes instead of sizeof(can_frame) bytes. It is likely there is something wrong with the FLEXCAN driver. In my experience, this is not unusual for NXP drivers.

I also had this problem, using a Colibri iMX6
The lines of code which worked for me were:
int canfd_enabled = 1;
int error_code;
error_code = setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_enabled, sizeof(int));
nbytes = read(s, &frame, sizeof(struct can_frame));
Thanks Dschumanji!

Related

Raw sockets in C, isn't connect redundant?

I'm writing a simple program that creates an ethernet I frame and sends it through an interface to the specified MAC.
As i have read, the process for connecting to a socket in UNIX goes a bit like:
int sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
struct sockaddr_ll sll;
/* populate sll with the target and interface info */
connect(sockfd, (struct sockaddr*)&sll, sizeof(sll));
write(sockfd, stuff, sizeof(stuff));
close(sockfd)
The thing is, for me, stuff is a valid eth frame already containing everything needed to send a packet to its destination. Isn't the connect step redundant then? What am I missing?
Have a nice day.
Not only is the connect "redundant", it is an error -- according to the Linux man page:
The connect(2) operation is not supported on packet sockets.
So the connect is probably failing but not actually doing anything. Since you ignore the return value of connect, you don't notice the failure.
As stated above, the connection step was wrong.
I will give the details of how i solved it in this post in case anyone in need sees this: (this is as i understood it, feel free to correct me)
For a trully raw communication in userspace you have to understand three concepts:
Sockets are analogous to file descriptors.
Binding a socket is like opening a file.
You can not read or write to a socket, just kindly ask the kernel to do it for you.
The process i followed is as follows:
int sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
struct sockaddr_ll sll;
sll.sll_family = AF_PACKET;
sll.sll_ifindex = index; //This is the index of your network card
//Can be obtained through ioctl with SIOCGIFINDEX
sll.sll_protocol = htons(ETH_P_ALL);
bind(sockfd, (struct sockaddr*)&sll, sizeof(sll));
size_t send_len = write(sockfd, data, size);
As you can see, we dont really use connect, as it was, indeed, a mistake.
p.s. for a full example: https://github.com/TretornESP/RAWRP

Raw socket bound to device not receiving all packets

I have a raw socket set up bound to a device that is already in promiscuous mode:
int sock = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);
if(sock == -1)
{
return -1;
}
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_ifrn.ifrn_name, "eth0", IFNAMSIZ);
if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0)
{
close(sock);
return -2;
}
while(1) {
packet_size = recvfrom(sock , buffer , 65536 , 0 , NULL, NULL);
// packet processing...
}
And my issue is that I am only receiving packets on my socket with IP destination matching the IP of the device (eth0) I am bound to. How can I receive all the TCP packets that the device is receiving? I can see all the TCP packets on the device in Wireshark, but the only packets that I see in my raw socket are those addressed to the device IP.
The reason of receiving packets directed only to IP of your device is that you are using PF_INET raw socket. When PF_INET raw socket is used - skb faces different sanity checks when goes across the stack (see below).
F.e. :
int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{
/*...*/
/* When the interface is in promisc. mode, drop all the crap
* that it receives, do not try to analyse it.
*/
if (skb->pkt_type == PACKET_OTHERHOST)
goto drop;
So the call trace is something like: __netif_receive_skb_core()->ip_rcv()->...->ip_local_deliver()->...->raw_local_deliver()->raw_rcv()->...->tcp_rcv() (you can check trace through the trace-cmd).
But tcpdump/Wireshark obtains packets around __netif_receive_skb_core(), i.e. before some sanity checks. Hence is discrepancy that confused you.
Therefore if you want skb's to bypass a large part of Linux kernel network stack - you should use PF_PACKET raw sockets.
Useful link

Cannot sniff UDP packets in C without Wireshark running

I have a setup that looks like this:
Target ---- Switch ---- Switch ---- Windows computer
|
Linux computer
So I have a target connected to a switch it sends out UDP-packets for debug purpose. Normally these packets goes to a Windows computer for analysis, this works. I have now added a Linux computer as well, to get the same data to both Linux and Windows I have setup a managed switch to mirror the traffic, this works fine when I look in Wireshark. I have then written a simple C-application for analysing the data on the Linux computer, this software does only work if Wireshark is running at the same time. Otherwise it does not receive any data from the target. Why is this?
int main()
{
int saddr_size, data_size;
struct sockaddr saddr;
unsigned char *buffer = (unsigned char *) malloc(BUFFER_SIZE);
printf("Starting...\n");
int sock_raw = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sock_raw < 0)
{
printf("Socket Error");
return 1;
}
while (1)
{
saddr_size = sizeof saddr;
data_size = recvfrom(sock_raw, buffer, BUFFER_SIZE, 0, &saddr, (socklen_t*) &saddr_size);
if (data_size < 0)
{
printf("Recvfrom error , failed to get packets\n");
return 1;
}
processPacket(buffer);
}
close(sock_raw);
printf("Finished");
return 0;
}
The data coming from the target are sent on a format similar to RTP and is addressed to the Windows computer.
So to sum up; Why do I not receive any data from the target in my C-application without Wireshark running?
Same as here, you need to put the interface (not socket as I originally posted) into promiscuous mode. Wireshark does that, which is why your code works when Wireshark is running.
Just a guess: promiscuous mode is not turned on and the ethernet controller is discarding frames not addressed to it.

What is the BSD (or portable) way to get ToS byte (like IP_RECVTOS from linux)?

What is the right (portable, stable) way to get the ToS byte of a received packet? I'm doing UDP with recvmsg() and on linux I can get the ToS if I setsockopt() IP_RECVTOS/IPV6_RECVTCLASS, but IP_RECVTOS doesn't seem to be available on my BSD systems. What is the right way to do this?
I primarily want this to work on the BSDs and Solaris.
Edit:
To clarify:
I currently use recvmsg() where I get the TTL and TOS in the msg_control field on Linux, but in order to get TTL and TOS I need to setsockopt()-enable IP_RECVTTL and IP_RECVTOS. And since Solaris and BSD (working with FreeBSD at the moment) don't have IP_RECVTOS from what I can see I don't get TOS when looping over the CMSG data.
I tried enabling IP_RECVOPTS and IP_RECVRETOPTS, but I still don't get any IP_TOS type CMSG.
Edit 2:
I want ToS to be able to verify (as much as possible) that it wasn't overwritten in transit. If for example a VoIP app all of a sudden notices that it's not getting EF tagged packets, then something is wrong and there should be an alarm. (and no, I'm not expecting EF to be respected or preserved over the public internet)
I want TTL basically just because I can. Hypothetically this could be used to trigger "something changed in the network between me and the other side" alerts, which can be useful to know if somethings stops working at the same time.
I was thinking if you can create two sockets.
One socket of type DGRAM used exclusively for sending
One Raw socket used exclusively for receiving.
Since you are using UDP, you can call a bind + recvFrom on the Raw Sock Fd and then manually unpack the IP header to determine the TOS or TTL.
When you want to send, use the DGRAM sockFd so you dont have to bother to actually create the UDP & IP packet yourself.
There may be issues like the kernel may pass the received buffer to both sockets or to the UDP socket instead of Raw socket or just to the Raw socket. If that is the case (or if it is implementation dependent) then we are back to square one. However, you can try calling bind on the Raw socket and see if it helps. I am aware this maybe a hack but searching on the net for a setsockopt for BSD returned nothing.
EDIT: I wrote a sample program
It kind of achieves the objective.
The code below creates two sockets (one raw & one udp). The udp socket is bound on the actual port I am expecting to receive data whereas the raw socket is bound on Port 0. I tested this on Linux and like I expected any data for port 2905 is received by both the sockets. I am however able to retrieve the TTL & TOS values. Dont downvote for the quality of the code. I am just experimenting whether it will work.
Further EDIT: Disabled the receive by UDP socket.
I have further enhanced the code to disable the receive by the UDP packet. Using setsockopt, I set the UDP's socket receive buffer to 0. This ensures the kernel does not pass the packet to the UDP socket. IMHO,You can now use the UDP socket exclusively for sending and the raw socket for reading. This should work for you in BSD and Solaris also.
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<arpa/inet.h>
#include<string.h>
#include "protHeaders.x"
#include "gen.h"
int main(void)
{
S32 rawSockFd;
S32 udpSockFd;
struct sockaddr_in rsin;
struct sockaddr_in usin;
S32 one = 1;
const S32* val = &one;
struct timeval tv;
fd_set rfds;
S32 maxFd;
S16 ret;
S8 rawBuffer[2048];
S8 udpBuffer[2048];
struct sockaddr udpFrom,rawFrom;
socklen_t rLen,uLen;
memset(rawBuffer,0,sizeof(rawBuffer));
memset(udpBuffer,0,sizeof(udpBuffer));
memset(udpFrom,0,sizeof(udpFrom));
memset(rawFrom,0,sizeof(rawFrom));
if ((rawSockFd = socket(PF_INET,SOCK_RAW,IPPROTO_UDP)) < 0)
{
perror("socket:create");
RETVALUE(RFAILED);
}
/* doing the IP_HDRINCL call */
if (setsockopt(rawSockFd,IPPROTO_IP,IP_HDRINCL,val,sizeof(one)) < 0)
{
perror("Server:setsockopt");
RETVALUE(RFAILED);
}
rsin.sin_family = AF_INET;
rsin.sin_addr.s_addr = htonl(INADDR_ANY);
rsin.sin_port = htons(0);
usin.sin_family = AF_INET;
usin.sin_addr.s_addr = htons(INADDR_ANY);
usin.sin_port = htons(2905);
if(bind(rawSockFd,(struct sockaddr *)&rsin, sizeof(rsin)) < 0 )
{
perror("Server: bind failed");
RETVALUE(RFAILED);
}
if ((udpSockFd = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP)) < 0)
{
perror("socket:create");
RETVALUE(RFAILED);
}
if(bind(udpSockFd,(struct sockaddr *)&usin, sizeof(usin)) < 0 )
{
perror("Server: bind failed on udpsocket");
RETVALUE(RFAILED);
}
/*set upd socket receive buffer to 0 */
one = 0;
if (setsockopt(udpSockFd,SOL_SOCKET,SO_RCVBUF,(char *)&one,sizeof(one)) < 0)
{
perror("Server:setsockopt on udpsocket failed");
RETVALUE(RFAILED);
}
tv.tv_sec = 0;
tv.tv_usec = 0;
maxFd = (rawSockFd > udpSockFd)? rawSockFd:udpSockFd;
while(1)
{
FD_ZERO(&rfds);
FD_SET(rawSockFd,&rfds);
FD_SET(udpSockFd,&rfds);
ret = select(maxFd+1,&rfds,0,0,&tv);
if ( ret == -1)
{
perror("Select Failed");
RETVALUE(RFAILED);
}
if(FD_ISSET(rawSockFd,&rfds))
{
printf("Raw Socked Received Message\n");
if(recvfrom(rawSockFd,rawBuffer,sizeof(rawBuffer),0,&rawFrom,&rLen) == -1)
{
perror("Raw socket recvfrom failed");
RETVALUE(RFAILED);
}
/*print the tos */
printf("TOS:%x\n",*(rawBuffer+1));
printf("TTL:%x\n",*(rawBuffer+8));
}
if(FD_ISSET(udpSockFd,&rfds))
{
printf("UDP Socked Received Message\n");
if(recvfrom(udpSockFd,udpBuffer,sizeof(udpBuffer),0,&udpFrom,&uLen) == -1)
{
perror("Udp socket recvfrom failed");
RETVALUE(RFAILED);
}
printf("%s\n",udpBuffer);
}
}
RETVALUE(ROK);
}
The "proper" and standard solution is probably to use cmsg(3). You'll find a complete description in Stevens' "Unix network programming" book, a must-read.
Google Code Search found me this example of use.
My understanding is that firstly BSD does not support IP_RECVTOS like functionality and secondly BSD raw sockets do not support the reception of UDP nor TCP packets. However there are two other ways of doing this, firstly by using the /dev/bpf interface - either directly or via libpcap. Or secondly by using DIVERT sockets which allow for diversion of specified traffic flows to userland.
Has anyone actually tested the code above on a BSD box? (it may work on Solaris...)
On Linux this approach will work but as mentioned it is also possible (and more convenient) to use setsockopt() with IP_TOS on the outgoing socket to set the outgoing TOS byte and setsockopt() with IP_RECVTOS on the incoming socket and use recvmsg() to retrieve the TOS byte.
Unfortuneatly this sort of thing usually varies across different *ixs. On Solaris you want to use getsockopt with IP_TOS; I don't know about BSD.
See man 7 ip for details.

Reading from a promiscuous network device

I want to write a real-time analysis tool for wireless traffic.
Does anyone know how to read from a promiscuous (or sniffing) device in C?
I know that you need to have root access to do it. I was wondering if anyone knows what functions are necessary to do this. Normal sockets don't seem to make sense here.
On Linux you use a PF_PACKET socket to read data from a raw device, such as an ethernet interface running in promiscuous mode:
s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))
This will send copies of every packet received up to your socket. It is quite likely that you don't really want every packet, though. The kernel can perform a first level of filtering using BPF, the Berkeley Packet Filter. BPF is essentially a stack-based virtual machine: it handles a small set of instructions such as:
ldh = load halfword (from packet)
jeq = jump if equal
ret = return with exit code
BPF's exit code tells the kernel whether to copy the packet to the socket or not. It is possible to write relatively small BPF programs directly, using setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, ). (WARNING: The kernel takes a struct sock_fprog, not a struct bpf_program, do not mix those up or your program will not work on some platforms).
For anything reasonably complex, you really want to use libpcap. BPF is limited in what it can do, in particular in the number of instructions it can execute per packet. libpcap will take care of splitting a complex filter up into two pieces, with the kernel performing a first level of filtering and the more-capable user-space code dropping the packets it didn't actually want to see.
libpcap also abstracts the kernel interface out of your application code. Linux and BSD use similar APIs, but Solaris requires DLPI and Windows uses something else.
I once had to listen on raw ethernet frames and ended up creating a wrapper for this. By calling the function with the device name, ex eth0 I got a socket in return that was in promiscuous mode.
What you need to do is to create a raw socket and then put it into promiscuous mode. Here is how I did it.
int raw_init (const char *device)
{
struct ifreq ifr;
int raw_socket;
memset (&ifr, 0, sizeof (struct ifreq));
/* Open A Raw Socket */
if ((raw_socket = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 1)
{
printf ("ERROR: Could not open socket, Got #?\n");
exit (1);
}
/* Set the device to use */
strcpy (ifr.ifr_name, device);
/* Get the current flags that the device might have */
if (ioctl (raw_socket, SIOCGIFFLAGS, &ifr) == -1)
{
perror ("Error: Could not retrive the flags from the device.\n");
exit (1);
}
/* Set the old flags plus the IFF_PROMISC flag */
ifr.ifr_flags |= IFF_PROMISC;
if (ioctl (raw_socket, SIOCSIFFLAGS, &ifr) == -1)
{
perror ("Error: Could not set flag IFF_PROMISC");
exit (1);
}
printf ("Entering promiscuous mode\n");
/* Configure the device */
if (ioctl (raw_socket, SIOCGIFINDEX, &ifr) < 0)
{
perror ("Error: Error getting the device index.\n");
exit (1);
}
return raw_socket;
}
Then when you have your socket you can just use select to handle packets as they arrive.
You could use the pcap library (see http://www.tcpdump.org/pcap.htm) which is also used by tcpdump and Wireshark.
Why wouldn't you use something like WireShark?
It is open source, so at least you could learn a few things from it if you don't want to just use it.
WireShark on linux has the capability to capture the PLCP (physical layer convergence protocol) header information.

Resources