SocketCAN on WSL: USB CAN adapters from Windows
A practice note this week for developers who have been married off to a Windows® machine by their IT department and still want to develop and pre-test their hardware-in-the-loop (HIL) bench scripts locally before deploying to the actual Linux® HIL: SocketCAN under WSL2 works. The Linux kernel needs to be rebuilt, but after that the full SocketCAN toolchain runs locally on the Windows host, identical to the target platform.
I would explicitly not want to replace the production HIL with this setup. The USB chain through usbipd-win is too fragile for continuous operation. But as a development and pre-test environment, with the same toolchain as on the target, it is gold.
SocketCAN, briefly
SocketCAN has been part of the Linux kernel since around 2008 and treats CAN buses like any other network interface: can0, vcan0, ip link, tcpdump, a clean socket API in C or Python. The can-utils package (github.com/linux-can/can-utils →) brings candump, cansend, cangen, canplayer, cangw, all in the style familiar from tcpdump and iproute2. Anyone who has ever pointed Wireshark at CAN knows how comfortable the bus reads from this angle.
Adapter landscape
What surprised during the search: the breadth of supported hardware. Off the top of my head:
- PEAK PCAN-USB family (peak_usb)
- Kvaser USB adapters (kvaser_usb)
- ESD USB CAN interfaces (esd_usb2)
- 8devices USB2CAN (gs_usb)
- Innomaker USB2CAN (gs_usb)
- Lawicel CANUSB and SLCAN compatible adapters (slcan)
- MCP2515 SPI controllers (on Raspberry Pi® or other Linux hosts with SPI)
- CAN controllers in i.MX, STM32MP®, Renesas RZ and many other SoCs (m_can, flexcan, …)
Almost any adapter sold on the usual embedded shops has a matching Linux driver. When choosing, a quick look at drivers/net/can/usb/ in the kernel source gives certainty.
What you can safely ignore: many vendors also ship their own Linux drivers as a download, because that is the norm under Windows. On Linux you usually do not need them. The mainline kernel drivers already cover the devices, are maintained, integrate cleanly with SocketCAN, and avoid DKMS hassle. The vendor packages are mostly a habit imported from the Windows world, where each device ships with its own driver.
WSL2: usbipd-win and a custom kernel
Tested with Ubuntu under WSL2. The two hurdles:
1. USB passthrough. By default WSL2 sees no USB devices. The Microsoft open source tool usbipd-win forwards USB devices into the WSL instance. In an admin PowerShell on the Windows host:
usbipd list
usbipd bind --busid 4-1 # once per device, as admin
usbipd attach --wsl --busid 4-1
Inside WSL the device then shows up in lsusb.
Important: the passthrough is exclusive. As long as the device is attached to WSL, Windows no longer sees it. To use it from Windows again, run usbipd detach --busid 4-1, and it reappears in the Windows device manager.
2. CAN in the kernel. The stock WSL2 kernel does not enable the CAN modules. modprobe can fails, the drivers simply are not built. So: check out the WSL kernel source from Microsoft, adjust the config, build, point .wslconfig at the new kernel, restart.
In the WSL shell:
# Build essentials
sudo apt install -y build-essential flex bison libssl-dev libelf-dev bc dwarves
# WSL kernel source from GitHub
git clone --depth 1 https://github.com/microsoft/WSL2-Linux-Kernel.git
cd WSL2-Linux-Kernel
# Take the default config, then enable the CAN options
cp Microsoft/config-wsl .config
make menuconfig
In menuconfig enable at least these options:
CONFIG_CAN=y
CONFIG_CAN_RAW=y
CONFIG_CAN_BCM=y
CONFIG_CAN_VCAN=y
CONFIG_CAN_GS_USB=y # or CONFIG_CAN_PEAK_USB / CONFIG_CAN_KVASER_USB / ...
Then build and install:
make -j$(nproc)
make modules -j$(nproc)
sudo make modules_install
# Copy bzImage out to the Windows host
mkdir -p /mnt/c/Users/$USER/kernel
cp arch/x86/boot/bzImage /mnt/c/Users/$USER/kernel/
On the Windows host point .wslconfig (typically %USERPROFILE%\.wslconfig) at the new kernel:
[wsl2]
kernel=C:\\Users\\<user>\\kernel\\bzImage
Then restart WSL from a Windows PowerShell:
wsl --shutdown
Sounds like work, is routine: follow the steps, the kernel is built in under an hour. After that everything runs as on a native Linux:
sudo ip link set can0 up type can bitrate 500000
candump can0
Done.
What it actually buys
- Full Linux toolchain on Windows: candump, cansend, Wireshark with the CAN dissector, python-can as logging and replay pipeline, all without moving the development machine.
vcan0for tests without hardware: a virtual CAN interface that unit tests and stubs can run against. Saves the adapter in many iterations.- No more proprietary SDKs: if you were tied to vendor SDKs (PEAK PCAN-View, Kvaser CANlib, …) you can switch to the same open toolchain that later runs on the target as well.
For bench scripts that will later run on a Linux HIL, this is a pleasant day: the same toolchain on the developer laptop as on the HIL.
Side benefit: old USB to RS232 dongles under Windows 11
The same usbipd-win trick also rescues the old USB to RS232 dongles whose vendor drivers no longer work under Windows 11 (the classic case being the Prolific PL2303, for which Microsoft pulled driver support). Passed through to WSL with usbipd attach, the Linux kernel has known the FTDI and Prolific chips natively for ages. The dongle shows up in WSL as /dev/ttyUSB0 and just works. minicom, screen or pyserial talk to it normally.
The catch: whatever talks to the dongle has to live on the Linux side. A Windows tool that expects to see the serial port does not benefit, because the passthrough is exclusive.
Keywords: SocketCAN, WSL2, usbipd-win, CAN adapter Linux, can-utils, build Linux kernel, use CAN on Windows, Hardware in the Loop, PEAK PCAN, Kvaser USB, embedded CAN toolchain consulting, Embedded Consulting Switzerland
Planning CAN on a new embedded project, or replacing a legacy toolchain? We help with adapter choice, test pipeline setup and CI integration, from the Linux host side through to the embedded target.