【修复miracast协商失败问题】

改动 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;

改动原因分析

问题场景
  1. 首次协商失败: 当对端设备(如 OPPO K7X 手机)通过 Probe Request/Response 被发现时,如果对端支持 PBC(Push Button Configuration),但本地设备没有及时记录这个信息
  2. 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 方法
改动效果
  1. 提前记录 WPS 方法: 在设备发现阶段就记录对端支持的 WPS 方法(PBC)
  2. 避免后续失败 : 当后续进行 GO Negotiation 时,dev->wps_method 已经正确设置,不会因为 WPS_NOT_READY 而失败
  3. 提高首次连接成功率: 特别是对于某些手机(如 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 Address attribute,告诉对端本设备将要使用的 MAC 地址
问题场景
  1. 多接口环境 : 在某些情况下(特别是使用 p2p_mgmt 接口时),wpa_s->own_addr 可能不是实际要使用的地址
  2. 地址不一致: 如果发送 GO Negotiation Request 时使用的地址和接收 Response 时设置的地址不一致,可能导致协商失败
  3. 首次协商失败: 第一次协商时,可能因为地址设置不正确而导致失败
改动效果
  1. 动态更新地址: 每次接收 Action 帧时,都重新设置 intended address
  2. 正确处理多接口 : 如果有 p2p_mgmt 接口,使用父接口的地址;否则使用当前接口的地址
  3. 确保地址一致性: 保证发送和接收时使用的地址是一致的

两个改动的关系

虽然这两个改动看起来独立,但它们共同解决"首次协商失败"的问题:

  1. 改动 1 (WPS Method): 确保 WPS 配置方法正确设置,避免因 WPS method 不匹配导致的失败
  2. 改动 2 (Intended Address): 确保 P2P 接口地址正确设置,避免因地址不一致导致的失败

两者结合使用,能够显著提高首次 P2P 连接的成功率。


实际影响分析

✅ 正面影响

  1. 提高首次连接成功率:

    • 解决了首次协商总是失败的问题
    • 特别是对某些手机设备(如 OPPO K7X)的连接成功率显著提升
  2. 更早的 WPS 方法识别:

    • 在设备发现阶段就识别并记录 WPS 方法
    • 避免后续协商时的状态错误
  3. 地址管理改进:

    • 动态更新 intended address
    • 在多接口环境中正确工作

⚠️ 潜在考虑

  1. 性能影响(轻微):

    • 每次接收 Action 帧时都设置 intended address
    • 但这个操作开销很小,影响可以忽略
  2. 地址设置的时机:

    • 目前是在接收时设置,理论上应该在发送前设置
    • 但考虑到 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);
潜在问题
  1. 设置时机可能不合适:

    • 每次接收 Action 帧时都设置 intended address
    • 但这个地址应该是"将来要使用的接口地址",应该在发送 GO Negotiation Request 之前设置,而不是接收时设置
    • 虽然不一定会导致问题,但逻辑上不够清晰
  2. 与其他设置位置的冲突:

    • 代码中还有其他地方设置 intended address(例如第 875、887 行)
    • 频繁覆盖可能导致地址不一致
  3. 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);
 }
相关推荐
wanhengidc1 小时前
云手机 高算力 快速便捷
运维·服务器·科技·游戏·智能手机
饕餮争锋1 小时前
Linux 常用命令分类详解
linux·运维·服务器
蟹至之1 小时前
【MySQL】索引 (上) —— 索引的定义与数据结构
数据库·mysql·索引
·云扬·1 小时前
基于YCSB的MongoDB性能压测实践指南
数据库·mongodb
卿雪1 小时前
MySQL【索引】:索引的概念与分类
java·数据库·python·mysql·adb·golang
wanhengidc1 小时前
云手机如何进行数据备份
运维·服务器·科技·智能手机·云计算
阿巴~阿巴~1 小时前
HTTP头部字段:高效通信的关键
服务器·网络·网络协议·http·http头部字段
minji...1 小时前
Linux 进程控制(三) (进程程序替换,exec系列函数)
linux·运维·服务器
Xの哲學1 小时前
Linux TTY子系统深度剖析
linux·服务器·算法·架构·边缘计算