SocketCAN Programming Guide
Programming Fundamentals
SocketCAN Architecture
SocketCAN integrates the CAN bus into the Linux networking subsystem. Applications can therefore communicate over CAN through the standard Socket API instead of a device-specific API.
Core Concepts
Socket Types
SocketCAN uses the PF_CAN protocol family and supports several socket types:
| Socket type | Protocol | Typical use |
|---|---|---|
SOCK_RAW | CAN_RAW | Sending and receiving raw CAN frames; the most common option |
SOCK_DGRAM | CAN_BCM | Broadcast Manager functions such as cyclic transmission |
SOCK_SEQPACKET | CAN_ISOTP | ISO-TP transport for diagnostic communication |
Data Structures
CAN 2.0 frame:
#include <linux/can.h>
struct can_frame {
canid_t can_id; /* 32-bit CAN ID plus EFF/RTR/ERR flags */
__u8 can_dlc; /* Payload length: 0-8 bytes */
__u8 __pad; /* Padding */
__u8 __res0; /* Reserved */
__u8 __res1; /* Reserved */
__u8 data[8] __attribute__((aligned(8)));
};CAN FD frame:
#include <linux/can.h>
struct canfd_frame {
canid_t can_id; /* 32-bit CAN ID plus EFF/RTR/ERR flags */
__u8 len; /* Payload length: 0-64 bytes */
__u8 flags; /* CAN FD flags such as BRS and ESI */
__u8 __res0; /* Reserved */
__u8 __res1; /* Reserved */
__u8 data[64] __attribute__((aligned(8)));
};CAN ID flags and masks:
#define CAN_EFF_FLAG 0x80000000U /* Extended frame: 29-bit ID */
#define CAN_RTR_FLAG 0x40000000U /* Remote transmission request */
#define CAN_ERR_FLAG 0x20000000U /* Error frame */
#define CAN_SFF_MASK 0x000007FFU /* Standard 11-bit ID mask */
#define CAN_EFF_MASK 0x1FFFFFFFU /* Extended 29-bit ID mask */Development Environment
Required Headers
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>Compilation
# Compile a CAN application
gcc -o can_app can_app.c
# Link an additional library when required
gcc -o can_app can_app.c -lpthread
# Include debugging information
gcc -g -o can_app can_app.cComplete Examples
Example 1: Basic CAN Transmit and Receive
The following program is complete and directly compilable. It binds to a CAN interface, transmits one classic CAN frame, and waits for one frame to be received.
/* can_basic.c - basic CAN transmit and receive example */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
int main(int argc, char *argv[])
{
int s;
struct sockaddr_can addr;
struct ifreq ifr;
struct can_frame frame;
int nbytes;
if (argc != 2) {
fprintf(stderr, "Usage: %s <CAN interface>\n", argv[0]);
fprintf(stderr, "Example: %s can0\n", argv[0]);
return 1;
}
/* 1. Create a raw CAN socket. */
s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (s < 0) {
perror("Failed to create socket");
return 1;
}
/* 2. Look up the selected CAN interface. */
strncpy(ifr.ifr_name, argv[1], IFNAMSIZ - 1);
ifr.ifr_name[IFNAMSIZ - 1] = '\0';
if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
perror("Failed to get interface index");
close(s);
return 1;
}
/* 3. Bind the socket to the interface. */
memset(&addr, 0, sizeof(addr));
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("Failed to bind socket");
close(s);
return 1;
}
printf("Bound to interface %s\n", argv[1]);
/* 4. Build and transmit a classic CAN frame. */
memset(&frame, 0, sizeof(frame));
frame.can_id = 0x123;
frame.can_dlc = 8;
frame.data[0] = 0x11;
frame.data[1] = 0x22;
frame.data[2] = 0x33;
frame.data[3] = 0x44;
frame.data[4] = 0x55;
frame.data[5] = 0x66;
frame.data[6] = 0x77;
frame.data[7] = 0x88;
nbytes = write(s, &frame, sizeof(frame));
if (nbytes != sizeof(frame)) {
perror("Failed to transmit CAN frame");
close(s);
return 1;
}
printf("Sent CAN frame: ID=0x%03X DLC=%d\n",
frame.can_id, frame.can_dlc);
/* 5. Wait for a CAN frame. */
printf("Waiting for a CAN frame...\n");
nbytes = read(s, &frame, sizeof(frame));
if (nbytes < 0) {
perror("Failed to receive CAN frame");
close(s);
return 1;
}
/* 6. Display the received frame. */
printf("Received CAN frame: 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");
close(s);
return 0;
}Compile and run:
gcc -o can_basic can_basic.c
# Configure and enable can0 first.
sudo ip link set can0 type can bitrate 500000
sudo ip link set can0 up
./can_basic can0Example 2: CAN FD Communication
This example enables CAN FD support, sends a 64-byte frame with bit-rate switching, and then waits for a CAN FD frame.
/* canfd_example.c - CAN FD transmit and receive example */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
int main(int argc, char *argv[])
{
int s;
struct sockaddr_can addr;
struct ifreq ifr;
struct canfd_frame frame;
int enable_canfd = 1;
int nbytes;
if (argc != 2) {
fprintf(stderr, "Usage: %s <CAN interface>\n", argv[0]);
return 1;
}
s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (s < 0) {
perror("Failed to create socket");
return 1;
}
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES,
&enable_canfd, sizeof(enable_canfd)) < 0) {
perror("Failed to enable CAN FD support");
close(s);
return 1;
}
strncpy(ifr.ifr_name, argv[1], IFNAMSIZ - 1);
ifr.ifr_name[IFNAMSIZ - 1] = '\0';
if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
perror("Failed to get interface index");
close(s);
return 1;
}
memset(&addr, 0, sizeof(addr));
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("Failed to bind socket");
close(s);
return 1;
}
printf("CAN FD mode enabled on %s\n", argv[1]);
memset(&frame, 0, sizeof(frame));
frame.can_id = 0x456;
frame.len = 64;
frame.flags = CANFD_BRS;
for (int i = 0; i < 64; i++) {
frame.data[i] = i;
}
nbytes = write(s, &frame, sizeof(frame));
if (nbytes != sizeof(frame)) {
perror("Failed to transmit CAN FD frame");
close(s);
return 1;
}
printf("Sent CAN FD frame: ID=0x%03X Length=%d Flags=0x%02X\n",
frame.can_id, frame.len, frame.flags);
printf("Waiting for a CAN FD frame...\n");
nbytes = read(s, &frame, sizeof(frame));
if (nbytes < 0) {
perror("Failed to receive CAN FD frame");
close(s);
return 1;
}
printf("Received CAN FD frame: ID=0x%03X Length=%d\n",
frame.can_id, frame.len);
printf("Data: ");
for (int i = 0; i < frame.len; i++) {
printf("%02X ", frame.data[i]);
if ((i + 1) % 16 == 0) {
printf("\n ");
}
}
printf("\n");
close(s);
return 0;
}Configure, compile, and run:
gcc -o canfd_example canfd_example.c
sudo ip link set can0 type can bitrate 1000000 dbitrate 5000000 fd on
sudo ip link set can0 up
./canfd_example can0SDK and Open-Source Examples
KH-UCANFD Linux SDK
The KH-UCANFD Linux SDK includes applications such as kcanfd_test.c and cantx_1KHz.c. They demonstrate socket creation, CAN FD socket options, transmission, reception, and error handling.
Download the latest KH-UCANFD Linux SDK
can-utils
The utilities in can-utils are implemented on top of SocketCAN and provide useful reference implementations for common CAN tasks.
View the can-utils source code
openarmcan
openarmcan is part of the OpenArm project. It provides a CAN communication library plus motor-oriented applications and test programs.
View the openarmcan source code