改动 1: 在 p2p_add_device() 中设置 WPS Method
改动位置
文件 : src/p2p/p2p.c
函数 : p2p_add_device()
位置: 约第 912-915 行
改动内容
改动前(原代码):
c
if (msg.adv_service_instance)
dev->flags |= P2P_DEV_P2PS_REPORTED;
return 0;
改动后(新代码):
c
if (msg.adv_service_instance)
dev->flags |= P2P_DEV_P2PS_REPORTED;
if (msg.wps_config_methods & WPS_CONFIG_PUSHBUTTON) {
dev->wps_method = WPS_PBC;
dev->oob_pw_id = p2p_wps_method_pw_id(dev->wps_method);
}
return 0;
改动原因分析
问题场景
- 首次协商失败: 当对端设备(如 OPPO K7X 手机)通过 Probe Request/Response 被发现时,如果对端支持 PBC(Push Button Configuration),但本地设备没有及时记录这个信息
- WPS Method 未设置 : 后续进行 GO Negotiation 时,如果
dev->wps_method仍然是默认值(可能是WPS_NOT_READY),会导致协商失败
工作原理
p2p_add_device(): 在解析 Probe Request/Response 或 Beacon 帧时调用,用于添加或更新对端设备信息- WPS Config Methods : Probe Response 帧中包含
wps_config_methods字段,指示对端支持的 WPS 配置方法 - WPS_CONFIG_PUSHBUTTON (0x0080): 表示对端支持 PBC 方法
改动效果
- 提前记录 WPS 方法: 在设备发现阶段就记录对端支持的 WPS 方法(PBC)
- 避免后续失败 : 当后续进行 GO Negotiation 时,
dev->wps_method已经正确设置,不会因为WPS_NOT_READY而失败 - 提高首次连接成功率: 特别是对于某些手机(如 OPPO K7X),这个改动能显著提高连接成功率
改动 2: 在接收 Action 帧时设置 Intended Address
改动位置
文件 : wpa_supplicant/p2p_supplicant.c
函数 : wpas_p2p_rx_action()
位置: 约第 7536-7539 行
改动内容
改动前(原代码):
c
void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
const u8 *sa, const u8 *bssid,
u8 category, const u8 *data, size_t len, int freq)
{
if (wpa_s->global->p2p_disabled)
return;
if (wpa_s->global->p2p == NULL)
return;
p2p_rx_action(wpa_s->global->p2p, da, sa, bssid, category, data, len,
freq);
}
改动后(新代码):
c
void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
const u8 *sa, const u8 *bssid,
u8 category, const u8 *data, size_t len, int freq)
{
if (wpa_s->global->p2p_disabled)
return;
if (wpa_s->global->p2p == NULL)
return;
p2p_set_intended_addr(wpa_s->global->p2p,
wpa_s->p2p_mgmt ?
wpa_s->parent->own_addr :
wpa_s->own_addr);
p2p_rx_action(wpa_s->global->p2p, da, sa, bssid, category, data, len,
freq);
}
改动原因分析
Intended Address 的作用
- Intended P2P Interface Address: 在 P2P GO Negotiation 或 Invitation 流程中,用于指示"将来要使用的 P2P 接口地址"
- GO Negotiation Request/Response : 这些 Action 帧中包含
Intended P2P Interface Addressattribute,告诉对端本设备将要使用的 MAC 地址
问题场景
- 多接口环境 : 在某些情况下(特别是使用
p2p_mgmt接口时),wpa_s->own_addr可能不是实际要使用的地址 - 地址不一致: 如果发送 GO Negotiation Request 时使用的地址和接收 Response 时设置的地址不一致,可能导致协商失败
- 首次协商失败: 第一次协商时,可能因为地址设置不正确而导致失败
改动效果
- 动态更新地址: 每次接收 Action 帧时,都重新设置 intended address
- 正确处理多接口 : 如果有
p2p_mgmt接口,使用父接口的地址;否则使用当前接口的地址 - 确保地址一致性: 保证发送和接收时使用的地址是一致的
两个改动的关系
虽然这两个改动看起来独立,但它们共同解决"首次协商失败"的问题:
- 改动 1 (WPS Method): 确保 WPS 配置方法正确设置,避免因 WPS method 不匹配导致的失败
- 改动 2 (Intended Address): 确保 P2P 接口地址正确设置,避免因地址不一致导致的失败
两者结合使用,能够显著提高首次 P2P 连接的成功率。
实际影响分析
✅ 正面影响
-
提高首次连接成功率:
- 解决了首次协商总是失败的问题
- 特别是对某些手机设备(如 OPPO K7X)的连接成功率显著提升
-
更早的 WPS 方法识别:
- 在设备发现阶段就识别并记录 WPS 方法
- 避免后续协商时的状态错误
-
地址管理改进:
- 动态更新 intended address
- 在多接口环境中正确工作
⚠️ 潜在考虑
-
性能影响(轻微):
- 每次接收 Action 帧时都设置 intended address
- 但这个操作开销很小,影响可以忽略
-
地址设置的时机:
- 目前是在接收时设置,理论上应该在发送前设置
- 但考虑到 Action 帧的处理流程,在接收时设置也是合理的
⚠️ 改动 2: Intended Address 设置 - 潜在问题
分析
当前实现
c
p2p_set_intended_addr(wpa_s->global->p2p,
wpa_s->p2p_mgmt ?
wpa_s->parent->own_addr :
wpa_s->own_addr);
潜在问题
-
设置时机可能不合适:
- 每次接收 Action 帧时都设置 intended address
- 但这个地址应该是"将来要使用的接口地址",应该在发送 GO Negotiation Request 之前设置,而不是接收时设置
- 虽然不一定会导致问题,但逻辑上不够清晰
-
与其他设置位置的冲突:
- 代码中还有其他地方设置 intended address(例如第 875、887 行)
- 频繁覆盖可能导致地址不一致
-
p2p_mgmt 接口处理:
- 逻辑是:如果有
p2p_mgmt接口,使用父接口地址;否则使用当前接口地址 - 这个逻辑是合理的,但需要确保
parent不是 NULL
- 逻辑是:如果有
建议的改进
方案 1: 添加空指针检查
c
p2p_set_intended_addr(wpa_s->global->p2p,
wpa_s->p2p_mgmt && wpa_s->parent ?
wpa_s->parent->own_addr :
wpa_s->own_addr);
方案 2: 只在特定时机设置
只在接收 GO Negotiation Request 或 Invitation Request 时设置,而不是所有 Action 帧:
c
/* Only set intended address when receiving GO Negotiation or Invitation */
if (category == WLAN_ACTION_P2P_GO_NEG_REQ ||
category == WLAN_ACTION_P2P_INV_REQ) {
p2p_set_intended_addr(wpa_s->global->p2p,
wpa_s->p2p_mgmt && wpa_s->parent ?
wpa_s->parent->own_addr :
wpa_s->own_addr);
}
方案 3: 检查是否真的需要
查看是否有必要在接收时设置,或者应该在发送前统一设置。
c
1. fix first negotiation always fail. 2. fix oppo k7x almost cannot conneced.
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 27fd8e5..f0c31f1 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -903,6 +903,11 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
if (msg.adv_service_instance)
dev->flags |= P2P_DEV_P2PS_REPORTED;
+ if (msg.wps_config_methods & WPS_CONFIG_PUSHBUTTON) {
+ dev->wps_method = WPS_PBC;
+ dev->oob_pw_id = p2p_wps_method_pw_id(dev->wps_method);
+ }
+
return 0;
}
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
old mode 100755
new mode 100644
index d19c7d7..473c612
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -6763,6 +6763,10 @@ void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
if (wpa_s->global->p2p == NULL)
return;
+ p2p_set_intended_addr(wpa_s->global->p2p,
+ wpa_s->p2p_mgmt ?
+ wpa_s->parent->own_addr :
+ wpa_s->own_addr);
p2p_rx_action(wpa_s->global->p2p, da, sa, bssid, category, data, len,
freq);
}