2024-02-20T09:03:15+00:00
My self hosted webserver comes with a Realtek 8723a SDIO Wi-Fi card which doesn’t work with linux-image-current-rockchip that comes with Armbian. So instead of getting my hands dirty on fixing the 8723bs driver to support 8723a inside my box, I went out to buy a usb wi-fi dongle.
Luckily, the usb wi-fi dongle works on kernel 6.1.x with some limitation: the displayed signal strength status is not so great. So, I switch to enable Armbian beta apt repository to get more recent kernel for my box.
Sometimes, or somewhat often, the wi-fi dongle doesn’t work after a system restart or a cold boot. The kernel message says that there is a failure during firmware loading of the usb wi-fi dongle.
In this situation, to access my box, I plugged in my Android phone
and chose USB Tethering
to access the box via ssh. I find
the ip address of the box via ip neigh
command and use the
ip address shown to access the box via ssh. This is possible since there
is NetworkManager
running on Armbian and it is listening to
hotplug event. When the USB Tethering
is activated on
Android, the udev
subsystem of the linux kernel will inform
NetworkManager
and the daemon will issue a dhcp request to
the Android host. The Android tethering host will respond with an ip
address for the requesting client. This works very well for my recovery
when the wi-fi dongle doesn’t come up, so I can still access my box
without resorting to serial console or preparing a keyboard and monitor
for pc like access.
When facing with this situation, I pulled the usb dongle from the box usb port, wait a few seconds, and put the dongle back in another port. I tried this a few times and sometimes the wi-fi dongle comes up. With the same trick on another occasion, the wi-fi dongle doesn’t come up as I intended.
With this rought treatment, I began to think that may be a usb port
could get loose
or getting degraded. So I began to think
about solution to toggle the usb port power off and toggling back to on
to simulate usb removal.
There are ways to achieve this. The first is using kernel sysfs
interface. The other is using a program that talks to usb devices, such
as uhubctl
.
So I installed uhubctl
and tried to run it manually when
the rtl8xxxu
driver get a failure during firmware load.
until ip link | grep wl ; do
sudo uhubctl -s 0bda:8179 -a 2 ; sleep 3
done
The above command will run ip link
command. If it
doesn’t detect an interface with wl
prefix, the usb port
will be power-cycled. In this situation, I limit the action for the
vendor id and device id of the usb wi-fi dongle
(0bda:8179
). After some tries, the wi-fi link comes up and
connected to the wi-fi network that has been configured before.
Instead of resorting to USB tethering
access, I created
a systemd service to check for the presence of 0bda:8179
usb device (the wi-fi dongle) and perform power-cycle repeat when the
wlan0
interface is not found.
Here is the
/etc/systemd/system/toggle-usb-wifi-port.service
file that
performs the action described above.
[Unit]
Description=Reset USB port to load realtek wifi dongle
After=network.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/sh /usr/local/sbin/toggle-usb-port.sh
[Install]
WantedBy=multi-user.target
Here is the content of toggle-usb-port.sh
script.
#!/bin/sh
WIFI_DEVICE="0bda:8179"
if ! uhubctl -s "$WIFI_DEVICE" ; then
echo "No Realtek Wi-Fi dongle is connected."
exit 0
fi
sleep 2
until ip link | grep wl ; do
uhubctl -s "$WIFI_DEVICE" -a 2 ; sleep 3
done
Afterwards, I enabled the systemd unit after reloading systemd.
sudo systemctl daemon reload
sudo systemctl enable toggle-usb-wifi-port.service
With this workaround, I feel somewhat confident that the wi-fi dongle will come up after a cold boot or after a system reboot.
Very convenient.
I am thinking about integrating the action with udev so the link
check will be performed even after the system is fully booted and the
wi-fi is inserted later. The proposed
/etc/udev/rules.d/99-realtek-dongle.rules
is as
follows.
SUBSYSTEM=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="8179", RUN+="/usr/bin/systemctl start toggle-usb-wifi-port.service"
The udev integration is not tested, so it is not guaranteed to work.
Update: I’ve added RemainAfterExit=yes
property to the
systemd unit so the toggle wi-fi script is not executed continuously to
prevent race condition. The udev integration is an alternative to start
the toggling process without enabling the
toggle-usb-wifi.service
.
Update: I removed the [Install]
section of the systemd
service and used the udev
subsystem to trigger the usb
toggling whenever the usb wifi dongle is detected. While it works, it
took some time for the wireless interface to become available.
With these workarounds, I hope the self hosted webserver will be more reliable in case there is a need of a system reboot or coming up after an unplanned power outage. Feel free to follow this guide to fix similar issue with usb devices that needs replugging such as my Realtek usb wi-fi dongle.
Update: Got another problematic usb dongle from the same chipset manufacturer with similar workaround.
Thanks for reading this page.