得之我幸 失之我命

when someone abandons you,it is him that gets loss because he lost someone who truly loves him but you just lost one who doesn’t love you.

Debian BCM4364 无法连接 WPA3

问题描述

在 Intel MacBook Pro 上安装 Debian Trixie 后,使用 Broadcom BCM4364 无线网卡和 brcmfmac 驱动连接 Wi-Fi。家中有两个无线网络:

  • Wi-Fi-2.4g:使用 WPA2,可以正常连接。
  • Wi-Fi-5g:使用 WPA3-SAE,通过 NetworkManager 无法正常连接。

出现问题时的系统环境如下:

项目 版本或型号
操作系统 Debian Trixie
内核 7.2.4-1-t2-trixie
无线网卡 Broadcom BCM4364
驱动 brcmfmac
固件 9.30.514.0.32.5.94
wpa_supplicant 2:2.10-24

解决方案

本机最终使用带有本地 workaround 的 wpa_supplicant 2.12,通过 systemd 启动,继续由 NetworkManager 管理无线连接。内核和 brcmfmac 保持系统原版。

以下合并了排障时分次安装的依赖,并补充了验证与回滚说明。该 workaround 仅在本文所列环境中完成验证。

如果排查期间添加过 brcmfmac.feature_disable=0x82000,应先撤销并重启;原本没有该参数则无需处理。

1. 准备源码和编译环境

安装编译工具和依赖,下载源码:

1
2
3
4
5
6
7
8
9
10
$ cd ~
$ wget https://w1.fi/releases/wpa_supplicant-2.12.tar.gz
$ tar xf wpa_supplicant-2.12.tar.gz
$ cd ~/wpa_supplicant-2.12/wpa_supplicant
$ cp defconfig .config # 使用源码自带的默认配置

# 确认 nl80211 和 SAE 支持已启用
$ grep -E '^CONFIG_(SAE|DRIVER_NL80211)=' .config
CONFIG_DRIVER_NL80211=y # 启用与 Linux 无线驱动通信的 nl80211 接口
CONFIG_SAE=y # 启用 WPA3-Personal 使用的 SAE 支持

2. 修改并编译 wpa_supplicant

未修改的 2.12 在本机连接时停留在 ASSOCIATED,日志显示:

1
2
ASSOC INFO: wait for driver port authorized indication
Authentication with ... timed out.

本次 workaround 在驱动握手卸载的处理分支中,取消等待单独的授权通知,直接更新连接状态。

编辑源码前,先保留一份原文件,方便检查差异:

1
2
$ cp -p events.c events.c.orig
$ nano events.c

搜索:ASSOC INFO: wait for driver port authorized indication,找到包含该日志的判断块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if (already_authorized) {
/*
* We are done; the driver will take care of RSN 4-way
* handshake.
*/
wpa_supplicant_cancel_auth_timeout(wpa_s);
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
eapol_sm_notify_portValid(wpa_s->eapol, true);
eapol_sm_notify_eap_success(wpa_s->eapol, true);
} else {
/* Update port, WPA_COMPLETED state from the
* EVENT_PORT_AUTHORIZED handler when the driver is done
* with the 4-way handshake.
*/
wpa_msg(wpa_s, MSG_DEBUG,
"ASSOC INFO: wait for driver port authorized indication");
}

替换为:

1
2
3
4
5
6
7
8
9
/*
* The driver handles the RSN 4-way handshake. Some brcmfmac
* devices do not reliably send NL80211_CMD_PORT_AUTHORIZED,
* so complete the connection on association.
*/
wpa_supplicant_cancel_auth_timeout(wpa_s);
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
eapol_sm_notify_portValid(wpa_s->eapol, true);
eapol_sm_notify_eap_success(wpa_s->eapol, true);

只替换上述内部判断,保留外层条件及后续 8021X 分支

这段修改没有按 BCM4364 型号限定,会影响进入该分支的连接,应作为特定环境下的 workaround 使用。

1
2
3
4
5
6
7
$ diff -u events.c.orig events.c  # 确认只修改了上述判断块
$ make -j"$(nproc)"
$ ./wpa_supplicant -v
wpa_supplicant v2.12

$ strings ./wpa_supplicant | grep 'wait for driver port authorized indication'
# 本次编译后没有输出,作为辅助检查

3. 安装自定义版本

将编译结果安装到 /usr/local,保留 Debian 自带的 /usr/sbin/wpa_supplicant

1
2
3
4
5
6
7
8
9
10
$ sudo install -m 0755 \
~/wpa_supplicant-2.12/wpa_supplicant/wpa_supplicant \
/usr/local/sbin/wpa_supplicant-2.12-brcmfmac

$ sudo install -m 0755 \
~/wpa_supplicant-2.12/wpa_supplicant/wpa_cli \
/usr/local/bin/wpa_cli-2.12-brcmfmac

$ /usr/local/sbin/wpa_supplicant-2.12-brcmfmac -v
wpa_supplicant v2.12

自定义版本不会随 Debian 软件包自动更新,需自行维护。保留源码、.config 和修改差异,方便后续重新编译。

4. 配置 systemd 服务

先查看现有服务配置:

1
2
3
4
5
6
$ systemctl cat wpa_supplicant.service --no-pager
# 以下仅摘录原服务的启动命令
ExecStart=/usr/sbin/wpa_supplicant -u -s -O "DIR=/run/wpa_supplicant GROUP=netdev"

# 创建覆盖配置,如果已有覆盖配置,先备份,并保留其中与本次修改无关的设置
$ sudo systemctl edit wpa_supplicant.service

在编辑区域填入:

1
2
3
[Service]
ExecStart=
ExecStart=/usr/local/sbin/wpa_supplicant-2.12-brcmfmac -u -s -O "DIR=/run/wpa_supplicant GROUP=netdev"

空的 ExecStart= 清除原启动命令,下一行指定自定义版本

保存后检查末尾 override.conf 中的 ExecStart 是否指向 /usr/local/sbin 下的自定义版本:

1
2
$ sudo systemctl daemon-reload
$ systemctl cat wpa_supplicant.service --no-pager

下面的重启操作会中断 Wi-Fi,请在本机终端或通过其他网络连接执行。 如果此前手动启动过测试实例,应先结束对应实例,避免同时管理 wlan0

1
2
3
4
5
$ sudo systemctl restart wpa_supplicant.service
$ sudo systemctl start NetworkManager.service # 如果排查时停止过 NetworkManager,将其启动
$ systemctl status wpa_supplicant.service --no-pager -l
# 确认 Active 为 active (running)
# 确认进程命令行使用 /usr/local/sbin/wpa_supplicant-2.12-brcmfmac

此时由 NetworkManager 通过 D-Bus 提供连接配置,不需要另外创建手动测试用的 wpa_supplicant.conf

5. 验证连接

本机已有 WPA3 连接配置,服务切换后 NetworkManager 自动连接成功,没有额外执行启用自动连接的命令。

下文以 wlan0 为网卡名,以 Wi-Fi-5g 代替实际连接名称:

1
2
3
4
$ nmcli device status
# 以下仅摘录无线接口
DEVICE TYPE STATE CONNECTION
wlan0 wifi connected Wi-Fi-5g

如果没有自动连接,可以手动启用已有配置。连接配置名不一定与 SSID 相同,应先查看:

1
2
3
$ nmcli connection show
$ sudo nmcli --ask connection up "Wi-Fi-5g" ifname wlan0
# 仅在未自动连接时执行,并替换为实际连接配置名

查询当前认证方式和连接状态:

1
2
3
4
5
$ sudo /usr/local/bin/wpa_cli-2.12-brcmfmac -p /run/wpa_supplicant -i wlan0 status  # 关注以下字段
ssid=Wi-Fi-5g
key_mgmt=SAE
pmf=2
wpa_state=COMPLETED

由于补丁会主动设置 COMPLETED,还应检查地址和实际连通性:

1
2
3
4
5
6
7
8
9
10
$ nmcli -f GENERAL.CONNECTION,GENERAL.STATE,IP4.ADDRESS,IP4.GATEWAY device show wlan0
# 地址已匿名化,x 表示本机实际获得的主机地址
GENERAL.CONNECTION: Wi-Fi-5g
GENERAL.STATE: 100 (connected)
IP4.ADDRESS[1]: 192.168.1.x/24
IP4.GATEWAY: 192.168.1.1

$ ping -I wlan0 -c 4 192.168.1.1
# 192.168.1.1 为示例网关,执行时替换为实际地址
# 确认能够通过 wlan0 收到网关响应

最后重启,验证已有配置能否自动连接:

1
$ sudo reboot

重启后:

1
2
3
4
5
6
7
$ nmcli device status
# 以下仅摘录无线接口
DEVICE TYPE STATE CONNECTION
wlan0 wifi connected Wi-Fi-5g

$ systemctl status wpa_supplicant.service --no-pager -l
# 确认仍运行自定义版本

本机重启后自动连接成功,完成了本次连接及开机自动连接验证。

6. 回滚

以下为补充的回滚操作。若 override.conf 是本次新建,且仅包含上述配置,可以删除:

1
2
3
4
5
6
7
8
9
$ sudo rm /etc/systemd/system/wpa_supplicant.service.d/override.conf
# 如果该文件原本存在,应恢复备份,而不是删除整个文件

$ sudo systemctl daemon-reload
$ sudo systemctl restart wpa_supplicant.service
# 重启服务会中断 Wi-Fi

$ systemctl status wpa_supplicant.service --no-pager -l
# 确认进程重新使用 /usr/sbin/wpa_supplicant

回滚后恢复系统版本,原来的 WPA3 连接问题可能再次出现,可通过 NetworkManager 连接此前可用的 WPA2 网络。

Debug 过程

排查分为三个阶段:确认驱动的 SAE 能力、定位 wpa_supplicant 的连接超时,以及区分无线连接与 IP 配置问题。期间尝试过禁用驱动功能,也测试过强制开启 SAE 能力标志的 brcmfmac 补丁,但最终均未保留。

1. 排查中的弯路:禁用 SAE/FWSUP

排查早期,参考当时查到的 T2Linux Broadcom Wi-Fi 连接问题,尝试了禁用固件 SAE/FWSUP 的 workaround。

但该 workaround 针对的是 wpa_supplicant 2.11 起的连接回归,而本机使用的是 2.10。当时没有确认日志,证明故障由固件认证卸载引起,也没有确认禁用后是否具备可用的用户态 SAE 认证路径,走了弯路

在 GRUB 菜单中选中 Debian 启动项,按 e 编辑,在以 linux 开头的行末临时加入:

1
brcmfmac.feature_disable=0x82000

F10 启动后检查:

1
2
$ cat /proc/cmdline
# 确认输出中包含 brcmfmac.feature_disable=0x82000

参数生效后,连接 WPA3 仍然报相同错误。但这次失败后没有立即撤销参数,固件 SAE 能力仍处于禁用状态,导致后续检查驱动能力时后续检查时看不到 SAE_OFFLOAD,误认为是原版驱动缺少该能力。

对照当时使用的 brcmfmac 源码,才确认该参数禁用的能力为:

1
2
3
0x80000  SAE    固件侧 SAE 认证能力
0x02000 FWSUP 固件侧 supplicant 支持
0x82000 同时禁用上述两项能力

因此,带着该参数查不到 SAE offload,不能说明原版驱动缺少这项能力。当时没有及时排除这个干扰,一度尝试修改 brcmfmac,针对 BCM4364 强制设置 BRCMF_FEAT_SAE

准备测试补丁时发现,强制设置的 SAE 标志还会被后面的 feature_disable 逻辑清除,于是撤销启动参数并重启。之后再以系统原版驱动进行对照检查:

1
2
3
4
5
6
7
8
9
10
$ cat /proc/cmdline
# 确认已没有 brcmfmac.feature_disable=0x82000

$ iw dev
# 查看无线接口对应的 phy 编号,重载驱动后编号可能变化

$ iw phy phy2 info | grep -i SAE
# phy2 为示例,替换为实际编号
* [ SAE_OFFLOAD ]: SAE offload support
* [ SAE_OFFLOAD_AP ]: AP mode SAE authentication offload support

原版驱动配合当前固件已经能够报告 SAE offload,强制设置 SAE 标志的补丁没有必要。

这次尝试没有解决原始故障,撤销参数也只是恢复了原有配置。真正影响排查的是:尝试失败后没有及时恢复基线,随后又把人为禁用的能力当成了驱动缺失的能力。

2. 从 wpa_supplicant 2.10 切换到 2.12

在驱动能够报告 SAE offload 后,Debian 自带的 wpa_supplicant 2:2.10-24 仍然连接失败,出现:

1
2
WPA: Failed to select authenticated key management type
WPA: Failed to set WPA key management and encryption suites

检查 2.12 源码后,发现它包含对客户端 SAE offload 的识别和处理逻辑,因此编译该版本,在保留系统版本的前提下进行手动测试。

2.12 的日志能够看到 SAE 被选中:

1
RSN: using KEY_MGMT SAE

连接也推进到关联成功:

1
2
3
NL80211_CMD_CONNECT
Connect event (status=0 ignore_next_local_disconnect=0)
Associated on 5765 MHz

但查询状态时,仍停留在:

1
2
3
key_mgmt=SAE
pmf=2
wpa_state=ASSOCIATED

这说明升级改变了连接行为,但仅升级到未修改的 2.12,还不足以解决本机的问题。

3. 测试 sae_pwe 后仍然超时

sae_pwe 控制 SAE 如何将密码转换为认证时使用的密码元素(Password Element,PWE),不是加密强度或 WPA 版本。

含义
0 仅使用传统的 Hunting-and-Pecking 方法
1 仅使用 Hash-to-Element(H2E)方法
2 同时允许两种方法,根据双方能力选择

手动测试的初始日志包含:

1
nl80211: sae_pwe=0

排查期间将测试配置中的 sae_pwe 改为 2,重新测试后,日志确认参数已经传入:

1
nl80211: sae_pwe=2

但连接仍停留在 ASSOCIATED,随后超时。因此,这次修改没有消除当时的故障,需要继续查看关联成功后的完整日志。

后续手动测试保留了 sae_pwe=2,但没有在应用 workaround 后单独对比不同取值。最终 NetworkManager 方案也没有记录额外设置该参数的操作,因此不将它列为解决方案的必需步骤。

4. 从完整日志定位授权通知等待

最初只筛选 SAE、关联和失败等关键词,遗漏了关联成功后的关键提示。查看从连接尝试到第一次超时的完整日志后,发现:

1
2
3
4
5
6
State: ASSOCIATING -> ASSOCIATED
Associated with <AP-BSSID>
...
ASSOC INFO: wait for driver port authorized indication
...
Authentication with <AP-BSSID> timed out.

未修改的 wpa_supplicant 2.12 已经收到关联成功事件,进入 ASSOCIATED,随后等待驱动提供授权确认。等待超时后,程序主动断开连接。

检查对应源码:

1
2
3
$ cd ~/wpa_supplicant-2.12
$ grep -n -A22 -B8 'wait for driver port authorized indication' wpa_supplicant/events.c
# 定位到 already_authorized 判断及 EVENT_PORT_AUTHORIZED 等待逻辑

在由网卡固件处理四次握手的分支中,wpa_supplicant 需要驱动告知授权结果:

  • 如果关联事件已携带授权确认,即 already_authorized 为真,立即进入完成状态。
  • 否则,等待后续 EVENT_PORT_AUTHORIZED,收到后再更新状态。

本次连接走到了等待分支,但在超时前没有获得程序所需的授权确认。据此得到了“解决方案”中的 workaround:保留“由网卡固件处理四次握手”的外层判断,取消内部对授权通知的等待,直接更新连接状态,然后重新编译。

修改后,手动测试返回:

1
2
3
4
ssid=Wi-Fi-5g
key_mgmt=SAE
pmf=2
wpa_state=COMPLETED

日志也出现:

1
CTRL-EVENT-CONNECTED

由于补丁主动设置了完成状态,这些输出只能说明程序绕过了原来的等待路径,不能单独证明认证及数据通信正常。后续补齐 IP 配置并成功通信,才验证了修改后这套组合的实际可用性。

对于未修改的 2.12,没有测试配置 IP 后能否在超时前短暂通信。不过,配置 IP 本身不会提供驱动授权通知,也不会消除已经观察到的超时断连。

因此,这一阶段的结论是:**未修改的 2.12 在等待授权通知时超时断连;绕过等待后,配合 IP 配置可以正常通信。至于授权确认为什么没有到达,仍未完成根因定位。**❓

5. 无线连接之后,仍需配置 IP

为了排除 NetworkManager 的影响,手动测试时停止了 NetworkManager,直接运行编译后的 wpa_supplicant。

此时虽然状态已经变为 COMPLETED,无线接口却没有 IPv4 地址:

1
2
$ ip -4 addr show wlan0
# 没有 IPv4 地址输出

wpa_supplicant 负责无线认证与关联,不负责自动完成 DHCP 和 IP 配置。停止 NetworkManager 后,这部分工作也失去了管理者。

由于没有安装 dhclient,于是使用 BusyBox 的 udhcpc 请求地址:

1
2
$ sudo busybox udhcpc -i wlan0 -f -q
# 日志显示获得租约,但接口上仍然没有 IPv4 地址

进一步检查发现,udhcpc 缺少用于应用租约的配置脚本。补充脚本,将租约中的地址和默认路由写入接口后,网络通信恢复。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 最小租约处理脚本,只处理 IPv4 地址和默认路由,没有配置 DNS
# 会清除该接口已有的全局地址,仅用于当时已停止 NetworkManager 的手动测试环境
$ sudo tee /tmp/udhcpc-wlan0.sh >/dev/null <<'EOF'
#!/bin/sh

case "$1" in
deconfig)
ip addr flush dev "$interface" scope global
;;

bound|renew)
PREFIX="$(busybox ipcalc -p "$ip" "$subnet" |
sed -n 's/^PREFIX=//p')"

ip addr flush dev "$interface" scope global
ip addr add "$ip/$PREFIX" dev "$interface"

if [ -n "$router" ]; then
ip route replace default via ${router%% *} dev "$interface"
fi
;;
esac
EOF

$ sudo chmod +x /tmp/udhcpc-wlan0.sh
$ sudo busybox udhcpc -i wlan0 -s /tmp/udhcpc-wlan0.sh -q -n
# 使用脚本处理 DHCP 租约,将地址和默认路由应用到接口

$ ip -4 addr show wlan0
$ ip route
# 确认无线接口已有 IPv4 地址及对应路由

这一阶段表明,“有连接状态但无法通信”的现象还包含独立的 IP 配置问题,不能全部归因于 WPA3 认证。

6. 交回 NetworkManager 管理

完成手动验证后,将自定义二进制安装到 /usr/local,通过 systemd 覆盖配置替换服务的启动路径,再由 NetworkManager 接管无线接口。

用 systemd 查看,确认服务正常运行:

1
2
3
$ systemctl status wpa_supplicant.service --no-pager -l
# Active: active (running)
# 进程路径为 /usr/local/sbin/wpa_supplicant-2.12-brcmfmac

随后 NetworkManager 自动连接到目标网络,并获得地址和网关。重启后再次检查,无线接口仍连接到该网络。

维护

后续升级内核、固件或 wpa_supplicant 时,应重新测试未修改的版本是否仍存在相同故障。如果原版已经能够正常连接,可以撤销覆盖配置,停止维护这份 workaround。

be slow to promise and quick to perform.