3. 蓝牙核心规范与互操作测试依据
做 Nordic nRF 蓝牙互操作测试,第一步不是打开 nRF Connect 或抓包器,而是先弄清楚“依据是什么”。蓝牙核心规范(Bluetooth Core Specification)把协议栈拆成若干层,每一层都同时定义了强制要求(Mandatory,M)和可选特性(Optional,O)。互操作测试的本质,就是验证被测设备(DUT)在某一层是否满足它“声称支持”的那部分要求,并且在与不同厂商设备交互时行为一致。规范里没有“大概支持”这种说法:一个特性要么声明支持并必须按规范行为,要么声明不支持并必须正确拒绝或忽略。
从测试视角看,核心规范可以分成两条主线。第一条是“连接与链路”主线:LL(Link Layer)、L2CAP、SMP,负责设备如何被发现、建立链路、加密和分配信道。第二条是“数据与服务”主线:ATT、GATT、GAP,负责数据如何组织、读写、通知,以及设备如何广播和连接。互操作问题往往不是单层出错,而是跨层传导——例如 LL 的连接参数更新被拒绝,会表现为 GATT 操作超时;SMP 配对失败,会让需要加密的特征读写直接返回错误。
先看 GAP。GAP 定义了四种角色:Broadcaster、Observer、Peripheral、Central。互操作测试中最常见的争议点是广播数据格式和连接参数。规范强制要求 LE 广播包中的 AD 结构必须符合“长度+类型+数据”的格式,且 Flags AD 类型(0x01)在可连接广播中必须存在。可选特性包括扩展广播(Extended Advertising)、周期性广播(Periodic Advertising)和 LE 功率控制。如果 DUT 声明支持扩展广播,就必须能正确解析和发送扩展广播头,否则与只支持传统广播的设备交互时会出现扫描不到的问题。
GATT 和 ATT 是互操作问题最集中的地方。ATT 是底层协议,规定了属性句柄、操作码和错误码;GATT 在其上定义了服务发现、特征读写和通知/指示的语义。强制要求包括:ATT_MTU 默认至少为 23 字节;Exchange MTU Request 必须能被正确响应;Read By Group Type 和 Find Information 请求必须返回规范定义的响应格式。可选特性包括长属性读/写(Prepare Write + Execute Write)、通知与指示、以及服务变更特征(Service Changed)。测试时经常遇到的一个互操作问题是:客户端发送 Exchange MTU Request 请求 247 字节,服务端返回 23 字节,此时客户端必须按 23 字节继续工作,而不是直接断开。这个“降级兼容”行为就是强制要求的一部分。
L2CAP 在 LE 上主要承担信道复用和信令。强制要求是 LE 信令信道 CID=0x0005 必须支持,ATT 固定信道 CID=0x0004 必须存在。可选特性包括 LE 信用基于流控模式(LE Credit Based Flow Control)和增强信用基于流控模式(Enhanced Credit Based Flow Control),后者常用于 CoC(Connection-oriented Channels)。互操作测试中,如果 DUT 声明支持 CoC,就必须正确实现信令命令的拒绝和参数协商,否则与不同厂商的 CoC 实现对接时会卡在连接建立阶段。
SMP 负责配对和密钥分发。强制要求包括 Pairing Request/Response 的交换、加密启动流程、以及密钥分发格式。可选特性包括 LE Secure Connections、MITM 保护、以及密钥长度协商。一个典型的互操作场景是:Central 发起配对请求,要求 MITM 保护,Peripheral 只支持 Just Works。此时 Peripheral 必须返回正确的 Pairing Response,将 MITM 标志置为 0,而不是直接拒绝。如果 DUT 错误地拒绝了配对请求,就会导致后续需要加密的 GATT 操作全部失败。
LL 是链路层,直接决定连接能否建立和维持。强制要求包括广播、扫描、发起连接的状态机行为,以及连接参数更新流程。可选特性包括 LE 2M PHY、LE Coded PHY、周期性广播同步传输等。互操作测试中,连接参数更新是最容易出问题的环节:Central 发送 Connection Parameter Update Request,Peripheral 可以接受或拒绝。如果拒绝,必须发送带有正确原因码的 Response,而不是静默丢弃。静默丢弃会导致 Central 一直等待,最终连接超时断开。
测试依据的落地方法:在 nRF Connect SDK 中,可以通过 bt_gatt_service_register() 注册服务,通过 bt_le_adv_start() 启动广播。测试时先用 nRF Connect for Mobile 作为 Central,观察服务发现是否完整、MTU 协商结果、通知是否按预期到达。再用另一台不同厂商的手机作为 Central 重复同样操作,对比行为差异。差异点就是互操作测试需要重点记录和判定的对象。
把上述规范要求整理成一张可执行的检查表,比泛泛阅读规范更有效。下面给出一个针对 GAP/GATT/ATT/SMP/LL 的互操作测试检查表示例,字段和判定依据均来自核心规范的强制/可选划分。
| 协议层 | 测试项 | 强制/可选 | 预期行为 | 判定依据 |
|---|---|---|---|---|
| GAP | 可连接广播包含 Flags AD | 强制 | 广播包中存在 0x01 类型 AD 结构 | 扫描响应可被不同厂商 Central 解析 |
| GAP | 扩展广播 | 可选 | 声明支持时能正确收发扩展广播头 | 与只支持传统广播的设备交互不崩溃 |
| ATT | MTU 协商降级 | 强制 | 请求 247 返回 23 时按 23 继续 | 后续读写不因 MTU 变小而失败 |
| GATT | 服务发现完整性 | 强制 | 所有 Primary Service 可被 Read By Group Type 发现 | 不同 Central 发现结果一致 |
| SMP | MITM 降级 | 强制 | 不支持 MITM 时返回 MITM=0 的 Pairing Response | 配对流程不中断,加密可继续 |
| LL | 连接参数更新拒绝 | 强制 | 拒绝时发送带原因码的 Response | Central 不因等待超时而断开 |
| L2CAP | CoC 信令拒绝 | 可选 | 声明支持时正确返回拒绝原因 | 与不同厂商 CoC 实现对接不卡死 |
需要特别强调的是,规范中的“可选”不等于“可以不做”。一旦设备在广播、服务声明或配对请求中声称支持某个可选特性,它就必须按照规范完整实现该特性的行为。互操作测试的判定逻辑是:先确认 DUT 声明了什么,再验证它是否做到了声明的内容,最后验证它在与不同厂商设备交互时是否保持一致。这三步缺一不可。
在实际项目中,建议把上述检查表与 nRF Connect SDK 的日志结合使用。打开 CONFIG_BT_DEBUG_LOG=y 和 CONFIG_BT_ATT_DEBUG=y,可以在串口日志中看到 ATT PDU 的收发方向、操作码和错误码。例如看到 ATT_OP_ERROR_RSP 时,对照规范中的错误码表判断是“属性未找到”还是“权限不足”。日志中的 HCI 事件则能反映 LL 层的连接参数更新是否被接受。把日志、抓包和检查表三者对照,才能把“规范要求”真正落到“互操作判定”上。