RFC: PF_CAN (SocketCAN-compatible) network stack for FreeBSD

Vladimir Goncharov <[email protected]> Mon, 29 Jun 2026 20:03:37 +0700
Newsgroups gmane.os.freebsd.devel.net
Message-ID <[email protected]>
Hello,

I'd like to introduce a Controller Area Network (CAN) socket stack I have
been developing for FreeBSD, and ask for guidance on bringing it upstream.
This would be my first contribution to FreeBSD, so I would genuinely
appreciate help with the process as well as with any design concerns.

Motivation
----------
CAN bus is everywhere in automotive, industrial and embedded systems, but
FreeBSD has no CAN support today.  The goal of this work is a PF_CAN/AF_CAN
socket family that is source-compatible with the Linux SocketCAN API, so
that existing CAN software (can-utils, libsocketcan, and custom raw-CAN
applications) builds and runs on FreeBSD with at most a recompile.

What is implemented
-------------------
- A new PF_CAN protocol family with CAN_RAW sockets.  The architecture is
   ported from NetBSD's sys/netcan, but every application-visible interface
   (option level SOL_CAN_RAW, the option numbers, and the frame and filter
   layouts) is re-aligned to the Linux SocketCAN UAPI rather than NetBSD's,
   for source portability.
- Classic CAN and CAN FD frames; per-socket acceptance filters (including
   inverted and error-frame filters), CAN_RAW_LOOPBACK, 
CAN_RAW_RECV_OWN_MSGS,
   CAN_RAW_JOIN_FILTERS and CAN_RAW_FD_FRAMES, with Linux-compatible local
   loopback semantics.
- vcan(4), a virtual (loopback) CAN interface.
- slcan(4) + slcand(8): a userspace bridge for serial-line CAN ("slcan" /
   Lawicel) adapters, with an optional TCP transport.  FreeBSD has no 
N_SLCAN
   line discipline, so this lives in userspace over a cdev-backed interface.
- BPF capture (DLT_CAN_SOCKETCAN); tcpdump works.
- A real hardware driver: mcp2515(4) for the Microchip MCP2515 SPI CAN
   controller (classic CAN).
- ATF tests (tests/sys/netcan) and man pages (can.4, vcan.4, slcan.4,
   slcand.8).

It is about 4,600 lines across six commits (AF_CAN constant; netcan core;
ATF tests; slcand; an rk_spi fix; the mcp2515 driver).

Status
------
Built and tested on 16-CURRENT/aarch64, both as a loadable module and built
statically (options CAN). It is hardware-proven: on a SOQuartz (RK3566),
CAN frames flow both directions between a physical MCP2515 on SPI and a
second CAN node (FreeBSD VM with CAN bridge over slcan/TCP). CAN FD
mode is not hardware proven yet, I'm waiting for MCP2518FD boards.

The series also includes one small, CAN-independent fix: the Rockchip rk_spi
controller did not relay bus resources/interrupts to its parent, so an SPI
child with a GPIO interrupt could not allocate its IRQ.

Provenance and licensing
-------------------------
- The netcan-derived kernel code keeps the NetBSD Foundation BSD-2-Clause
   notice (originally contributed by Robert Swindells and Manuel Bouyer).
- The UAPI headers are derived from the Linux SocketCAN headers and carry
   Volkswagen's copyright; those are dual GPL-2.0-only OR BSD-3-Clause, 
and I
   use them under the BSD-3-Clause option.
- New code is BSD-2-Clause.

Try it
------
I have written a step-by-step guide -- building the kernel/module, modifying
and wiring a low-cost MCP2515 module (it needs a small 3.3V mod, 
described in
the repo), and running live traffic -- here:

     https://github.com/cleverfox/freebsd_canbus

A reader should be able to reproduce the setup and exercise CAN end to end.

The complete change series (six commits on top of a recent main) is on a
branch, for reading or fetching:

     https://github.com/cleverfox/freebsd-src  (branch: canbus)

I'm going to post it for review on Phabricator (reviews.freebsd.org);
the GitHub branch is just a convenience until then.

Not yet done / future work
--------------------------
- Linux-compatible netlink link configuration (IFLA_CAN_* bit timing, etc.);
   bitrate is currently a driver sysctl.
- Other SocketCAN protocols (BCM, ISO-TP, J1939)
- CAN FD controller driver (MCP2518FD).

What I am asking
----------------
1. My goal is to land this in the base system.  Is that the right target, or
    would the project prefer it begin as a port / out-of-tree first?
2. As a first-time contributor I plan to post this on Phabricator.  
Would you
    prefer a single review, or a stack split by layer (socket.h / netcan 
core /
    vcan / slcan+slcand / tests / mcp2515 driver)?
3. Would anyone familiar with the socket/protosw and VNET KPIs be willing to
    review or mentor?  I modelled the locking on rtsock.c (a global pcb-list
    mutex plus per-socket locks, with a netisr input path) and would 
like to be
    sure that and the VNET integration are idiomatic.
4. Any concerns to address up front -- for example the AF_CAN/PF_CAN 
constant
    allocation, or the decision to track the Linux UAPI rather than 
NetBSD's?

I am happy to revise as needed and to keep the changes small and reviewable.
Thank you for reading, and for any pointers.

Best regards,
Vladimir Goncharov