Fixing wpa_supplicant’s systemd unit file

Created On:

I recently started to use wpa_supplicant on Ubuntu 21.10 to manage a USB WiFi adapter. I noticed that when the adapter was not attached to the computer during boot then the boot hangs for 90 seconds. systemd displays the following errors after 90 seconds and continues the boot.

sys-subsystem-net-devices-wlan0.device: Job sys-subsystem-net-devices-wlan0.device/start timed out.
Timed out waiting for device /sys/subsystem/net/devices/wlan0.
Dependency failed for WPA supplicant daemon (interface-specific version).
wpa_supplicant@wlan0.service: Job wpa_supplicant@wlan0.service/start failed with result 'dependency'.
sys-subsystem-net-devices-wlan0.device: Job sys-subsystem-net-devices-wlan0.device/start failed with result 'timeout'

I also noticed that after the boot was complete, inserting the adapter would not start wpa_supplicant until I manually started wpa_supplicant. Both of these issues comes from the Ubuntu provided wpa_supplicant systemd unit.

[Unit]
Description=WPA supplicant daemon (interface-specific version)
Requires=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device
Before=network.target
Wants=network.target

[Service]
Type=simple
ExecStart=/sbin/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -Dnl80211,wext -i%I

[Install]
Alias=multi-user.target.wants/wpa_supplicant@%i.service

The systemd unit at /lib/systemd/system/wpa_supplicant@.service

This systemd unit file allows me to write my configuration for the wlan0 device at /etc/wpa_supplicant/wpa_supplicant-wlan0.conf and enable wpa_supplicant for the device by running: systemctl enable wpa_supplicant@wlan0.

The two problems come from two different stanzas in the unit file. The first is the Requires= stanza.

Requires=sys-subsystem-net-devices-%i.device

According to the systemd man page:

If this unit gets activated, the units listed will be activated as well. If one of the other units fails to activate, and an ordering dependency After= on the failing unit is set, this unit will not be started. Besides, with or without specifying After=, this unit will be stopped if one of the other units is explicitly stopped.

During boot systemd attempts to activate sys-subsystem-net-devices-wlan0.device which is impossible when the device is not connected. By default systemd will wait 90 seconds in this case before moving on. Usually this is not a problem on it’s own but combined with the Alias= stanza.

Alias=multi-user.target.wants/wpa_supplicant@%i.service

This creates a hard dependency between the multi-user.target target and the service and unfortunately, the multi-user.target is the default target systemd boots into. Combined with the previous Requires= stanza this blocks completing booting for 90 seconds.

To fix these issues, a drop-in unit can remove the dependency on the multi-user.target and tie the lifecycle of the device and wpa_supplicant together.

[Unit]
Requires=
BindsTo=sys-subsystem-net-devices-wlan0.device

[Install]
Alias=
WantedBy=
WantedBy=sys-subsystem-net-devices-wlan0.device

The drop-in unit at /etc/systemd/system/wpa_supplicant@wlan0.service.d/override.conf

The combined BindsTo= and WantedBy= stanzas tie the lifecyles of the device and wpa_supplicant together. wpa_supplicant will only be started if the device is inserted, and will be stopped if the device is removed. Further the successful startup of wpa_supplicant is no longer required for boot, fixing the blocking boot problem.