Device: OnePlus 5 (oneplus-cheeseburger, msm8998)
Wi-Fi chip: WCN3990 (ath10k_snoc)
Kernel: linux-postmarketos-qcom-msm8998 (Linux 6.0.x)
OS: postmarketOS edge (Alpine edge + systemd)
All commands in this guide run directly on the device as root (via
doas sh or doas -s). The device is assumed to have a working internet
connection (e.g. via 2.4 GHz Wi-Fi or USB tethering).
No internet on the device? You can download files on a host PC and transfer them via
scpover USB networking (scp file user@172.16.42.1:/tmp/), then run the install commands on the device viassh user@172.16.42.1.
-
regulatory.db signature rejection -- the kernel only trusts the
sforsheesigning key, but Alpine edge ships awens-signed regdb. Without the fix,cfg80211refuses to load regulatory rules and 5 GHz channels are either missing or passive-scan only. -
Outdated WCN3990 board file --
firmware-oneplus-msm8998ships an olderboard-2.bin; replacing it with the one fromlinux-firmware-ath10kprovides better calibration data. -
NetworkManager defaults that can destabilize the link (powersave, MAC randomization, scan randomization).
The ath10k_snoc driver still experiences periodic firmware crashes on 5 GHz:
ath10k_snoc: failed to install key ... -110
qcom-q6v5-mss: fatal error received: ... wlan_process
ath10k_snoc: firmware crashed!
The driver recovers automatically, but the connection drops briefly each time. This is a deeper firmware/driver issue not solvable from userspace. The steps below bring you to the best known state for stability and for reporting upstream.
- postmarketOS edge installed and booting.
- Internet access on the device (2.4 GHz Wi-Fi, USB tethering, etc.).
- Root access via
doas.
Install required tools and create a working directory:
doas apk add wget tar zstd
mkdir -p /tmp/5ghz-fix && cd /tmp/5ghz-fixThe kernel config enforces signed regdb verification:
CONFIG_CFG80211_REQUIRE_SIGNED_REGDB=yCONFIG_CFG80211_USE_KERNEL_REGDB_KEYS=y
The built-in trusted key is sforshee: 00b28ddf47aef9cea7. Alpine edge
wireless-regdb (2024.01.23+) is signed by wens (a different upstream key),
so the kernel rejects it. The last sforshee-signed release is 2023.09.01.
Option A -- from kernel.org (always available):
cd /tmp/5ghz-fix
wget "https://mirrors.edge.kernel.org/pub/software/network/wireless-regdb/wireless-regdb-2023.09.01.tar.xz"
tar -xf wireless-regdb-2023.09.01.tar.xz
cp wireless-regdb-2023.09.01/regulatory.db regulatory.db
cp wireless-regdb-2023.09.01/regulatory.db.p7s regulatory.db.p7sOption B -- from Alpine v3.19 mirror (if still available):
cd /tmp/5ghz-fix
wget -O wireless-regdb.apk \
"https://dl-cdn.alpinelinux.org/alpine/v3.19/main/aarch64/wireless-regdb-2023.09.01-r0.apk"
tar -xOf wireless-regdb.apk lib/firmware/regulatory.db > regulatory.db
tar -xOf wireless-regdb.apk lib/firmware/regulatory.db.p7s > regulatory.db.p7ssha256sum regulatory.db regulatory.db.p7sExpected:
0a4abd7ae20d07bb70642937ccb2293a72a6504730eea45a698882599f586368 regulatory.db
bcd81aed039ea6b9b6f3726fbf26911a0caf4a5d894210e0fa2effb384d6b326 regulatory.db.p7s
doas install -m 0644 /tmp/5ghz-fix/regulatory.db /lib/firmware/regulatory.db
doas install -m 0644 /tmp/5ghz-fix/regulatory.db.p7s /lib/firmware/regulatory.db.p7sOn pmos,
/libis typically a symlink to/usr/lib, so both paths are covered by a single install.
doas rebootAfter reboot:
dmesg | grep -E 'cfg80211:.*(X\.509|regulatory)'Good -- you should see:
cfg80211: Loading compiled-in X.509 certificates for regulatory database
cfg80211: Loaded X.509 cert 'sforshee: 00b28ddf47aef9cea7'
Bad -- if you see this, the regdb was not replaced correctly:
cfg80211: loaded regulatory.db is malformed or signature is missing/invalid
Without this, the kernel defaults to country 00 (world regulatory) which
restricts 5 GHz channels.
echo "options cfg80211 ieee80211_regdom=CL" | doas tee /etc/modprobe.d/wifi-regdom.confReplace
CLwith your two-letter country code (e.g.US,DE,BR).
Reboot for the module parameter to take effect:
doas rebootVerify after reboot:
iw reg get | head -20You should see country CL: (or your code) in the global section with
5 GHz frequency ranges listed.
Note: If you are already associated with an AP that announces its own country code (e.g.
US), thephy#0section will show the AP's country instead of yours. This is normal -- the modprobe default only applies before association and as a fallback when the AP does not advertise a country. What matters is that it is notcountry 00(world regulatory).
firmware-oneplus-msm8998 ships /lib/firmware/ath10k/WCN3990/hw1.0/board-2.bin
but it is older than the version in linux-firmware-ath10k. The
linux-firmware-ath10k package ships its version as board-2.bin.zst
(compressed), which ath10k_snoc on this kernel does not decompress
automatically. We decompress it manually and install it.
doas apk add linux-firmware-ath10kcd /tmp/5ghz-fix
zstd -d -f /lib/firmware/ath10k/WCN3990/hw1.0/board-2.bin.zst -o board-2.binVerify:
sha256sum board-2.binExpected (for the 20260221-r0 package):
867e1010787764020653812167d93f5952cbbea05f576209d953d8c9322f18aa board-2.bin
Install it over both board file paths:
FW_DIR=/lib/firmware/ath10k/WCN3990/hw1.0
doas install -o root -g root -m 0644 /tmp/5ghz-fix/board-2.bin $FW_DIR/board-2.bin
doas install -o root -g root -m 0644 /tmp/5ghz-fix/board-2.bin $FW_DIR/board.binThe
-o root -g rootflags ensure the files are owned by root. Without them, the files may end up owned by your user, which works but is inconsistent with the rest of/lib/firmware/.
doas rebootAfter reboot:
dmesg | grep 'ath10k_snoc.*board_file'You should see a line like:
ath10k_snoc 18800000.wifi: board_file api 2 bmi_id N/A crc32 XXXXXXXX
A nonzero crc32 value indicates the board file was loaded. A crc32 00000000
after a fresh boot (not after a crash recovery) means the board file is not
being read correctly.
These reduce unnecessary driver interactions that can trigger firmware crashes.
doas mkdir -p /etc/NetworkManager/conf.d
echo "[connection]
wifi.powersave = 2" | doas tee /etc/NetworkManager/conf.d/wifi-powersave.conf
wifi.powersave = 2means "disable". The default (3) lets NM enable powersave, which on ath10k can cause timeouts. This file applies globally to all current and future Wi-Fi connections. Without it, you would need to disable powersave individually on each new connection profile.
By default, NetworkManager randomizes the Wi-Fi MAC on every connection
(stable mode from /usr/lib/NetworkManager/conf.d/50-random-mac.conf).
This override disables that and sets a fixed MAC instead:
echo "[device]
wifi.scan-rand-mac-address=no
[connection]
wifi.cloned-mac-address=XX:XX:XX:XX:XX:XX
ethernet.cloned-mac-address=preserve" | doas tee /etc/NetworkManager/conf.d/99-no-random-mac.confReplace
XX:XX:XX:XX:XX:XXwith your desired MAC address.
What this does:
scan-rand-mac-address=no-- disables MAC randomization during Wi-Fi scans.wifi.cloned-mac-address=XX:XX:XX:XX:XX:XX-- forces NetworkManager to always use this specific MAC for all Wi-Fi connections.ethernet.cloned-mac-address=preserve-- leaves ethernet interfaces untouched.- Files in
/etc/NetworkManager/conf.d/override/usr/lib/NetworkManager/conf.d/, and the99-prefix ensures this file is read last.
This ensures the per-connection setting also matches, in case it was previously
set to something else (stable, permanent, random, etc.):
doas nmcli connection modify "YOUR_5GHZ_SSID" \
802-11-wireless.cloned-mac-address XX:XX:XX:XX:XX:XXReplace
YOUR_5GHZ_SSIDwith your connection name (find it withnmcli connection show) andXX:XX:XX:XX:XX:XXwith the same MAC as above.
doas systemctl restart NetworkManagerRun this after all steps are done and the device has been rebooted:
echo '=== 1. regulatory.db signature ==='
dmesg | grep -E 'cfg80211:.*(X\.509|regulatory\.db)' | tail -5
echo ''
echo '=== 2. Regulatory domain ==='
iw reg get 2>/dev/null | head -10
echo ''
echo '=== 3. ath10k firmware and board ==='
dmesg | grep -E 'ath10k_snoc.*(firmware ver|board_file|qmi fw_version)' | tail -5
echo ''
echo '=== 4. Wi-Fi link status ==='
iw dev wlan0 link 2>/dev/null || echo 'wlan0 not connected'
echo ''
echo '=== 5. Wi-Fi powersave ==='
iw dev wlan0 get power_save 2>/dev/null || echo 'N/A'
echo ''
echo '=== 6. 5 GHz channels available ==='
echo "$(iw phy phy0 channels 2>/dev/null | grep -c '5[0-9]\{3\} MHz \[') total 5 GHz channels"
echo ''
echo '=== 7. MAC address ==='
ip link show wlan0 | grep ether| Check | Good | Bad |
|---|---|---|
| 1. regdb | Loaded X.509 cert 'sforshee', no malformed error |
malformed or signature is missing/invalid |
| 2. regdom | country CL: (your code) in global section, not country 00:. The phy#0 section may show the AP's country instead -- this is normal. |
country 00: or only 2.4 GHz |
| 3. board | crc32 nonzero on first boot line |
crc32 00000000 on first boot |
| 4. link | freq: 5xxx when connected to 5 GHz AP |
Not connected |
| 5. powersave | Power save: off |
Power save: on |
| 6. channels | 20+ total 5 GHz channels (some may be DFS/No IR) | 0 or very few |
| 7. MAC | The fixed MAC you configured | Random/different on each boot |
-
Do NOT use
ath10k_core cryptmode=1-- it causescryptmode > 0 requires raw mode support from firmwareand the driver refuses to probe entirely. -
Do NOT write to
/sys/kernel/debug/remoteproc/remoteproc*/crash-- this has pushed the device into Qualcomm EDL (Emergency Download) mode in testing. -
Do NOT run
iw reg set XXas a substitute for the modprobe option -- it has no effect when the regdb was rejected at boot, and once associated to an AP the driver uses the AP's country code anyway.
-
apk upgradewill overwriteregulatory.dbwith the latestwireless-regdbfrom Alpine edge (wens-signed), breaking step 1. After upgrading, re-apply step 1. -
apk upgrademay overwriteboard-2.biniffirmware-oneplus-msm8998is updated. After upgrading, check if step 3 needs re-applying. -
The
/etc/NetworkManager/conf.d/overrides (steps 4a, 4b) survive package upgrades since/etc/is not managed byapk. -
The proper long-term fix for the regdb issue is for the postmarketOS kernel to either embed the
wenskey or disableCONFIG_CFG80211_REQUIRE_SIGNED_REGDB.
-
regulatory.db signing mismatch: kernel trusts
sforsheebut Alpine shipswens-signed regdb. Same issue on Qualcomm Debian images: qualcomm-linux/qcom-deb-images#174 -
WCN3990 board file packaging:
firmware-oneplus-msm8998ships outdated uncompressedboard-2.bin,linux-firmware-ath10kships newer version but only as.zst.
After applying every fix in this guide (correct regdb, regulatory domain, updated board file, powersave off, MAC pinned, scan randomization off, infinite autoconnect retries), the 5 GHz band remains unusable for sustained traffic.
| Field | Value |
|---|---|
| Chip | Qualcomm WCN3990 (ath10k_snoc) |
| Firmware version | 1.0.0.483 (api 5) |
| Build ID | WLAN.HL.1.0.c6-00126-QCAHLSWMTPLZ-1.211883.1.278648.1 |
| Build date | 2020-04-14 |
| Package | firmware-oneplus-msm8998-10.0.1-r4 (extracted from stock OxygenOS) |
| Source | https://github.com/JamiKettunen/firmware-mainline-oneplus5 |
This firmware is a closed-source Qualcomm blob that runs on the modem DSP
(qcom-q6v5-mss). Version 1.0.0.483 is the only version available for
WCN3990 on this device. There is no newer release and no way to patch it.
In testing, the firmware crashed 14 times in ~3.5 hours on 5 GHz, with crash cascades of 3 crashes in 20 seconds. All crashes share the same program counter:
err_qdi.c:450:EX:wlan_process:1:WLAN RT:2070:PC=b00bfa9c
err_qdi.c:450:EX:wlan_process:1:WLAN RT:1073:PC=b00bfa9c
err_qdi.c:450:EF:wlan_process:1:cmnos_thread.c:3242:Asserted in wlan_vdev.c:_w
The single crash PC (b00bfa9c) points to a specific, reproducible bug in
the firmware. The wlan_vdev.c assertion is likely a secondary failure
triggered by the crash-recovery loop.
Each crash kills the data path for 10-15 seconds. The ath10k_snoc driver
recovers the link, but NetworkManager often declares the connection failed
before recovery completes. A sustained operation like apk update cannot
complete without being interrupted by a crash.
| Mitigation | Effect |
|---|---|
| Correct regdb + regulatory domain | Unlocks 5 GHz channels, does not prevent crashes |
Updated board file from linux-firmware-ath10k |
Better calibration, does not prevent crashes |
| Powersave off | Removes one crash trigger, crashes still occur |
| MAC pinning + no scan randomization | Reduces driver interactions, crashes still occur |
| Infinite autoconnect retries | NM reconnects after crash, but each drop is 10-15s |
| devcoredump crash trap + auto-reconnect | Fastest possible recovery, still ~10s downtime per crash |
Use 2.4 GHz. It is the only stable band with the WCN3990 firmware on
ath10k_snoc / Linux 6.0.x. The 5 GHz band is fundamentally broken for
sustained traffic due to a bug in the closed-source Qualcomm firmware that
cannot be fixed from userspace or the kernel.
The 5 GHz connection profile should be kept with autoconnect=no in case
a future kernel or firmware update improves the situation, but it should
not be used for anything that requires reliability.
Alternatives for better throughput:
- USB Wi-Fi dongle with a well-supported chipset (mt76, rtl8xxxu).
- USB tethering from another device.
- Future kernel upgrade (though the firmware remains the bottleneck).