Skip to content

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 typeProtocolTypical use
SOCK_RAWCAN_RAWSending and receiving raw CAN frames; the most common option
SOCK_DGRAMCAN_BCMBroadcast Manager functions such as cyclic transmission
SOCK_SEQPACKETCAN_ISOTPISO-TP transport for diagnostic communication

Data Structures

CAN 2.0 frame:

c
#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:

c
#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:

c
#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

c
#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

bash
# 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.c

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

c
/* 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:

bash
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 can0

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

c
/* 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:

bash
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 can0

SDK 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

References

Driving Intelligent Connections, Empowering the Future