ARTICLE · 1175869
Wi-Fi Direct 源码分析(10):从 GO Negotiation 结果到 P2P-GROUP-STARTED
Wi-Fi Direct 源码分析(10):从 GO Negotiation 结果到 P2P-GROUP-STARTED
摘要:从 wpas_go_neg_completed() 的 GO/Client 分叉继续,追踪 WPS provisioning、关联、4-Way Handshake 与 P2P-GROUP-STARTED。

@[toc]
第 09 篇停止在一个明确边界:P2P Core 已经完成 GO Negotiation,并通过:
cfg->go_neg_completed
↓
wpas_go_neg_completed()把 struct p2p_go_neg_results 交回 wpa_supplicant。此时已经知道:
• 哪一端成为 GO; • 哪一端成为 Client; • Group 使用的频率/信道; • peer device/interface address; • classic 路径使用的 WPS method; • Group ID/SSID 等后续 formation 参数。S1
但此时仍未完成真正可用的数据连接。本篇只解决 GO Negotiation 之后的 Group Formation 与安全建立过程,直到 P2P-GROUP-STARTED。
1. 先把五个容易混在一起的术语固定下来
PBC
PBC = Push Button Configuration,属于 WPS provisioning method。p2p_connect <peer> pbc 表示经典 Group Formation 后续使用 WPS PBC,不表示存在一个名为“PBC Negotiation”的独立协议阶段。S3
Provision Discovery
Provision Discovery 是第 09 篇已经分析的可选 P2P Public Action exchange,用于在 GO Negotiation 前确认 provisioning/config method。它不是 WPS credential exchange 本身。
GO Negotiation
GO Negotiation 解决 GO/Client 角色、Channel List、Operating Channel、Interface Address、Configuration Timeout 等 Group Formation 参数。它结束时产生 p2p_go_neg_results,但并不直接建立最终 WPA 数据链路。S2
WPS provisioning
经典 Wi-Fi Direct Group Formation 中,GO 作为 WPS Registrar,Client 作为 WPS Enrollee。双方通过 EAP-WSC/WPS exchange,把 Client 真正加入 Group 所需的 SSID 和安全 credential 交付下来。S3
4-Way Handshake
WPS 得到 credential 后,Client 还要使用正常 WPA/RSN 安全流程重新建立数据连接。4-Way Handshake 使用 EAPOL-Key M1/M2/M3/M4 派生、确认和安装 PTK,并完成 GTK 等组密钥分发;成功后 supplicant 进入 WPA_COMPLETED。这一步才代表 Client 的加密数据端口真正具备正常工作条件。S4
所以 classic 主线是:
2. wpas_go_neg_completed():GO Negotiation 与 Group Formation 的真正分界
P2P 初始化时:
p2p.go_neg_completed = wpas_go_neg_completed;所以第 09 篇 Core 的完成事件最终回到:
wpas_go_neg_completed()该函数先处理成功/失败、Group interface、协商结果,然后出现最关键的角色分叉:S1
if (res->role_go) {
wpas_start_go(group_wpa_s, res, 1, group_wpa_s->p2p_mode);
} else {
os_get_reltime(&group_wpa_s->scan_min_time);
if (res->p2p2)
wpas_start_gc(group_wpa_s, res);
else
wpas_start_wps_enrollee(group_wpa_s, res);
}本文跟踪 classic 路径,因此:
这也是第 09 与第 10 篇的拆分点:前者结束“协商”,后者开始“真正创建/加入 Group”。
3. 本端成为 GO:wpas_start_go() 先创建临时 Group network
当 res->role_go == 1 时进入:
wpas_start_go()它先复制 GO Negotiation 结果,再创建一个临时 struct wpa_ssid network,并把 Group Formation 所需参数写进去:S1
ssid = wpa_config_add_network(wpa_s->conf);
...
wpa_config_set_network_defaults(ssid);
ssid->temporary = 1;
ssid->p2p_group = 1;
ssid->p2p_persistent_group = !!params->persistent_group;
ssid->mode = group_formation ? WPAS_MODE_P2P_GROUP_FORMATION :
WPAS_MODE_P2P_GO;
ssid->frequency = params->freq;
ssid->proto = WPA_PROTO_RSN;
ssid->pairwise_cipher = WPA_CIPHER_CCMP;
ssid->group_cipher = WPA_CIPHER_CCMP;当前从 GO Negotiation 进入时:
group_formation = 1所以 network 首先处于:
WPAS_MODE_P2P_GROUP_FORMATION而不是最终的 WPAS_MODE_P2P_GO。这个 mode 本身就是一个生命周期标志:GO 角色已经确定,但 WPS Group Formation 尚未完成。
4. wpas_start_go() 为什么注册 p2p_go_configured() callback
wpas_start_go() 不会在一个同步调用栈里直接把 AP/GO 完全启动。它配置好 network 后,建立后续回调:
wpa_s->ap_configured_cb = p2p_go_configured;
wpa_s->ap_configured_cb_ctx = wpa_s;
wpa_s->ap_configured_cb_data = wpa_s->go_params;
...
wpa_supplicant_req_scan(wpa_s, 0, 0);这里重新使用 wpa_supplicant 正常的网络选择/AP setup 状态机;GO/AP 配置真正完成后,回调:
p2p_go_configured()被调用。S1
经典 PBC 路径中,p2p_go_configured() 最终启动 GO 侧 WPS Registrar:
p2p_go_configured()
↓
wpa_supplicant_ap_wps_pbc()
↓
GO 等待 Client 的 WPS Enrollee所以 GO 主线不是:
wpas_start_go() -> Group 完成而是:
5. 本端成为 Client:wpas_start_wps_enrollee() 进入 WPS 加组
当 res->role_go == 0 且不是 P2P2 时:
wpas_start_wps_enrollee()该函数保存 GO Negotiation 结果,并按 WPS method 分流。PBC 路径直接调用:S1
if (res->wps_method == WPS_PBC) {
wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1, 0);wpas_wps_start_pbc() 位于 wpa_supplicant/wps_supplicant.c,其内部创建一个临时 WPS network:
wpas_wps_start_pbc()
↓
wpas_wps_add_network()
↓
建立临时 WPA_KEY_MGMT_WPS network
↓
wpas_wps_reassoc()
↓
wpa_supplicant_req_scan()这里出现的 scan 和第 07/08 篇 Device Discovery scan 目的完全不同:
Device Discovery scan
目标:发现附近 P2P Device
Group Formation scan
目标:找到 GO Negotiation 已经确定的 GO BSS / SSID,准备关联6. Client 如何从 scan 走到 association,再进入 EAP-WSC / WPS
WPS 临时 network 进入正常 supplicant 网络选择流程后,Client 会:
扫描 GO BSS
↓
选择匹配的 WPS network
↓
802.11 Authentication / Association
↓
进入 WPA_KEY_MGMT_WPS
↓
EAPOL / EAP-WSC这里 WPS 的作用不是完成最终 WPA 4-Way Handshake,而是安全地把后续连接需要的 credential 交给 Enrollee。S3
WPS Core 收到 Credential 后,通过 callback 进入:
wpa_supplicant_wps_cred()它把 WPS 临时 network 转换/替换为真正的 WPA/RSN network 配置,关键内容包括:
SSID
WPA2/RSN security parameters
PSK / passphrase
cipher / key management因此 WPS 的输出是“后续正常安全连接所需要的配置”,不是“业务数据连接已经完成”。
7. WPS success 怎样进入 P2P-GROUP-FORMATION-SUCCESS
WPS 成功事件最终进入:
wpas_p2p_wps_success()Client 与 GO 都会借此向 P2P Group Formation 汇总。hostap 2.12 中该路径最终调用:S1
wpas_group_formation_completed()成功时上报:
P2P-GROUP-FORMATION-SUCCESS这个事件的含义是:classic P2P Group Formation / WPS provisioning 已经成功。
它与:
P2P-GROUP-STARTED不是同一个时机,尤其 Client 侧还必须完成后续正常 WPA/RSN 数据连接。
8. 为什么 Client WPS 成功以后还要断开并重新连接
WPS 阶段使用的是:
WPA_KEY_MGMT_WPS而 wpa_supplicant_wps_cred() 已经得到真正的 WPA/RSN credential。WPS session 结束以后,Client 必须切回正常网络安全配置。
wpas_wps_eapol_cb() 识别到这一转换条件后执行:S1
wpas_wps_eapol_cb()
↓
wpa_supplicant_deauthenticate()
↓
reassociate = 1
↓
eloop_register_timeout(..., wpas_wps_assoc_with_cred, ...)随后 wpas_wps_assoc_with_cred() 使用新 credential 重新寻找/关联 GO。
这一步非常关键,因为它解释了为什么:
WPS 成功并不等于:
WPA_COMPLETEDWPS 是“拿到钥匙和网络参数”;重新关联 + WPA/RSN handshake 才是“使用这些安全材料真正把数据链路建立起来”。
9. 4-Way Handshake 在这条链上处于什么位置
Client 使用 credential 重新关联 GO 后,进入正常 WPA2/RSN Personal 数据连接流程。这里会出现 EAPOL-Key 4-Way Handshake。S4
概念链可以固定为:
其核心作用是:
• 双方基于已经持有的 PMK/PSK 与 nonce/address 派生并确认 PTK; • Client 安装用于单播保护的 PTK; • 获取并安装组播/广播所需 GTK; • 完成受保护数据端口建立所需的安全状态。
因此完整的 Client path 是:
WPS provisioning
↓
获得 SSID + PSK/passphrase 等 credential
↓
重新关联 GO
↓
4-Way Handshake
↓
WPA_COMPLETED10. WPA_COMPLETED 怎么走到 wpas_p2p_completed()
正常 supplicant 状态机进入:
WPA_COMPLETED时,wpa_supplicant.c 的状态切换逻辑会执行:
wpa_s->after_wps = 0;
wpa_s->known_wps_freq = 0;
wpas_p2p_completed(wpa_s);这就是 Client 的最终安全连接与 P2P Group 生命周期重新汇合的位置。S1
wpas_p2p_completed() 首先检查:
if (!wpa_s->show_group_started || !ssid)
return;而第 7 节的 wpas_group_formation_completed() 在 Client 路径已经设置:
show_group_started = 1所以当 4-Way Handshake 成功、状态进入 WPA_COMPLETED 后:
wpas_p2p_completed()
↓
wpas_p2p_group_started(..., go = 0, ...)
↓
P2P-GROUP-STARTED ... client ...这解释了 Client 为什么必须等到 4-Way Handshake 之后才上报 Group Started。
11. GO 和 Client 为什么上报 P2P-GROUP-STARTED 的时机不同
wpas_group_formation_completed() 成功后会区分本端角色:S1
GO 侧
GO/AP 已经创建,WPS Group Formation 成功后可以直接调用:
wpas_p2p_group_started(go=1)
↓
P2P-GROUP-STARTED ... GO ...Client 侧
Client 不能在 WPS success 时立即报告数据连接已经可用,只先设置:
show_group_started = 1随后必须等待:
WPS credential
↓
重新关联
↓
4-Way Handshake
↓
WPA_COMPLETED
↓
wpas_p2p_completed()最终才调用:
wpas_p2p_group_started(go=0)完整差异可以记成:
12. P2P-GROUP-STARTED 最终在哪里构造
最终 control event 由:
wpas_p2p_group_started()构造,而不是由 driver、P2P Core 或 GO Negotiation Confirm 直接上报。S1
事件会包含:
interface name
GO / client role
SSID
frequency
GO device address
persistent flag
必要的 credential / IP related extension典型形态:
P2P-GROUP-STARTED <ifname> GO ssid="DIRECT-xx" freq=<freq> ...或:
P2P-GROUP-STARTED <ifname> client ssid="DIRECT-xx" freq=<freq> ...到这里,P2P Group 在 supplicant 生命周期上已经“Started”。IP 地址、DHCP、route 和真正的 TCP/UDP/ICMP 数据面不在本文展开。
13. 两条完整角色主线
GO 路径
Client 路径
这两条图正好解释了旧文章中最容易被一条箭头链跳过的内容:GO Negotiation、WPS provisioning、association、WPA 4-Way Handshake 和 Group Started 属于不同机制,靠 callback 与状态机逐段连接。
关键源码索引
wpas_go_neg_completed() | 角色分叉 | p2p_supplicant.c |
wpas_start_go() | GO network | p2p_supplicant.c |
p2p_go_configured() | GO callback | p2p_supplicant.c |
wpas_start_wps_enrollee() | Client WPS | p2p_supplicant.c |
wpas_wps_start_pbc() | WPS start | wps_supplicant.c |
wpa_supplicant_wps_cred() | Credential | wps_supplicant.c |
wpas_wps_eapol_cb() | WPS 后重连 | wps_supplicant.c |
wpas_wps_assoc_with_cred() | 用 credential 重连 | wps_supplicant.c |
wpas_group_formation_completed() | Formation success | p2p_supplicant.c |
wpas_p2p_completed() | WPA_COMPLETED bridge | p2p_supplicant.c |
wpas_p2p_group_started() | 最终事件 | p2p_supplicant.c |
资料来源
[S1] hostap 2.12 Git:Group Formation / WPS integration
• 版本: hostap_2_12• 文件:p2p_supplicant.c、wps_supplicant.c、wpa_supplicant.c • 使用位置:第 2~13 节 • 支撑内容:GO/Client 分支、临时 Group network、WPS Registrar/Enrollee、Credential、WPS 后重连、 WPA_COMPLETED -> wpas_p2p_completed()、P2P-GROUP-STARTED。
[S2] Wi-Fi Direct Specification v1.9
• 版本:v1.9 • URL/文档:Wi-Fi Direct Specification v1.9 • 使用位置:第 1、2 节 • 支撑内容:GO Negotiation 与 Group Formation 的阶段边界和 P2P Group 角色。
[S3] WPS specification / hostap WPS implementation
• 版本:v2.0.8 • URL/文档:Wi-Fi Protected Setup Specification v2.0.8 • 来源:wps_supplicant.c、src/wps • 使用位置:第 1、4~8 节 • 支撑内容:PBC、WPS Registrar/Enrollee、EAP-WSC、Credential 与 WPS completion。
[S4] hostap WPA/RSN supplicant implementation
• 版本:hostap 2.12 • 来源:src/rsn_supp、wpa_supplicant.c • 使用位置:第 1、9、10 节 • 支撑内容:EAPOL-Key 4-Way Handshake、 WPA_COMPLETED与 P2P completion bridge。















































































