第 14 章:Wi-Fi Direct(P2P)— 临时结伴的旅行团

"不需要旅行社,两个陌生人也能在路上结伴同行——临时推举一个领队,说走就走。"


本章导读

在传统 Wi-Fi 里,所有设备都要先连上一个 AP(路由器),才能互相通信——就像所有人都必须先到火车站、由车站统一调度才能出发。但很多场景并不需要这个 "车站":手机直接传文件给另一台手机、笔记本直接连打印机、相机直接投屏到电视。

Wi-Fi Direct(Wi-Fi 联盟的认证品牌名,底层技术规范叫 Wi-Fi Peer-to-Peer,简称 P2P)就是为这种 "设备直连" 设计的。它最巧妙的地方在于:不需要真正的 AP,而是让其中一台设备临时 "扮演" AP——这台设备叫 P2P Group Owner(GO,组拥有者),其他设备作为 P2P Client(客户端)连上它。

临时结伴的旅行团 一群驴友在路上偶遇,想结伴同行。他们不需要旅行社(AP),而是当场推举一个人当领队(GO)——领队负责定路线、管钱包、收新人;其他人当团员(Client)。这个临时旅行团(P2P Group)说散就散,下次再遇到还能凭 "老交情" 快速重组(Persistent Group)。

本章覆盖:

  • P2P 的角色与拓扑:谁是领队、谁是团员
  • 设备发现:两个人在茫茫人海里怎么 "对上眼"(Scan / Find,Listen / Search)
  • GO 协商:谁来当领队?(GO Intent + Tie-breaker 的三次握手)
  • 组建立与安全:WPS 配对 + 四次握手 + GO 当 DHCP 服务器
  • 加入已有的组:自己 Scan 进去 vs 被 Invitation 拉进去
  • 持久组:老搭子如何免协商秒重连
  • 电源管理:领队如何 "打个盹" 省电(NoA / OppPS)
  • 帧格式:P2P IE 与关键属性

本章技术结论依据 Wi-Fi Direct® Specification v2.0(Wi-Fi Alliance, 2025),并标注对应章节;底层 802.11 机制引用 IEEE 802.11-2020。


1 P2P 的角色与拓扑

1.1 三种角色

角色旅行团比喻说明
P2P Device一个有结伴能力的驴友既能当领队也能当团员,支持 P2P 发现和 WSC(Wi-Fi 简单配置)
P2P Group Owner(GO)领队"类 AP" 实体,提供 BSS 功能与服务,内置 WSC Registrar;可选地为团员之间转发数据、共享上网
P2P Client团员实现非 AP STA 功能,担任 WSC Enrollee
Legacy Client不懂规矩的散客老设备,不懂 P2P 协议,把 GO 当普通 AP 直接连

GO 不是真路由器,它只是一台临时扮演 AP 角色的普通设备。组解散后,它又变回普通 P2P Device。

1.2 拓扑:1:n 的星形

一个 P2P Group 的拓扑是 1:n——一个 GO 连接多个 Client(§2.2)。这和传统 BSS 一样是星形结构:所有团员都连到领队,团员之间的通信也要经过领队中转(如果 GO 启用了 Intra-BSS Distribution)。

P2P 角色与拓扑

一个 P2P Group 有单一 SSID,提供单一安全域(§2.2)。1:1(n=1)只是 1:n 的特例——两台设备直连。

1.3 两个地址:身份证 vs 工牌

P2P 设备有两个 MAC 地址,这是初学者最容易搞混的地方(§2.4.3):

地址比喻用途
P2P Device Address身份证(终身不变)唯一标识一个 P2P 设备,用于发现阶段所有帧的接收地址(RA)。是设备全局 MAC 地址(或设置了本地管理位的版本)
P2P Interface Address临时工牌(组内有效)仅用于某个 P2P Group 组内通信。组会话开始前分配,组会话结束即失效

身份证(Device Address)证明 "你是谁",全国通用、一辈子不变;工牌(Interface Address)只在 "这家公司"(这个 Group)有效,离职(组解散)就作废。一个人可以同时在多家公司兼职(并发多个 Group),每家发一个不同的工牌。

1.4 并发:脚踏两条船

P2P 设备可以同时连着一个传统 WLAN(上网)和一个 P2P Group(直连),这叫 P2P Concurrent Device(§2.3)。例如:手机一边连着家里路由器(5 GHz, 信道 36)刷网页,一边用 Wi-Fi Direct(2.4 GHz, 信道 6)投屏到电视。这需要设备支持多个 MAC 实体。


2 设备发现 — 茫茫人海中 "对上眼"

发现是 P2P 最精巧的机制。问题是:两台设备事先都不知道对方在哪个信道,怎么 "碰头"?

P2P Discovery 包含四个部分(§3.1.1):

组件作用
Device Discovery两台设备汇聚到同一信道,交换设备信息(名称、类型)
Service Discovery(可选)连接前先发现对方提供什么高层服务
Group Formation决定谁当 GO,建立新组
P2P Invitation邀请设备加入现有组,或唤起一个持久组

2.1 先理清:发现里有两件相反的事

初学者读 P2P 发现最容易卡住,是因为没分清两件方向相反的事——而协议里到处都在说 "回不回复 Probe Request",绕得人晕。先把这两件事拎清楚,后面就全通了:

我在干什么我发什么帧我收什么帧谁这么干
主动找别人 Probe Request(探测请求)别人回我的 Probe Response想找设备的一方
让别人找到我 Probe Response(探测响应)别人发来的 Probe Request想被发现、想被连的一方

所谓 "不回复 Probe Request",意思是我不去应答 "别人" 发来的探测(即我不发 Probe Response、不让自己被这次探测发现)。它不等于"我什么都收不到"——我照样在收别人对我自己那条 Probe Request 的应答(Probe Response)。一个是 "我应答你",一个是 "你应答我",方向正好相反。

为什么一台设备不能两件事同时做?因为 "主动找" 要在多个信道上来回扫 / 发,人是动的;"被找到" 要老老实实停在一个固定信道等别人来探。边走边喊站着不动等人来,物理上没法同一时刻都干。P2P 的整套发现机制,本质就是在这两个角色之间切换时间片

理清这点后,下面三个 "状态" 就只是回答了两个问题

  • Scan 阶段回答 "这附近有什么?"——开场先普查一遍。
  • Find 阶段Listen / Search 回答 "我和那个同样在找的人,怎么撞到同一个信道上?"——靠交替切换两个角色去碰头。

2.2 Scan 阶段 — 开场普查

In-band(带内)设备发现的第一步是 Scan 阶段(§3.1.2.1.2)。它直接复用 IEEE 802.11-2020 的标准扫描流程:设备扫遍所有支持的信道,目的有三个——

  1. 看看周围有没有已存在的 P2P Group(能直接去连,就不用费劲新建组了);
  2. 看看有哪些传统网络(可与扫 P2P 同时进行);
  3. 挑出一个最佳工作信道(Operating Channel),万一要自己当 GO 建组时用。

在 Scan 阶段,设备扮演的是上表的第一行:它在 Probe Request、各个 GO / 网络回给它的 Probe Response。

所以 "Scan 阶段不回复 Probe Request" 就顺理成章了:此刻我正忙着快速扫遍所有信道找别人,根本没停在任何一个信道上,自然没法当 "被探测的对象" 去应答谁。我是来普查的,不是来摆摊的。

刚到一座陌生城市,你先快步绕城转一圈——看看哪儿有现成的旅行团能搭、哪个广场人最多适合集合(最佳信道)。转圈的时候你只顾看(收别人的招牌),不会停下来支个摊等人来问你(不应答别人的探测)。

2.3 Find 阶段 — 两个人怎么 "撞" 到一起

普查完,如果没有现成的组,两台都想直连的设备就要碰头。难点在 14.2.1 已经点破:"边走边找" 和 "停着被找" 没法同时做。Find 阶段的解法是让设备在这两个角色间快速交替循环(§3.1.2.1.3):

状态此刻扮演的角色比喻行为
Listen State(监听)让别人找到我站在原地张望停在固定的 Listen Channel(从 1/6/11 里选一个、全程不变),回复 Probe Request → 此刻可被发现
Search State(搜索)主动找别人走动着喊话在社交信道 1/6/11 上依次 Probe Request;此刻不回复别人的 Probe Request(DMG 之外)

把这张表和 14.2.1 的两件事对上,所有 "回不回复" 就都说得通了:

  • Listen State = "停着被找"。我停在固定信道等人来探,所以我回复 Probe Request,让对方发现我。
  • Search State = "走着找人"。我正在多个信道间发探测,停不下来,所以不回复别人的探测——和 Scan 一个道理。

为什么非得交替、不能只干一件? 如果两台设备都只顾 "走着找人"(都在 Search),那就是两个人满城乱跑互相喊,谁也没停下来应答,永远撞不上;如果都只 "停着被找"(都在 Listen),那就是两个人各自站在不同广场干等,谁也不去找谁。只有一个恰好在 Listen(停着)、另一个恰好 Search 到了它所在的那个信道(走来探它),才能 "对上眼"。换句话说,交替循环,就是为了制造这个 "一动一静、正好撞上" 的时刻。

P2P 设备发现 Find 阶段

2.4 社交信道:约定的 "集合广场"

为了让两台设备快速汇聚,P2P 把搜索范围限定在三个 Social Channels(社交信道)2.4 GHz 的信道 1、6、11(DMG/60 GHz 用信道 2)(§3.1.2.1.1)。

DMG 是什么? DMG(Directional Multi-Gigabit,定向多吉比特)工作频率在 45 GHz 以上的 60 GHz 频段,对应 IEEE 802.11ad/ay(俗称 WiGig)。它频率极高、带宽极大(速率可达数 Gbps),但靠定向波束传输、绕射差、几乎穿不了墙,只适合近距离高速场景。本章规则绝大多数针对常规的 2.4/5 GHz;凡标注 "DMG 之外""DMG 下 " 的地方,都是 P2P 为这个 60 GHz 频段开的特例(比如它用信道 2 而非 1/6/11、加密改用 AES-GCMP、收发探测的规则也略有不同)。初读可直接跳过所有 DMG 分支,只看常规频段那一路即可。

偌大的城市,两个想碰头的人不可能在每条街上找。于是约定 "只在三个广场碰头"——你不在 1 号广场,就去 6 号、11 号转转。范围一小,碰头就快。

2.5 随机化:避免 "永远错过"

这里有个精妙的设计。如果两台设备的 Listen 和 Search 完全同步、节奏一致,它们可能永远碰不上(一个喊话时另一个也在喊话,一个张望时另一个也在张望)——就像两个人在门口反复 "你先走 / 不你先走"。

解决办法:Listen State 的持续时间是随机的(§3.1.2.1.3)。每个 Listen State 持续 随机整数 × 100 TU,这个随机整数在 minDiscoverableInterval(默认 1)和 maxDiscoverableInterval(默认 3)之间取值。随机性打破了同步锁步,保证两台设备迟早会在某个社交信道上 "对上眼"。

TU(Time Unit) = 1024 微秒(802.11 标准时间单位)。100 TU ≈ 102.4 毫秒。


3 GO 协商 — 谁来当领队?

两台对等的设备碰头后,必须决定谁当 GO(领队)、谁当 Client(团员)。这通过 Group Owner Negotiation(GO 协商)完成——一个三次帧交换(§3.1.4.2)。

GO 协商三次握手与判定

3.1 三次握手

方向作用
GO Negotiation Request发起方 → 对方携带我的 GO Intent、能力、信道列表、Intended Interface Address 等
GO Negotiation Response对方 → 发起方回应我的 Intent 与能力,Status=Success 表示同意进入组建立
GO Negotiation Confirmation发起方 → 对方确认最终参数(GO/Client 角色、SSID、信道)

整个 Group Formation(含 GO 协商 + Provisioning)应在 15 秒内完成(§3.1.4.1)。如果发出 GO 协商帧后 100 毫秒内没收到下一帧,发起方就认定协商失败(§3.1.4.2)。

3.2 GO Intent:谁更想当领队?

核心是 Group Owner Intent attribute(§4.1.6)——一个表达 "我有多想当 GO" 的值。它只有 1 个字节,但拆成两部分(§4.1.6 Table 31):

比特字段取值含义
Bit 0Tie breaker(决胜位)0 或 1当双方 Intent 相同时,决定谁当 GO
Bit 1–7Intent(意愿值)0–15越大越想当 GO

判定规则(§3.1.4.2):

  1. Intent 值大的一方当 GO。
  2. Intent = 15 是 "我必须当 GO"——仅当某服务只能在 GO 上正常工作时才设 15(例如提供 Cross Connect(跨接共享上网)的设备)。
  3. 若双方 Intent 相等且都 < 15:发送 Tie-breaker 位 = 1 的一方当 GO。
  4. 若双方 都设 15:协商失败,回 "Fail: both P2P Devices indicated an Intent of 15"。此时由 P2P Device Address 较大的一方发送这个失败响应。

选领队就像 AA 制旅行选召集人。Intent 是 "我有多愿意操心"(0 = 完全不想管,15 = 非我不可)。两个人愿意程度一样高时,就靠 "抛硬币"(Tie-breaker 位)定。但如果两个人都坚持 "必须我来"(都填 15),那这趟团就组不成了——谁也不服谁。

3.3 Tie-breaker 的细节:为什么平局是 "公平" 的?

平局判定就一条:发出 Tie-breaker 位 = 1 的一方当 GO。但这立刻引出一个尖锐的问题——Tie-breaker 不就是发送方在自己帧里填的一个 bit 吗?那我每次都填 1,岂不是稳赢?

要把这事讲清楚,得分三层看。

第一层:初始位是随机的。 规范规定(§3.1.4.2):发起方第一次发 GO Negotiation Request 时(比如刚开机),Tie-breaker 位应当随机取 0 或 1,且长期来看两个值各占一半。再加上两条规则——

  • Response 帧的 Tie-breaker 位,要相对收到的 Request 取反
  • 每次新发(重传不算) Request 时,把自己的位翻转一次

"取反" 保证了双方的位必然相反(一个 0 一个 1),所以平局判定永远有唯一赢家,不会出现 "两边都填 1" 的死局;"翻转" 则保证万一这轮失败要重试,下一轮的 "硬币" 不会永远是同一面。把初始随机这条接上,平局时发起方当 GO 的概率正好是 50%

发起方初始随机到Response 取反后谁的位 = 1结果
10发起方发起方当 GO
01响应方响应方当 GO

发起方随机到 1 还是 0 各一半,所以发起方并不占便宜——这是一枚公平的硬币,设计目标就是不偏袒谁。

第二层:这个 "随机" 是君子协定,不是防伪机制。 注意规范的措辞是 "shall be set randomly"——它是对守规矩的实现提的行为要求,而不是协议在机制上强制、不可伪造的随机。这里没有随机数承诺、没有 nonce 交换、没有事后校验,Tie-breaker 就是一个裸露的比特位。所以严格说:

情况平局时谁当 GO
双方都按规范、各自掷硬币50/50,发起方不占便宜
一方耍赖、每次硬填 1确实能赢下每次平局——协议拦不住

第三层:为什么规范敢用这种 "靠自觉" 的设计、不上防伪? 因为 GO 和 Client 之间不是对抗关系——双方目标一致,都想把组建起来,没人想搅黄。而且当 GO 更像苦差而非特权:要扛着不休眠(见 14.7 电源管理)、当 DHCP 服务器、替团员转发流量、可能还得共享上网。真正 "非我当 GO 不可" 的设备(比如要做 Cross Connect(跨接共享上网)的),直接光明正大填 Intent = 15 就行,根本用不着在 Tie-breaker 上做手脚。既然没人有动机去抢着当 GO,一句 "请掷硬币" 的软约定就够用了,犯不上为它设计防伪——这和安全协议(攻击者有强动机伪造)是完全不同的威胁模型。

平局抛硬币,靠的是大家都老实抛。理论上有人能用 "双面都是 1 的硬币" 作弊每次都当召集人——但召集人是出钱出力的苦差,正常人只会抢着推让,没人会作弊去抢这个累活。所以这枚硬币不用防伪,君子协定就够了。


4 组建立与安全 — 配对、握手、发 IP

GO 角色确定后,进入 Provisioning(配置) 阶段,本质就是跑一遍 WSC(Wi-Fi Simple Configuration,即 Wi-Fi Protected Setup / WPS)(§3.1.4.3)。

4.1 Provisioning = WPS 配对

角色WPS 身份比喻
GOInternal Registrar(注册方)领队,掌管 "入团密码"
ClientEnrollee(注册者)新团员,提交申请领密码

配对方式有三种(§3.1.4,Table 3):

  • PIN:一方显示 PIN 码,另一方输入(Display / Keypad)
  • PushButton(PBC):两边都按按钮,120 秒 "walk time" 内完成
  • NFC:碰一下,带外(Out-of-Band)传递密码

WPS 流程中,Registrar 收到 Enrollee 的 M1("我想入网")后直接回 M2("我来给你发凭证"),不发 M2D(§3.1.4.3)。

M2D 是什么? 它是 WPS 规范里的 M2 的一个变体(D 取自 "不带密钥协商/Diffie-Hellman-less"),含义是 "我收到你的申请了,但现在还没被授权给你发凭证,你先等等"。在开放的 WPS 场景里,一个 Enrollee 发出 M1 后可能被多个 Registrar 听到,那些尚未被用户授权的 Registrar 就回 M2D 婉拒占位。换句话说,M2D 是开放场景里用来" 婉拒占位 " 的稍候信号。但在 P2P 里,GO 协商早已锁定唯一对端,且用户在两台设备上都输了 PIN 或按了按钮——授权在配对开始前就板上钉钉,根本不存在 "还没授权、先挂个稍候牌" 的情况,所以 GO 收到 M1 直接发正式的 M2。

由于 WPS 可能要等用户输入、耗时长达 2 分钟,而 Group Formation 要求 15 秒内完成,所以配对所需信息(如 PIN)必须在协商前就准备好(§3.1.4.1)。

4.2 安全:WPA2/WPA3 + 四次握手

组内通信强制采用 WPA2-Personal 或 WPA3-Personal 加密(AES-CCMP;DMG 下用 AES-GCMP)(§3.2.6.1)。关联成功后,GO 与 Client 立即执行 四次握手(GO 当 authenticator,Client 当 supplicant),协商出临时密钥来加密单播和组播帧。

这一套安全机制完全复用 IEEE 802.11-2020 的 RSNA 体系。

这套 "WPA2 或 WPA3" 的强制加密有一个 6 GHz 例外:组一旦跑在 6 GHz 频段,就遵循 Wi-Fi 6 对 6 GHz 的硬性规则——RSNE 不得再声明 WPA2(AKM 套件 00-0F-AC:2/00-0F-AC:6 在 6 GHz 禁用),必须启用 PMF(管理帧保护,MFPR/MFPC 均置 1),组内只能用 WPA3-Personal(SAE)。动机是堵降级:6 GHz 是全新频段、没有老设备包袱,直接禁掉可被降级的 WPA2 最干净(v2.0 §3.5 将 6 GHz 组运行对齐 Wi-Fi 6 Mobile AP/STA 规则)。

4.3 GO 当 DHCP 服务器

组建立后还有一个关键角色:GO 必须充当 DHCP 服务器,给连入的 Client 分配 IP 地址(§3.2.6.1)。DHCP 至少要支持 IPv4,分配 IP 地址和子网掩码,且不应下发默认网关(因为这是个孤立的直连组,不是用来上公网的)。唯一例外是 Cross Connect(跨接共享上网):当 GO 一边连着传统 WLAN 上网、一边愿意把这个上网能力 "转手" 给组内团员时,它才会下发默认网关、把团员引向公网(§3.2.6.1)。

领队不光定路线,还要给每个团员发 "队内编号"(IP 地址),方便组内点名互相找。但他不告诉你 "出团去外面世界的那条路"(默认网关)——这个团只管组内活动,不负责带你出团上公网。除非领队自己租了车、愿意顺路把全团拉出去(Cross Connect 共享上网),他才会把 "去外面的路" 也发给你。


5 持久组 — 老搭子免协商秒重连

每次都跑完整的发现 + 协商 + WPS 配对很麻烦。Persistent P2P Group(持久组) 解决了重连问题(§3.2.5)。

成功建组后,设备可以存储 P2P Group ID 和 Credentials(凭证)。GO 可以凭此在以后重建同一个组,Client 也能请求唤起持久组。GO 通过把 Persistent Reconnect 位置 1(Group Capability Bitmap 中),声明 "我支持无需用户干预的重连"。

第一次结伴要互相加微信、对暗号(WPS 配对)。但成了 "老搭子" 后,存了彼此的联系方式(Credentials),下次再约直接发个定位就能集合——不用重新加好友。

唤起持久组用的是 P2P Invitation Procedure(邀请流程):把 Invitation Flags 里的 Invitation Type 设为 1,表示 "唤起一个之前建过的持久组"(§3.1.5.1)。这只是邀请流程的用途之一,下一节细讲。


6 加入已有的组 — "我去找团" vs "团来拉我"

前面 14.3 讲的 GO 协商,是两台都还没成组的设备从零建组。但现实里更常见的是:组已经在运行了(比如电视已经当 GO 开着投屏组),这时第三台设备要进来。加入一个已存在的组有两个方向相反的路径,初学者常把它们混在一起:

方向谁主动谁被动用什么机制
① 我去找团(自己加入)外部设备GO 守在原地Scan 发现 + 直接连(§3.1.2.4/§3.2.3)
② 团来拉我(被邀请)组内成员外部设备P2P Invitation Procedure(§3.1.5)

6.1 方向①:外部设备自己发现并加入

这正是你的直觉——Scan 就能解决 "设备加入已存在的组"。原理是:GO 一旦建好组,就活成了一台 AP。它固定守在 Operating Channel 上周期发 Beacon,安安静静等人来(§3.1.2.4:a GO "stays on the Operating Channel and waits for other devices to discover it")。于是任何想进来的设备:

  1. Scan 扫信道,收到 GO 的 Beacon / Probe Response,发现 "这儿有个组"(还能从 GO 广播的 Group Info 看到组里已有哪些 Client,§3.2.4);
  2. 决定加入后,自己发起连接:没配过对就跑 Provision Discovery + WSC 拿凭证,配过就直接关联(§3.2.3)。

这里根本不需要 GO 协商——角色早就定死了(GO 就是 GO),新设备只能当 Client。整个过程跟 "连一个普通 Wi-Fi 热点" 几乎一模一样。

旅行团已经组好、领队举着小旗站在广场(Operating Channel)。想入团的散客自己满广场转(Scan),看到小旗就走过去报名(关联 + 配对)。领队不用挨个去拉人,站着等就行。

6.2 方向②:组内成员主动邀请(P2P Invitation Procedure)

但有时候是组里的人想把外面某台设备拉进来——这就得靠 P2P Invitation Procedure。它是个两帧交换(§3.1.5):

方向作用
P2P Invitation Request邀请方 → 目标"来加入我这个组吧",带上 Group ID、BSSID、信道列表、Operating Channel
P2P Invitation Response目标 → 邀请方Status=Success 表示接受;拒不拒由对方实现策略决定(100 ms 内不回就算失败)

6.2.1 先解决一个前提:邀请方怎么 "够得着" 外面的设备?

这正是你的疑问——组里的人不都守在 operating channel 上吗?外面的设备在别的信道做自己的 Listen/Search,两边信道都不一样,邀请帧怎么递过去?

答案要分清两种 "组内成员",它们的活动自由度完全不同:

  • GO:它虽然 "主职" 是守在 operating channel 上发 Beacon 等人,但规范允许它临时离开去别的信道找人——§3.1.2.4 原文:a GO "may search on other channels to find desired devices or services"。也就是说,GO 想邀请谁,就自己切到那个设备所在的信道(对方在做 Listen/Search,能在社交信道上被探到),把 Invitation Request 递过去。它离开期间用 NoA 机制(14.7)提前告诉自家 Client"我下线一会儿",回来再继续发 Beacon。
  • Client:团员平时也驻留在 operating channel 上收发数据,但它同样可以临时切走去发现并邀请别人(前提是它的实现支持,且不影响组内业务)。

所以关键认识是:"守在 operating channel" 是组成员的常驻状态,不是禁锢。谁要主动邀请别人,谁就得临时离开本组信道、切到目标所在的信道去递邀请——递完再回来。这跟方向①里 "GO 站着等人" 是对称的:方向①是外人走过来,方向②是组内人主动走出去

领队平时举着旗站在 3 号广场(operating channel)。但他想拉某个老朋友入团时,会临时托人看着旗、自己跑去朋友所在的 6 号广场喊一嗓子(递 Invitation);喊完再回 3 号广场。出门前他在旗杆上贴张 "我离开一会儿" 的告示(NoA),免得团员找不到他。

6.2.2 万一目标设备 "找不到"——GO 中转的唤醒机制

还有一种更棘手的情况:邀请方是个 Client,而它想拉的目标恰好是另一个组里、正在省电休眠的 Client——两个 Client 谁也不直接盯着对方,根本碰不上。这时规范提供了一条经 GO 中转的迂回路(§3.2.4):

  1. 先拿到目标的地址。 你可能会问:还没 "找到" 目标 Client,怎么会先知道它的 P2P Device Address 去叫醒它?答案是——问它所在组的 GO。GO 平时就在做 Group Information Advertisement:它在自己发的 Probe Response(以及 Beacon)里携带 P2P Group Info attribute,逐个列出组内每个 Client 的描述符——Device Address、设备名、设备类型都在里面(§3.2.4)。所以发起方只要在 GO 的信道上探一下 GO(GO 是醒着的、随时应答),就能把这个组里所有成员的 Device Address 一次性捞回来,哪怕那些 Client 正在睡觉。地址来自 GO 的公开广播,不需要先联系上 Client 本人。
  2. 拿到地址后,发起方给目标所在组的 GO 发一帧 Device Discoverability Request,附上刚查到的目标 P2P Device Address;
  3. 那个 GO 收到后,对自家正在打盹的 Client 发一帧 GO Discoverability Request,把它唤醒并叫它保持在线(至少 100 TU);
  4. GO 再回 Device Discoverability Response 告诉发起方 "它醒了,可以去找它了"。

这之后,发起方才能顺利对目标设备做发现 / 发 Invitation。这套机制专门用来隔着 GO 把一个省电中的 Client"叫醒"——前提是该 Client 在入组时声明了支持 P2P Client Discovery(用 P2P Capability 里的 P2P Client Discovery 位)。

顺带回答一个普遍疑问:其实任何发现场景里,"先知道对方地址" 都不是前提。发现阶段的 Probe Request 用的是广播 / Wildcard(不指定具体 RA),对方应答时才把自己的 Device Address 报出来;而组内成员的地址则由 GO 在 Group Info 里主动公示。换句话说,地址是 "发现的产物",不是 "发现的前提"——你总是先广撒网碰到设备(或问到 GO),才拿到地址,而不是反过来。

你想约的人是另一个团的团员,而他正在帐篷里睡觉、手机静音。你连他叫什么都不知道,于是先找那个团的领队——领队手里有全团花名册(Group Info),随时翻给你看(你不用先认识团员本人)。你照着名册指出 "就找这位",领队过去把人摇醒、让他先别再睡(保持在线),然后回话告诉你 "人醒了,你可以去找他了"。

理清了 "怎么够得着",再看邀请本身的关键点:

  • 谁能发邀请? 组内的 GO 或 Client 都能发(§3.1.5.1)。所以不只是 "GO 邀请别人",一个普通团员也能拉人进自己的团。
  • Invitation Type 区分两种用途(就是 14.5 提到的那个标志位):
    • Type = 0:邀请一台设备加入正在运行的组——这就是你问的 "GO 怎么拉人进来"。
    • Type = 1:唤起一个之前建过的持久组(14.5 那个场景)。
  • 邀请只是 "开个头"。 目标设备接受后,真正的入组动作还是要走方向①那一套:到 GO 的 Operating Channel 上,没配过对就 Provision Discovery + WSC,配过就直接连(§3.1.5 明确指向 §3.2.3)。换句话说,邀请帧只是把对方 "叫" 到正确的信道、并告诉它该连哪个组,省去了对方满世界 Scan 去碰运气。

方向②是领队(或某个团员)掏出手机给外面的朋友发消息:"我们在 3 号广场,组名叫 XXX,过来吧!" 朋友答应后,照样得走到 3 号广场办入团手续(配对 / 关联)——但他不用自己满城找团了,因为你直接把地址甩给了他

Scan 是 "我去找团",Invitation 是 "团来拉我"。两条路最后都汇到同一个终点——在 GO 的信道上完成配对与关联。GO 协商(14.3)只发生在 "两台都没成组、要从头建组" 时;只要组已存在,加入就走这两条路之一,不再有 GO 协商。


7 电源管理 — 领队如何 "打个盹"

GO 扮演 AP,理论上要一直在线伺候 Client,很费电。P2P 定义了三套省电机制让 GO 能 "打盹"(§3.3,仅适用于 DMG 之外):前两套(OppPS、NoA)是 v1.0 就有的老方案,v2.0 新增了第三套基于 TWT 的省电(见 7.3)。

7.1 CTWindow 与 Opportunistic Power Save

**CTWindow(Client Traffic Window)** 是每个 TBTT(信标发送时刻)之后、GO 保证在线的一段时间(§3.3.2)。

Opportunistic Power Save(机会式省电):GO 把 NoA 属性里的 OppPS 位置 1、CTWindow 设为非零值。在每个 CTWindow 结束后,如果 GO 判断所有 Client 都进入了 Doze(休眠)状态,GO 就可以 "见缝插针" 地睡到下一个 TBTT(§3.3.3.1)。

领队规定 "每天早上 8:00–8:30 我一定在帐篷里听候差遣"(CTWindow)。过了这半小时,如果发现所有团员都还在睡觉,领队也就趁机眯一会儿——这就是 "机会式" 省电。

7.2 Notice of Absence — 提前公告 "我要离开"

Notice of Absence(NoA,缺席通知) 是更主动的省电:GO 提前在 Beacon / Probe Response 里公告一个 "我将不在场" 的时间表(§3.3.3.2),Client 据此知道这段时间别来找它。

NoA 缺席通知时序

NoA 时间表由 NoA Descriptor 的四个字段定义(§4.1.14, Table 43):

字段大小含义
Count/Type1 octet缺席的次数;255 = 持续(无限重复),0 保留不可用
Duration4 octets每次缺席多长(微秒)
Interval4 octets两次缺席间隔
Start Time4 octets时间表起始时刻(TSF 低 4 字节)

最多可同时有 2 个并发的 NoA 时间表(§3.3.3.2)。

领队在帐篷门口贴张告示:"我今天下午 2 点起出去办事,每次离开 30 分钟,每隔 1 小时一趟,共 3 趟。" 团员看到告示就知道什么时候找不到他,自己也趁机休息——大家一起省电。

省电状态优先级(§3.3.3.2,从高到低):

  1. 非周期 NoA(Count=1)的缺席(最高)
  2. 从 TBTT 到 Beacon 发送结束的在场
  3. CTWindow 期间的在场
  4. 周期 NoA(Count>1)的缺席(最低)

这意味着:无论什么 NoA 时间表,GO 都必须在每个 TBTT 醒来发 Beacon——告示牌本身不能停更。

Client 也可以反向发 P2P Presence Request 影响 GO 的省电节奏(比如 Client 有低延迟流量需求时),GO 用 P2P Presence Response 回应(§3.3.4.4)。

7.3 TWT-based 省电 — v2.0 的 "预约制"

v2.0 在 §3.3.3.5 引入第三套方案 TWT-based P2P Power Management:它不再靠 "见缝插针"(OppPS)或 "贴告示"(NoA),而是复用 IEEE 802.11 里的 TWT(Target Wake Time,目标唤醒时间) 机制——GO 在 Beacon / Probe Response 里广播一张 broadcast TWT 时间表(Broadcast TWT ID = 0),并把 Responder PM Mode 位置 1,宣告 "我只在预约的 TWT 服务期(SP)内在线,其他时间别来找我";Client 看到这张表,就知道该在哪个时间窗来敲门。

选择 TWT-based 省电的 GO 不能再同时用 OppPS 或 NoA(三选一,§3.3.3.5)。它的好处是:TWT 是 IEEE 已有的成熟机制,改动最小;时间表还能按需协商、灵活排布不在场时段,比 NoA 的固定周期更自由。GO 会在 v2.0 新增的 P2P Capability Extension 属性(见 14.10)里,把 TWT-based P2P Power Management 位置 1,向对端宣告自己支持这套玩法(§4.1.30, Table 64)。

前两套是 "见缝插针眯一会" 和 "门口贴告示",TWT 则是 "预约门诊"——领队提前排好值班表(broadcast TWT),团员按预约时间来,其余时间领队安心睡觉,双方都不用互相猜。


8 帧格式 — P2P IE 与关键属性

P2P 协议不发明新的 802.11 帧类型,而是复用 **Vendor Specific(厂商自定义)** 机制(§4.1.1, §4.2):

  • P2P IE(信息元素):基于 Vendor Specific IE,用 Wi-Fi Alliance 的 OUI = 50 6F 9A,OUI Type 指示 P2P。一个 P2P IE 携带一个或多个 P2P 属性
  • 两类 P2P 帧的 Category 不同,别混淆(均 OUI = 50 6F 9A;OUI Type 分两种——P2P IE 用 0x09、v2.0 新增的 P2P2 IE 用 0x28):
    • P2P Public Action 帧(用于组建立前的发现 / 协商):基于 Public Action 帧Category = 0x04、Action field = 0x09(§4.2.9,Table 91)。
    • P2P Action 帧(用于组内电源管理等):基于 Vendor Specific Action 帧Category = 0x7F(§4.2.10,Table 116)。

为什么要另起一个 P2P2 IE?v1.0 的 P2P IE 里,属性 ID 只定义到 28(外加 221 留给厂商自定义),这段编号在十余年里被越填越满。v2.0 想装的新能力——P2P Capability Extension(承载 TWT、6 GHz、P2P Pairing 等能力位)、WLAN AP Information、Device Identity Key 等——属性 ID 都落在 29 及以后(§4.1.1, Table 21)。与其硬塞进老 IE 让 v1.0 设备也去解析,不如新开一个 OUI Type 0x28 的 P2P2 IE 专门装它们:老设备看到不认识的 0x28 直接跳过,新设备两个都认——这就是一次干净的向后兼容版本分界。

8.1 P2P 属性表(部分)

P2P IE 里可携带的属性(§4.1.1, Table 21):

ID属性用途
0Status响应帧里的状态码
1Minor Reason Code细分原因码
2P2P Capability设备能力 + 组能力位图
3P2P Device ID目标设备地址
4Group Owner IntentGO 意愿值 + Tie-breaker
5Configuration Timeout配置所需时间
6Listen Channel监听信道
11Channel List支持的信道列表
12Notice of Absence缺席时间表
13P2P Device Info设备信息(名称、类型等)
14P2P Group Info组内成员信息
15P2P Group ID组标识(Device Address + SSID)
18Invitation Flags邀请类型
28Persistent Group Info持久组信息

8.2 P2P Public Action 帧(用于发现 / 协商)

承载 GO 协商、邀请、配置发现等组建立前的交互:

作用
GO Negotiation Request / Response / ConfirmationGO 协商三次握手
P2P Invitation Request / Response邀请加入 / 唤起持久组
Provision Discovery Request / Response协商 WPS 配置方法
Device Discoverability Request / Response发现处于省电的组内 Client

8.3 P2P Action 帧(用于组内管理)

承载组内的电源管理交互(§4.2.10, Table 117):

OUI Subtype
0Notice of Absence
1P2P Presence Request
2P2P Presence Response
3GO Discoverability Request

旅行团里,Public Action 帧是对外打的招呼(发现、协商、邀请,都冲着组外的人),Action 帧则是组内值日表——今天谁值日(NoA 缺席)、几点轮班(Presence Request/Response)、把睡着的叫醒(GO Discoverability Request),都是贴给自家人看的,外人进不来也用不着。


9 完整流程串讲

把全章串起来,两台手机用 Wi-Fi Direct 传文件,从发现到加密传输的逐帧过程如下图——这也是用 Wireshark 实际抓包时会看到的帧序列:

Wi-Fi Direct 完整帧交互

读图要点:① 发现分两步——先 Scan(A 扫遍信道、被动收 Beacon 做普查,不应答任何探测),再 Find(双方在社交信道交替 Listen/Search 互探碰头)。①②③ 都在关联之前完成,全部用 P2P Public Action 帧(Category 0x04、OUI 50 6F 9A)承载,抓包要开 monitor mode;从 ④ 关联起就回到标准 802.11 流程(关联 → WSC 配对 → 四次握手 → DHCP),和连普通 Wi-Fi 几乎无异。Provision Discovery(②)是可选的——它只是提前约定用哪种 WPS 配对法(谁显示 PIN、谁输入、还是双方按钮),跳过也能直接进 GO 协商。

注意这张图画的是从零建组(两台都没成组、需要 GO 协商)。若组已存在、只是有设备要加入,则没有 ③ GO 协商——走 14.6 的两条路之一(自己 Scan 加入,或被 Invitation 拉入),直接从 ④ 关联 / 配对接上。

用文字再串一遍:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1. 发现   两台手机进入 Find 阶段,在社交信道 1/6/11
交替 Listen(张望)和 Search(喊话),靠随机化
迟早在某个信道对上眼,交换设备名/类型

2. GO协商 三次握手交换 GO Intent。比如手机A填6、手机B填9
→ B 当 GO(领队),A 当 Client(团员)

3. 配对 跑 WPS:B(Registrar) 与 A(Enrollee) 用 PIN/PBC
配对,M1/M2 交换

4. 关联+安全 A 关联到 B,立即 四次握手协商密钥(WPA2/WPA3 · AES-CCMP)

5. 发IP B 作为 DHCP 服务器给 A 分配 IPv4 地址

6. 传输 A、B 在组内用 Interface Address 通信传文件
B 可用 NoA/OppPS 在空闲时打盹省电

7. 解散 传完断开,Interface Address 失效。若是持久组,
双方存下 Credentials,下次免协商秒重连

10 v2.0 的更新 — 老协议的新装备

本章内容按 Wi-Fi Direct® Specification v2.0(2025) 对齐,相对 v1.0 有几处值得单独拎出来的演进:

  • P2P2 IE(OUI Type 0x28:v1.0 只有 P2P IE(0x09),属性 ID 只排到 28;v2.0 新开 P2P2 IE 承载 ID ≥ 29 的新属性(P2P Capability Extension、WLAN AP Information、Device Identity Key 等),老设备自动跳过、新设备两个都认(§4.1.1)。
  • TWT 省电:新增第三套省电方案(§3.3.3.5),用 broadcast TWT 时间表代替 OppPS/NoA,见 14.7.3。
  • WPA3-Personal:组内加密从 "仅 WPA2-Personal" 升级为 WPA2-Personal 或 WPA3-Personal(SAE)(§3.2.6.1)。
  • Cross Connect 共享上网:明确 GO 可把 WLAN 上网能力转手给团员,此时 DHCP 才下发默认网关(§3.2.6.1),见 14.4.3。

除此之外,v2.0 还新增了 6 GHz 频段操作(§3.5)、5 GHz DFS 信道操作(§3.6)、非同步服务发现 USD(§3.7)、P2P Pairing 简化配对(§3.8)、BLE 辅助发现与配对(§3.9)和连接兼容模式 PCC Mode(§3.10)六块能力,它们共同构成 v2.0 相对 v1.0 的 "新装备" 全貌。

其中 USD(§3.7) 解决的是服务发现的同步约束:14.2 的老 Service Discovery 要先完成 Device Discovery、把两台设备汇聚到同一信道才能问 "你提供什么服务"——两步走、还依赖碰头。USD 复用 NAN 的 Service Discovery Frame,让 Seeker 按发布信道清单发 SDF 探询 Advertiser,设备发现与服务发现一帧同时完成,对已守在 Operating Channel 的 GO 更是免了来回切换。

P2P Pairing(§3.8) 则是对 14.4 WSC 一次性配对的补充:WSC 的 PIN/PBC 每次都要现场操作,配对后也不留长期身份。P2P Pairing 引入 DevIK(设备身份密钥)+ DIRA(设备身份解析地址)——配对时把 DevIK 通过安全信道递给对方,之后凭缓存的 DevIK 就能从 DIRA 的 Tag 反解出 "这是哪个老搭子",即便换了设备地址也认得;再走 PASN(DH group 19/20)做免输码的快速重认证,把 "每次对暗号" 升级成 "留了老交情"。

一句话:v2.0 没有推翻 P2P 的老框架,而是用 "新 IE + 新属性 + 新省电 + 更安全的加密" 给它补了装备,老设备依然能入团。


11 本章总结

机制作用旅行团比喻
GO / Client一台设备临时扮 AP临时推举领队 / 团员
Device / Interface Address终身身份 vs 组内临时身份身份证 / 临时工牌
Scan + Find(Listen/Search)在社交信道汇聚在约定广场轮流张望与喊话
社交信道 1/6/11 + 随机化快速碰头、避免锁步只在三个广场碰头、随机错峰
GO Intent + Tie-breaker从零建组时决定谁当 GO选召集人,平局抛硬币
WPS Provisioning配对换凭证加好友、对暗号
四次握手 + GO 当 DHCP加密 + 发组内编号发队内编号,不发回家地址
Scan 加入 / Invitation 邀请加入已存在的组的两条路自己找团 / 团来拉我
Persistent Group免协商秒重连老搭子直接约
NoA / OppPSGO 省电领队提前贴告示去打盹
P2P IE / Action 帧复用 Vendor Specific 承载队内专用暗号

v2.0 能力位速查(P2P Capability Extension,§4.1.30 Table 64):

能力bit置 1 含义
6 GHz Band Capable4支持在 6 GHz 频段建组
P2P Pairing Capable8支持 WPA3 简化配对
TWT-based P2P Power Mgmt12支持 TWT 预约制省电

Wi-Fi Direct 的精髓是:用一台普通设备临时扮演 AP,让 "设备直连" 既不依赖路由器,又复用了 802.11 成熟的关联与安全机制。 它和下一章的 TDLS 同属 "设备直连",但走了一条彻底抛开 AP 的路;两者对照着读,最能看清 "直连" 的两种思路。


下一章将讲述:P2P 是 "不要 AP 的直连",而 TDLS 偏偏是 "连着 AP 却仍要直连"——都连同一个路由器的两台设备,为什么数据还要绕 AP 中转?怎么抄近路?为什么建立直连的信令反而要" 先借道 AP"?建好之后又怎么切到更空闲的信道提速?