
一块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 IDb812是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, idVendor0bda, idProductb812这两行确认了设备在USB层面已经被识别。到这里环境确认结束可以进入驱动选择阶段。3. 驱动仓库怎么选不是随便clone一个就能用8812BU的驱动在GitHub上有好几个仓库名字看着都差不多真选起来还是要看维护情况和内核兼容性。这里对比一下主流的几个。3.1 8812BU相关的主流开源驱动仓库先说结论日常使用推荐morrownr/8812bu-20210820对监听模式有需求或者以后想搞渗透验证用aircrack-ng/rtl8812au。仓库适用芯片内核兼容性特点morrownr/8812bu-202108208812BU8812BU/8822BU系支持到5.15基于官方驱动封装稳定优先DKMS集成好aircrack-ng/rtl8812au8812AU/8812BU等多芯片内核追踪积极支持monitor mode适合无线安全研究cilynx/rtl88x2bu8812BU/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设置也可以走MOKMachine 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 /CNMy 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上花掉的时间省回来。