一块Realtek 8812BU USB网卡,Windows下插上就能用,换到Ubuntu上之后,要么插上去一点反应都没有,要么lsusb能看到设备,但右上角的网络菜单里死活找不到Wi-Fi开关。这种问题我前前后后在四五台机器上碰到过,每次原因还不完全一样。今天这篇就把我从头到尾的排查思路和最终解决方案完整记录下来,已经解决的可以直接抄作业,还没解决的跟着排查链路走一遍,大概率能定位到问题。
这篇文章适合所有在Ubuntu下用Realtek USB无线网卡的人,不只是8812BU这一颗芯片。像8822BU、8822CU这些同系芯片的坑基本一样,驱动仓库的选择和编译流程几乎都能复用。
1. 现象与根因:插上没反应不代表网卡坏了
1.1 两类典型表现:彻底无感知 vs 能看到设备但起不来
先说现象。8812BU在Ubuntu下失败的表现大致分两种:
第一种,插上USB口之后,系统完全无感知。lsusb里看不到任何Realtek相关设备,dmesg也没有对应的USB枚举日志。这种情况最容易让人误判成网卡硬件损坏,但根据我的经验,大概率是USB口的供电问题或者驱动根本没加载时系统对这个设备做了某种层面上的忽略。注意,lsusb看的是USB总线枚举结果,它是驱动之上、内核之下早就完成的动作,只有当内核的USB核心真的将设备枚举成功,lsusb才会显示。
第二种,lsusb能显示ID 0bda:b812 Realtek Semiconductor Corp. RTL8812BU 802.11a/b/g/n/ac AC1200,但系统里死活没有无线网卡接口。这种占大头。设备被看到了,USB枚举成功了,但内核没有可用驱动把硬件变成wlan0之类的网络接口。这时候问题就落在驱动层。
1.2 为什么Realtek的USB网卡在Linux上这么折腾
Realtek的USB网卡在Linux下的体验差,核心原因在于官方对Linux驱动的支持一直比较敷衍。8139系列老网卡早年之所以驱动稳定,是因为内核很早就内置了驱动模块,但后来这几代USB无线网卡,Realtek官方态度是:Windows驱动老老实实维护,Linux驱动给一版能用就行。
更麻烦的是,Realtek的Linux驱动源码质量参差不齐,官方发布时往往依赖较旧的内核API,新内核一发布,编译立刻报错。社区开发者接手后,做了大量适配工作,把驱动源码整理到GitHub上,才有了今天大家能用的版本。
所以,解决8812BU识别问题的本质,就是给Ubuntu内核补上一个适用于当前内核版本的第三方驱动模块。这个模块在编译时依赖内核头文件,运行时依赖内核模块加载机制,康上Secure Boot时还涉及签名校验。把这三层打通,问题就解决了大半。
2. 动手前的三连检查:确认环境再决定方案
很多人一上来就clone驱动仓库,结果make报一堆错误,折腾一下午也不知道问题出在哪。我现在的习惯是:先花五分钟确认环境,再做下一步。这三项检查决定了你后面要走的路线。
2.1 lsusb与接口枚举:先确认硬件有没有被总线看到
第一件事:
lsusb找到跟Realtek相关的行。8812BU通常会显示:
Bus 002 Device 003: ID 0bda:b812 Realtek Semiconductor Corp. RTL8812BU 802.11a/b/g/n/ac AC12000bda是Realtek的USB Vendor ID,b812是8812BU这个型号的Product ID。注意,如果你看到的是0bda:0812,那其实是8812AU,套的是另一套驱动。所以这里要看准了,别下载错了仓库。
如果lsusb里根本没有Realtek设备,先别急着折腾驱动。换一个USB口试一下,最好是机箱后面板直出的USB口而不是前置延长线。前置面板的USB线质量差,供电不足很容易导致8812BU这种功耗偏高的网卡无法完成枚举。我遇到过两次插前置口没反应、换后置口立刻识别的情况。
2.2 内核版本和头文件匹配:编译驱动的硬前提
编译外部驱动模块最忌讳一件事:内核头文件与当前运行的内核版本对不上。
确认当前内核版本:
uname -r比如6.8.0-48-generic,这个字符串后面要用。
然后确认对应头文件是否已安装:
dpkg -l | grep linux-headers-$(uname -r)如果没有输出,说明头文件缺失。安装方式:
sudo apt update sudo apt install linux-headers-$(uname -r)这里有个比较容易踩的坑:如果U盘安装Ubuntu后长时间没重启,uname -r显示的版本跟/usr/src下真实存在的头文件目录可能对不上。比如/usr/src里只有linux-headers-6.8.0-31-generic,但你跑到最新内核6.8.0-48,这时头文件就是缺的。最省事的办法是直接重启进新内核,再装对应头文件。
2.3 dmesg日志里藏着真正的线索
接下来看内核日志:
sudo dmesg | grep -i rtl sudo dmesg | grep -i usb | tail -20在没装外部驱动的情况下,第一种输出可能没有,因为内核默认没有匹配8812BU的驱动程序,自然不会打任何日志。第二种能看到USB枚举过程:
usb 2-2: new high-speed USB device number 4 using xhci_hcd usb 2-2: New USB device found, idVendor=0bda, idProduct=b812这两行确认了设备在USB层面已经被识别。到这里,环境确认结束,可以进入驱动选择阶段。
3. 驱动仓库怎么选:不是随便clone一个就能用
8812BU的驱动在GitHub上有好几个仓库,名字看着都差不多,真选起来还是要看维护情况和内核兼容性。这里对比一下主流的几个。
3.1 8812BU相关的主流开源驱动仓库
先说结论:日常使用,推荐morrownr/8812bu-20210820;对监听模式有需求,或者以后想搞渗透验证,用aircrack-ng/rtl8812au。
| 仓库 | 适用芯片 | 内核兼容性 | 特点 |
|---|---|---|---|
| morrownr/8812bu-20210820 | 8812BU(8812BU/8822BU系) | 支持到5.15+ | 基于官方驱动封装,稳定优先,DKMS集成好 |
| aircrack-ng/rtl8812au | 8812AU/8812BU等多芯片 | 内核追踪积极 | 支持monitor mode,适合无线安全研究 |
| cilynx/rtl88x2bu | 8812BU/8822BU | 维护活跃 | 与morrownr系出同门,分支各有侧重 |
3.2 我最终为什么选morrownr/8812bu-20210820
这个仓库名字里的20210820代表的是Realtek官方驱动的基线版本。morrownr这个人把官方的8812BU驱动做了大量工程化封装,典型优点有两个:
首先,他的install-driver.sh脚本把编译、安装、DKMS注册、模块加载全部自动化,省掉了一堆手工操作。其次,仓库维护频率高,内核API变化后更新跟得比较快。
另外一个很实际的原因:8812BU和8822BU同一套源代码可以通吃。这俩芯片的驱动结构非常接近,morrownr仓库直接照顾到了。如果你日后换了个8822BU的网卡,这套东西还能用。
3.3 内核自带rtw88驱动的干扰问题
在较新版本的Ubuntu(比如22.04之后的HWE内核)上,内核本身加入了rtw88_wow和rtw88_8822bu相关模块,其中rtw88_8822bu对8812BU/8822BU设备有驱动支持尝试。问题在于这部分驱动的成熟度不够,很多用户反馈连接不稳定,握手失败率很高。
更要命的是,如果你手动装好了morrownr的8822bu驱动,但内核自带的rtw88_8822bu模块也在,两个模块同时存在时,加载顺序不当会导致新驱动的接口起不来。
所以,如果你用的是较新内核并且装了外部驱动,最好先把内核自带的rtw88系模块拉黑:
echo "blacklist rtw88_8822bu" | sudo tee /etc/modprobe.d/blacklist-rtw88.conf echo "blacklist rtw88_usb" | sudo tee -a /etc/modprobe.d/blacklist-rtw88.conf echo "blacklist rtw88_core" | sudo tee -a /etc/modprobe.d/blacklist-rtw88.conf这个操作在旧内核上可做可不做,但在新内核上非常关键。我被这个冲突坑过一次,后面会单独讲排查过程。
4. 从编译到加载:DKMS方案一劳永逸
环境确认完,驱动仓库选定,接下来就是真正的编译安装环节。这里用DKMS方案,核心理由:Ubuntu每次升级内核后,DKMS会自动为新的内核版本重新编译第三方模块,省去手动重装驱动的麻烦。
4.1 安装编译工具链和DKMS
先装齐依赖:
sudo apt update sudo apt install -y build-essential dkms git sudo apt install -y linux-headers-$(uname -r)build-essential提供gcc、make等编译工具,dkms负责模块生命周期管理,linux-headers-$(uname -r)提供当前内核的构建接口。这三个一个都不能少。
装完后验证一下:
dkms status如果输出是空的,说明还没有注册任何第三方DKMS模块,正常。
4.2 获取源码并编译安装
拉取仓库:
git clone https://github.com/morrownr/8812bu-20210820.git cd 8812bu-20210820看一下目录结构,重点关注install-driver.sh这个脚本。这是morrownr封装的一键安装脚本,但我建议别急着跑,先了解它支持的参数:
./install-driver.sh --help常见参数有:
--keep:保留编译产物和源码,方便排查问题--auto:安装后自动将无线接口设置为未受管(unmanaged),交给NetworkManager管理--nm:安装时关闭NetworkManager对接口的随机MAC地址改动
实际安装时,我一般用:
sudo ./install-driver.sh --keep--keep这个参数在出问题时很有用,编译生成的.ko文件会保留,可以直接手动modprobe测试。脚本执行过程中能看到DKMS注册、模块编译、自动加载等一系列输出。整个过程大概三到五分钟,取决于机器性能。
安装完成后验证:
dkms status输出中应该有8812bu/1.1这样的条目,状态是installed。
然后确认模块能加载:
sudo modprobe 8812bu接着看有没有无线接口:
iwconfig如果输出中有wlan0或wlxe84e062a4f5e这样的无线接口,驱动已经工作。接口名是一长串MAC的情况在USB网卡上很常见,不影响使用,只是NetworkManager给它起的基于MAC的persistent名称罢了。
4.3 Secure Boot开启时的模块签名处理
这一步非常容易卡住。很多新机器默认开启Secure Boot,而内核只加载有合法签名的模块。第三方自编译模块没有签名,modprobe 8812bu会直接报错:
modprobe: ERROR: could not insert '8812bu': Key was rejected by the service先检查Secure Boot状态:
mokutil --sb-state如果输出SecureBoot enabled,就要么去BIOS关闭Secure Boot,要么给模块做签名。个人建议:日常开发机直接关掉Secure Boot最省心,毕竟它主要防的是引导链恶意软件。但如果你不想动BIOS设置,也可以走MOK(Machine Owner Key)签名流程,这里说一下我实测过的做法。
首次签名时,DKMS会在/var/lib/dkms/mok.pub生成公钥,你只需要注册这个公钥然后重启按提示导入即可:
sudo mokutil --import /var/lib/dkms/mok.pub这条命令会要求设置一个一次性密码,重启后在蓝色MOK管理界面输入这个密码确认导入。导入完成后,DKMS签过名的模块就能被内核接受。
但如果DKMS没有自动生成签名文件,或者你手动编译的模块没有走DKMS,就手动做一次签名:
sudo apt install -y shim-signed sudo mkdir -p /root/signing_key cd /root/signing_key sudo openssl req -new -x509 -newkey rsa:2048 -keyout MOK.priv -outform DER -out MOK.der -nodes -days 36500 -subj "/CN=My Signing Key/" sudo mokutil --import MOK.der sudo /usr/src/linux-headers-$(uname -r)/scripts/sign-file sha256 /root/signing_key/MOK.priv /root/signing_key/MOK.der /lib/modules/$(uname -r)/updates/dkms/8812bu.ko重启,进入MOK界面导入刚注册的密钥,再回来加载模块就正常了。这个过程我用过一次,流程虽然有点绕,但不用碰BIOS,适合不想改动固件设置的场景。
5. 装完没有反应?完整的排查链路
驱动装完之后不是万事大吉。我自己遇到过的坑,包括模块加载了但没有网络接口、rfkill把设备软屏蔽了、内核自带驱动冲突导致外部驱动起不来,每一步都值得单独说。
5.1 模块加载与接口识别的分步检查
装完驱动重启后发现还是没网卡,先别急着重装,按顺序做这几步。
第一,确认模块是否加载:
lsmod | grep 88x2bu如果是空的,模块没被加载,手动加载试一下:
sudo modprobe 8812bu如果报错,看一下具体错误。如果没报错但依旧没接口,看日志:
sudo dmesg | grep -i 88x2bu常见情况是日志里能看到:
88x2bu: loaded successfully但iwconfig依然没有无线接口。这种模块加载了、接口没生成的情况,多数是NetworkManager没有识别到设备,或者设备被rfkill屏蔽。
5.2 rfkill屏蔽:最容易误判的一环
很多本子或者主板带无线网卡硬件开关,而RF kill机制的统一管理会把所有无线设备一起软屏蔽。8812BU这种USB网卡也会被连带屏蔽。
检查方法:
rfkill list如果看到类似:
0: phy0: Wireless LAN Soft blocked: yes Hard blocked: no那问题就很明确了,系统软屏蔽了这个网卡。解除屏蔽:
rfkill unblock wifi如果重启又变回Soft blocked: yes,可以把射频开关状态固定:
sudo systemctl disable systemd-rfkill.service这样系统启动时不会自动恢复屏蔽状态。不过有的机器会因为省电策略问题需要保留rfkill服务,所以这个命令要不要执行,取决于你的机器是不是每次重启都屏蔽。我自己的台式机没有这个毛病,但朋友的一台NUC换了USB网卡后就总是被屏蔽,最后还是关掉rfkill服务解决的。
5.3 多驱动冲突导致模块加载异常
在新内核上,比较隐蔽的问题是内核自带的rtw88系驱动和外部模块冲突。有一次我装好了morrownr的驱动,lsmod里也有8812bu,但系统迟迟不出现无线接口,dmesg里反而出现一堆rtw88_8822bu的报错。
排查过程:
lspci -k | grep -A3 Network lsmod | grep rtw看到rtw88_8822bu模块也存在,说明8812BU被两个驱动抢。USB设备同一时刻只能被一个驱动绑定。rtw88_8822bu先加载了,外部8812bu反而排不上号。
解决办法就是前面提到的,把rtw88系模块列入黑名单:
echo "blacklist rtw88_8822bu" | sudo tee /etc/modprobe.d/blacklist-rtw88.conf echo "blacklist rtw88_usb" | sudo tee -a /etc/modprobe.d/blacklist-rtw88.conf echo "blacklist rtw88_core" | sudo tee -a /etc/modprobe.d/blacklist-rtw88.conf sudo update-initramfs -u更新initramfs这一步很重要,黑名单写在modprobe.d下并不会自动打包进内存盘。更新好后重启,无线接口就能正常出现了。
6. 内核升级后的驱动维护
驱动装好的那一刻只是开始。Ubuntu隔三差五升级内核,每次升级之后,第三方模块的二进制就会失效,因为内核API变了。这时候DKMS的价值就体现出来了。
6.1 DKMS自动重建的原理
DKMS的核心工作是:当新内核安装时,它会在内核post-install钩子里自动运行,检查/usr/src下注册的驱动模块,然后针对新内核版本重新编译一遍。
所以正常流程下,你不需要做任何事。升级内核、重启之后,8812BU驱动自动可用。前提是头文件在——如果新内核的头文件没装,DKMS只能干瞪眼。
升级前推荐手动跑一次:
sudo apt upgrade sudo dkms autoinstall6.2 手动处理重建失败的方法
如果dkms status显示某个内核版本下模块状态不是installed而是built或者failed,需要手动干预。
先移除再重装:
sudo dkms remove 8812bu/1.1 --all然后重新注册并安装:
cd ~/8812bu-20210820 sudo ./install-driver.sh --keep还有一种情况:大版本升级(比如22.04升到24.04)后,/usr/src下的源码还在,但DKMS数据库可能丢失。这时候直接进到源码目录,重新跑一次安装脚本是最快的。
另外多说一句关于头文件的坑。Ubuntu大版本升级之后,新内核的generic头文件和旧内核的共存,apt自动安装的linux-headers-generic这个元包通常能覆盖到。但如果你手动精简过系统,或者用了带-server后缀的内核,头文件包名会不一样,需要单独装:
sudo apt install linux-headers-$(uname -r)装之前先确认uname -r输出的确实是你当前运行的内核版本,别在grub里启动的是旧内核却给新内核装驱动,那怎么搞都不对。
最后分享一个我后来形成的习惯:每次Ubuntu更新内核之前,先去morrownr的仓库页面看一眼最近的commit时间和release状态。这个驱动跟内核API强绑定,如果最近有新增Tag,说明作者已经适配了最新的内核,放心升级;如果仓库超过半年没有任何动静,那我就会等一段时间再升内核,或者干脆先看CKMS报错日志再决定动作。毕竟8812BU这颗芯片本身不差了,867Mbps的5G速率日常用完全够,只要驱动稳定,体验并不会比Intel的AX200差到哪里去。希望这篇能把你在8812BU上花掉的时间省回来。