问题背景
问题场景
在某些 PC 设备(特别是 Windows 10/11 的 Miracast 实现)中,发送 P2P Invitation Request 时可能出现以下情况:
- Channel List attribute 中可能包含某些信道,但这些信道的 operating class 编码可能不完整或有问题
- Operating Channel attribute 中指定的信道本身是有效的,本地设备也支持
- 但由于 Channel List 的问题,导致计算出的 intersection(信道交集) 不包含 Operating Channel 中指定的信道
- 原代码只检查 Operating Channel 是否在 intersection 中,导致连接失败
实际表现
- 对端 PC 发起 Invitation Request
- 本地设备计算双方信道交集(intersection)
- 检查对端的 Operating Channel 是否在交集中
- 如果不在交集中,直接返回
P2P_SC_FAIL_NO_COMMON_CHANNELS失败 - 但实际上 Operating Channel 本身是有效的,本地也支持
改动内容详细分析
改动位置
文件 : src/p2p/p2p_invitation.c
函数 : p2p_process_invitation_req()
位置: 约第 325-333 行
改动前(原代码)
c
if (req_freq > 0 &&
p2p_channels_includes(&intersection,
msg.operating_channel[3],
msg.operating_channel[4])) {
// 使用对端的 operating channel
p2p->op_reg_class = msg.operating_channel[3];
p2p->op_channel = msg.operating_channel[4];
}
逻辑 : 只检查对端的 Operating Channel 是否在 双方信道的交集(intersection) 中。
改动后(新代码)
c
if (req_freq > 0 &&
(p2p_channels_includes(&intersection,
msg.operating_channel[3],
msg.operating_channel[4]) ||
p2p_channels_includes(&p2p->cfg->channels,
msg.operating_channel[3],
msg.operating_channel[4]))) {
// 使用对端的 operating channel
p2p->op_reg_class = msg.operating_channel[3];
p2p->op_channel = msg.operating_channel[4];
}
逻辑 : 检查对端的 Operating Channel 是否在 intersection 中 或者 在 本地配置的信道列表(p2p->cfg->channels) 中。
改动原因分析
为什么这样改?
-
兼容性考虑:
- 某些 PC 设备的 P2P 实现可能有 bug,导致 Channel List 和 Operating Channel 的 operating class 不对应
- 如果 Operating Channel 本身是有效的且本地支持,应该接受它,而不是因为 Channel List 的问题而拒绝
-
更宽松的信道检查:
- 原逻辑:Operating Channel 必须在双方都支持的交集中
- 新逻辑:Operating Channel 在交集中 或者 在本地支持的信道列表中即可
- 这样可以绕过对端 Channel List 的问题
-
实际效果:
- 提高了与有缺陷的 PC 设备的兼容性
- 减少了因 Channel List 编码问题导致的连接失败
潜在影响分析
✅ 正面影响
- 提高兼容性: 能够连接 Channel List 有问题的 PC 设备
- 减少失败率 : 避免因对端实现缺陷导致的
P2P_SC_FAIL_NO_COMMON_CHANNELS错误 - 更灵活的协商: 即使交集中没有对端偏好的信道,只要本地支持就接受
⚠️ 潜在风险
-
可能违反协议规范:
- 理论上,Operating Channel 应该在使用双方信道的交集中
- 如果对端在 Channel List 中没有包含某个信道,但又在 Operating Channel 中指定它,这可能表示对端实现有问题
- 但为了兼容性,放宽检查是合理的
-
后续信道验证:
- 虽然这里接受了对端的 Operating Channel,但后续(第 344-359 行)还会检查最终选择的信道是否在交集中
- 如果是 GO 角色,还会重新选择信道(
p2p_reselect_channel) - 所以实际使用的信道最终还是会通过验证
代码流程说明
Invitation Request 处理流程(简化)
-
解析 Invitation Request
- 提取对端的 Channel List
- 提取对端的 Operating Channel preference
- 计算双方信道的交集(intersection)
-
检查 Operating Channel(本 patch 改动点)
- 原逻辑: 只检查是否在 intersection 中
- 新逻辑 : 检查是否在 intersection 中 或 在本地 channels 中
- 如果通过,使用对端的 Operating Channel preference
-
后续验证(如果本端是 GO)
- 检查最终选择的信道是否在 intersection 中
- 如果不在,重新选择信道(
p2p_reselect_channel) - 如果重新选择后仍不在交集中,返回失败
关键点
- 本 patch 的作用: 放宽了接受对端 Operating Channel 的条件,允许即使在交集中没有,只要本地支持就接受
- 后续保护机制: 后续的信道重新选择逻辑会确保最终使用的信道是双方都支持的
总结
改动目的
修复因对端 PC 设备 Channel List 和 Operating Channel 不对应导致的连接失败问题。
改动方式
放宽 Operating Channel 的检查条件:不仅检查是否在双方信道的交集中,也检查是否在本地支持的信道列表中。
实际效果
- ✅ 提高与有缺陷的 PC 设备的兼容性
- ✅ 减少
P2P_SC_FAIL_NO_COMMON_CHANNELS错误 - ✅ 保持协议安全性(后续还有信道验证)
适用场景
- 对端 PC 发送的 Invitation Request 中 Channel List 编码有问题
- 但 Operating Channel 本身是有效的
- 本地设备支持该 Operating Channel
c
fix status is P2P_SC_FAIL_NO_COMMON_CHANNELS when computer channel list error
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index d39aa38..a0b7f5f 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -322,9 +322,12 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
p2p_dbg(p2p, "Peer operating channel preference: %d MHz",
req_freq);
if (req_freq > 0 &&
- p2p_channels_includes(&intersection,
- msg.operating_channel[3],
- msg.operating_channel[4])) {
+ (p2p_channels_includes(&intersection,
+ msg.operating_channel[3],
+ msg.operating_channel[4]) ||
+ p2p_channels_includes(&p2p->cfg->channels,
+ msg.operating_channel[3],
+ msg.operating_channel[4]))) {
p2p->op_reg_class = msg.operating_channel[3];
p2p->op_channel = msg.operating_channel[4];
p2p_dbg(p2p, "Use peer preference op_class %d channel %d",