问题描述
现象
在 Miracast 连接过程中,p2p0 接口在 P2P 组形成阶段被意外断开,导致连接失败并出现 GROUP FORMATION FAILURE 错误。
关键日志
[SME_AUTH_FREQ_CHECK] p2p0: num_multichan_concurrent=1, current_freq=2422, target_freq=5745, calling wpas_p2p_handle_frequency_conflicts
[FREQ_CONFLICT] wpas_p2p_handle_frequency_conflicts: entry, wpa_s=p2p0, freq=5745, ssid=0x823d2c00 (id=2)
wpas_p2p_handle_frequency_conflicts 8154
wpas_p2p_handle_frequency_conflicts 8172
[NL80211_DEAUTH] p2p0: nl80211_deauthenticate, bssid=0x822bf9c8M, reason=3, local_state_change=0
[CFG_DEAUTH] p2p%d: cfg80211 deauth entry, bssid=0x822bf9c8M, reason=3, local_state_change=0
[DEAUTH_ENTER] p2p%d: deauth request, bssid=0x822637d8M, reason=3, p2p=0, local_state_change=0
p2p%d: deauthenticating from 0x822637d8M by local choice (reason=3) [p2p=0]
调试过程
阶段一:问题定位
-
添加控制接口调试信息
- 位置:
ctrl_iface_udp.c,ctrl_iface.c - 目的:确认
DISCONNECT命令是否正确路由到对应接口 - 发现:
p2p0断开发生在wlan0收到DISCONNECT命令之前
- 位置:
-
添加 wpa_supplicant 层调试信息
- 位置:
wpa_supplicant.c - 函数:
wpa_supplicant_deauthenticate,wpas_request_disconnection - 目的:追踪断开调用的来源
- 发现:
p2p0断开由wpa_supplicant_disable_network触发
- 位置:
-
添加驱动层调试信息
- 位置:
mlme.c,cfg.c,sta.c - 目的:追踪驱动层的断开路径
- 发现:断开请求来自
cfg80211层,local_state_change=0表示外部触发
- 位置:
阶段二:调用路径追踪
-
追踪
wpa_supplicant_deauthenticate的所有调用点- 在
wpa_supplicant.c中所有调用wpa_supplicant_deauthenticate的位置添加调试信息 - 发现:
wpas_p2p_handle_frequency_conflicts是触发源
- 在
-
分析频率冲突处理逻辑
- 位置:
p2p_supplicant.c-wpas_p2p_handle_frequency_conflicts - 发现:函数在
wpa_supplicant_associate和sme_send_authentication中被调用
- 位置:
阶段三:根本原因分析
调用时机
频率冲突检查在以下两个函数中被调用:
-
wpa_supplicant_associate(wpa_supplicant.c:2692)- 调用条件:
num_multichan_concurrent < 2且检测到频率冲突 - 用于非 SME 模式的驱动
- 调用条件:
-
sme_send_authentication(sme.c:608)- 调用条件:同上
- 用于支持 SME 模式的驱动
Bug 分析
在 wpas_p2p_handle_frequency_conflicts 函数中(p2p_supplicant.c:8171-8175):
c
} else {
/* P2P connection has priority, disable the STA network */
wpa_supplicant_disable_network(wpa_s->global->ifaces, // ❌ Bug: 应该使用 wpa_s
ssid);
wpa_msg(wpa_s->global->ifaces, MSG_INFO, // ❌ Bug: 应该使用 wpa_s
WPA_EVENT_FREQ_CONFLICT " id=%d", ssid->id);
os_memset(wpa_s->global->ifaces->pending_bssid, 0, // ❌ Bug: 应该使用 wpa_s
ETH_ALEN);
// ...
}
问题:
wpa_s是正在尝试连接的接口(可能是p2p0)wpa_s->global->ifaces是全局接口列表中的第一个接口(通常是wlan0)- 当 P2P 连接有优先级时,代码错误地禁用了第一个接口的网络,而不是正在尝试连接的接口的网络
- 这导致
p2p0在尝试切换频率时被错误地断开
触发场景
p2p0当前在频率 2422 (2.4GHz) 上p2p0尝试切换到频率 5745 (5GHz)- 检测到频率冲突(current_freq=2422, target_freq=5745)
wpas_is_p2p_prioritized(iface)返回 true(P2P 有优先级)- 进入 else 分支,错误地禁用
wpa_s->global->ifaces(第一个接口)的网络 - 导致
p2p0被断开
解决方案
方案选择
经过分析,提供了两个方案:
-
方案一:修复 bug(推荐但被拒绝)
- 将
wpa_s->global->ifaces改为wpa_s - 优点:保留频率冲突检查的保护机制
- 缺点:需要修改核心逻辑
- 将
-
方案二:注释掉频率冲突检查(已采用)
- 使用
#if 0注释掉检查代码 - 优点:快速解决问题,避免错误的处理逻辑
- 缺点:失去频率冲突保护,可能在某些硬件上出现问题
- 使用
实施修改
修改文件 1: wpa_supplicant.c
c
#ifdef CONFIG_P2P
/*
* If multi-channel concurrency is not supported, check for any
* frequency conflict. In case of any frequency conflict, remove the
* least prioritized connection.
*/
/* Disabled frequency conflict check to avoid incorrect interface handling
* in wpas_p2p_handle_frequency_conflicts which causes p2p0 disconnection
* when switching frequencies (e.g., from 2422 to 5745).
*/
#if 0
if (wpa_s->num_multichan_concurrent < 2) {
int freq, num;
num = get_shared_radio_freqs(wpa_s, &freq, 1);
if (num > 0 && freq > 0 && freq != params.freq.freq) {
wpa_printf(MSG_DEBUG,
"Assoc conflicting freq found (%d != %d)",
freq, params.freq.freq);
if (wpas_p2p_handle_frequency_conflicts(
wpa_s, params.freq.freq, ssid) < 0) {
wpas_connect_work_done(wpa_s);
return;
}
}
}
#endif
#endif /* CONFIG_P2P */
修改文件 2: sme.c
c
#ifdef CONFIG_P2P
/*
* If multi-channel concurrency is not supported, check for any
* frequency conflict. In case of any frequency conflict, remove the
* least prioritized connection.
*/
/* Disabled frequency conflict check to avoid incorrect interface handling
* in wpas_p2p_handle_frequency_conflicts which causes p2p0 disconnection
* when switching frequencies (e.g., from 2422 to 5745).
*/
#if 0
if (wpa_s->num_multichan_concurrent < 2) {
int freq, num;
num = get_shared_radio_freqs(wpa_s, &freq, 1);
if (num > 0 && freq > 0 && freq != params.freq) {
wpa_printf(MSG_DEBUG,
"Conflicting frequency found (%d != %d)",
freq, params.freq);
if (wpas_p2p_handle_frequency_conflicts(wpa_s,
params.freq,
ssid) < 0) {
wpas_connection_failed(wpa_s, bss->bssid);
wpa_supplicant_mark_disassoc(wpa_s);
wpabuf_free(resp);
wpas_connect_work_done(wpa_s);
return;
}
}
}
#endif
#endif /* CONFIG_P2P */
调试工具和技巧
添加的调试信息位置
-
控制接口层
ctrl_iface_udp.c: UDP 控制接口接收命令ctrl_iface.c: 控制接口命令处理
-
wpa_supplicant 核心层
wpa_supplicant.c: 断开和关联处理sme.c: SME 模式认证处理
-
驱动接口层
driver_nl80211.c: nl80211 驱动接口nl80211.c(lnxporting): 内核 netlink 接口cfg.c,mlme.c,sta.c: 驱动核心逻辑
调试信息格式
使用统一的调试标记:
[CTRL_IFACE_RX]: 控制接口接收[CTRL_IFACE_PROCESS]: 控制接口处理[WPAS_REQUEST_DISCONNECTION]: wpa_supplicant 断开请求[WPAS_DEAUTH]: wpa_supplicant 去认证[WPAS_DRV_DEAUTH]: 驱动层去认证[NL80211_DEAUTH]: nl80211 去认证[CFG_DEAUTH]: cfg80211 去认证[DEAUTH_ENTER]: 驱动去认证入口[SME_AUTH_FREQ_CHECK]: SME 认证频率检查[ASSOC_FREQ_CHECK]: 关联频率检查[FREQ_CONFLICT]: 频率冲突处理
技术要点
关键概念
-
多通道并发能力 (
num_multichan_concurrent)- 表示硬件可以同时使用的不同频率数量
< 2表示不支持多通道并发(只能使用一个频率)>= 2表示支持多通道并发
-
频率冲突检查
- 目的:在单通道模式下,避免多个接口使用不同频率
- 机制:检测到冲突时,根据优先级决定保留哪个连接
-
接口优先级
- 通过
wpas_is_p2p_prioritized()判断 - 基于
wpa_s->global->conc_pref配置 WPA_CONC_PREF_P2P: P2P 有优先级WPA_CONC_PREF_STA: STA 有优先级
- 通过
调用链
p2p0 尝试切换频率 (2422 -> 5745)
↓
sme_send_authentication / wpa_supplicant_associate
↓
检测到频率冲突 (num_multichan_concurrent < 2)
↓
wpas_p2p_handle_frequency_conflicts
↓
wpas_is_p2p_prioritized(iface) 返回 true
↓
进入 else 分支
↓
错误地禁用 wpa_s->global->ifaces 的网络 (应该是 wpa_s)
↓
p2p0 被断开 ❌
测试验证
测试场景
-
Miracast 连接
- 启动 Miracast 服务
- 等待 P2P 设备发现
- 接受邀请并形成 P2P 组
- 验证
p2p0不再在频率切换时断开
-
频率切换
- 从 2.4GHz 切换到 5GHz
- 验证连接保持稳定
预期结果
- ✅
p2p0可以在不同频率间切换而不被断开 - ✅ Miracast P2P 组形成成功
- ✅ 不再出现
GROUP FORMATION FAILURE错误
后续建议
长期解决方案
-
修复
wpas_p2p_handle_frequency_conflicts中的 bugc// 将 wpa_s->global->ifaces 改为 wpa_s wpa_supplicant_disable_network(wpa_s, ssid); wpa_msg(wpa_s, MSG_INFO, ...); os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); -
验证硬件多通道并发能力
- 如果硬件实际支持多通道并发,考虑将
num_multichan_concurrent设置为 2 或更大值 - 这样可以完全避免频率冲突检查
- 如果硬件实际支持多通道并发,考虑将
-
完善测试覆盖
- 添加频率切换场景的自动化测试
- 覆盖不同优先级配置下的行为
相关文件
修改的文件
wpa_supplicant/wpa_supplicant.cwpa_supplicant/sme.c
添加调试信息的文件
wpa_supplicant/ctrl_iface_udp.cwpa_supplicant/ctrl_iface.cwpa_supplicant/wpa_supplicant.csrc/drivers/driver_nl80211.cnet/wireless/nl80211.c(lnxporting)hal_apollo/mac80211/cfg.chal_apollo/mac80211/mlme.chal_apollo/sta.c
核心问题文件
wpa_supplicant/p2p_supplicant.c-wpas_p2p_handle_frequency_conflicts()
总结
本次调试通过系统性地添加调试信息,从应用层到驱动层完整追踪了 p2p0 断开的调用路径,最终定位到 wpas_p2p_handle_frequency_conflicts 函数中的接口引用错误。通过注释掉频率冲突检查代码,临时解决了问题,但长期来看应该修复函数中的 bug 以恢复频率冲突保护机制。