Protocols / CAN

Examples

Linux talks CAN through SocketCAN: the interface behaves like a network device (can0), and frames are sent with ordinary socket() calls using the AF_CAN address family — not a character device like spidev or i2c-dev.

Bringing the interface up

# set the bitrate and bring the interface up (needs CAP_NET_ADMIN)
sudo ip link set can0 type can bitrate 500000
sudo ip link set can0 up

# for CAN FD, also set a data-phase bitrate
sudo ip link set can0 type can bitrate 500000 dbitrate 2000000 fd on
sudo ip link set can0 up

Command-line send and receive — can-utils

# watch every frame arriving on can0
candump can0

# send a frame with ID 0x123 and 3 data bytes
cansend can0 123#AABBCC

# send a CAN FD frame (## instead of #, with flags)
cansend can0 123##1AABBCCDDEEFF0011

C — sending a frame with SocketCAN

#include <linux/can.h>
#include <linux/can/raw.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/socket.h>

int s = socket(PF_CAN, SOCK_RAW, CAN_RAW);

struct ifreq ifr;
strcpy(ifr.ifr_name, "can0");
ioctl(s, SIOCGIFINDEX, &ifr);

struct sockaddr_can addr = {0};
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
bind(s, (struct sockaddr *)&addr, sizeof(addr));

struct can_frame frame = {0};
frame.can_id = 0x123;
frame.can_dlc = 3;
frame.data[0] = 0xAA;
frame.data[1] = 0xBB;
frame.data[2] = 0xCC;

write(s, &frame, sizeof(frame));

C — receiving frames

struct can_frame frame;
while (1) {
    int nbytes = read(s, &frame, sizeof(frame));
    if (nbytes < 0) continue;

    printf("id=0x%03X dlc=%d data=", frame.can_id, frame.can_dlc);
    for (int i = 0; i < frame.can_dlc; i++)
        printf("%02X ", frame.data[i]);
    printf("\n");
}
What I learned

Because SocketCAN treats can0 as a network interface, the usual network debugging habits apply directly — ip -details link show can0 shows the bus state (error-active/passive/bus-off) and bitrate, and a bus-off interface needs the link cycled down and back up to recover, the same shape as recovering a jammed Ethernet link.