4. BLE 抓包实战(上):使用 nRF Sniffer 与 Wireshark 抓取广播包、解析 ADV_IND 与 ADV_DIRECT_IND
做 BLE 开发,最怕什么?
怕设备连不上,怕数据发丢了,怕功耗下不来。这时候,光靠看代码是没用的。你得亲眼看看空口上到底发生了什么。
抓包,就是给无线通信装上一台「行车记录仪」。今天咱们就来实战,用 nRF Sniffer 配合 Wireshark,把 BLE 的广播包抓下来,一条一条拆开看。
4.1 准备工作:硬件与软件环境
先说说硬件。我手头最常用的是 nRF52840 DK 开发板,它自带一个 J-Link 调试器,刷个 Sniffer 固件就能当抓包器用。如果你手头是 nRF52832 DK 或者 nRF51 DK,也一样,步骤完全相同。
软件方面,你需要装三样东西:
- nRF Sniffer for BLE —— 这是 Nordic 官方的抓包固件和配套插件。去 Nordic 官网下载,版本建议选 4.x 以上,支持 BLE 5.x。
- Wireshark —— 网络抓包神器,版本 3.x 以上都行。我个人习惯用 3.6 或 4.0,界面更清爽。
- Python 3 —— nRF Sniffer 的 Wireshark 插件依赖 Python 运行。
4.2 刷写 Sniffer 固件
把开发板用 USB 线连到电脑。打开 nRF Connect Programmer,选择你的开发板,把下载好的 nrf_sniffer_for_ble_4.x.hex 文件拖进去,点「Write」。几秒钟就刷好了。
刷完后,板子会变成一个 BLE 嗅探器。你可以在设备管理器里看到一个新的 COM 口,或者一个 Wireshark 能识别的 USB 设备。
4.3 配置 Wireshark 与 nRF Sniffer 插件
装好 Wireshark 后,把 nRF Sniffer 包里的 extcap 文件夹复制到 Wireshark 的安装目录下。重启 Wireshark,你应该能在接口列表里看到一个叫 nRF Sniffer for BLE 的接口。
选中它,点开始。如果一切正常,Wireshark 会立刻开始显示空口上的 BLE 数据包。
嗯,这里要注意:默认情况下,Sniffer 会扫描所有信道(37/38/39),但只抓广播包。如果你想抓连接后的数据包,需要指定一个目标设备的 MAC 地址。这个我们下一节再细说。
4.4 抓取广播包:ADV_IND 与 ADV_DIRECT_IND
现在,让一个 BLE 设备(比如你的手机或另一块开发板)开始广播。Wireshark 里应该会刷出一堆包。
咱们先看最常见的两种广播包:
| 广播类型 | PDU 类型值 | 含义 | 典型场景 |
|---|---|---|---|
| ADV_IND | 0x00 | 可连接的非定向广播 | 普通 Beacon、设备可被发现 |
| ADV_DIRECT_IND | 0x01 | 可连接的定向广播 | 快速重连、已知设备配对 |
| ADV_NONCONN_IND | 0x02 | 不可连接的非定向广播 | iBeacon、Eddystone |
| ADV_SCAN_IND | 0x06 | 可扫描的非定向广播 | 被动扫描场景 |
在 Wireshark 里,展开一个广播包,你会看到这样的结构:
Bluetooth LE Link Layer
[Direction: Advertised (0)]
Advertising Channel PDU
Header: 0x00 (ADV_IND)
PDU Type: ADV_IND (0x00)
ChSel: 2
TxAdd: Random (1)
RxAdd: Public (0)
Length: 31
Advertising Address: xx:xx:xx:xx:xx:xx
Advertising Data: ...
关键字段就这几个:
- PDU Type —— 告诉你这是哪种广播包。
- TxAdd / RxAdd —— 地址类型,是 Public 还是 Random。很多设备为了隐私会用 Random 地址。
- Advertising Address —— 广播者的 MAC 地址。
- Advertising Data —— 广播数据,最多 31 字节。
4.5 深入解析 ADV_IND 广播数据
ADV_IND 是最常见的广播包。它的广播数据部分,由若干个 AD Structure(Advertising Data Structure)组成。每个 AD Structure 的格式是:
+--------+--------+--------+--------+--------+
| Length | Type | Data ... |
+--------+--------+--------+--------+--------+
- Length:1 字节,表示 Type + Data 的总长度。
- Type:1 字节,表示数据类型。比如 0x01 是 Flags,0x09 是 Complete Local Name。
- Data:Length - 1 字节,具体数据。
举个例子,我在项目中遇到过一款智能灯,它的广播数据里同时包含了 Flags、Complete Local Name 和 Manufacturer Specific Data。Wireshark 会自动解析这些字段,你直接看就行。
但有时候,Wireshark 解析不出来某些厂商自定义数据。这时候就得手动看 Hex 了。我习惯在 Wireshark 里右键 ->「Copy」->「Bytes as Hex Stream」,然后贴到 Hex 编辑器里慢慢看。
4.6 解析 ADV_DIRECT_IND:定向广播的秘密
ADV_DIRECT_IND 跟 ADV_IND 长得有点像,但有个关键区别:它包含两个 MAC 地址。
- AdvA:广播者的地址。
- TargetA:目标设备的地址。
说白了,定向广播就是「我只想跟这个设备说话,其他人别理我」。这种广播包在快速重连场景里很常见。比如你的手机靠近一个已配对的蓝牙耳机,耳机就会发 ADV_DIRECT_IND,直接找手机。
定向广播的优点是:
- 连接建立更快,因为扫描器不需要做过滤。
- 功耗更低,因为广播间隔可以设得很短(比如 3.75ms)。
但缺点也很明显:
- 目标设备必须知道广播者的地址,否则收不到。
- 定向广播不包含广播数据,只有两个地址。
你想想看,如果两个设备之前已经配对过,互相知道对方的 MAC 地址,那用 ADV_DIRECT_IND 重连,速度会快很多。我在做智能门锁项目时,就用这个机制实现了「靠近即开锁」的效果,用户体验非常好。
4.7 抓包实战中的常见问题
抓包过程中,你可能会遇到几个坑。我一个个说:
- 抓不到包? 检查 Sniffer 固件是否刷对,Wireshark 接口是否选对。有时候 USB 线质量不好也会导致数据丢失。
- 包太多,眼花缭乱? 在 Wireshark 里加过滤条件。比如只显示某个 MAC 地址的包:
btle.advertising_address == xx:xx:xx:xx:xx:xx。 - 广播数据解析不全? 有些厂商自定义数据,Wireshark 不认识。这时候可以装一个 Wireshark 的 Lua 解析器,或者手动看 Hex。
- Sniffer 掉线? 我遇到过几次,原因是 USB 供电不足。换个 USB 口,或者用带外接电源的 USB Hub 就能解决。
4.8 知识结构图:BLE 广播包抓包流程
下面这张图,把整个抓包流程串起来了。从硬件准备到数据解析,每一步都标清楚了。
4.9 实战小结
今天咱们把 BLE 广播包的抓包流程走了一遍。从硬件准备到 Wireshark 配置,再到 ADV_IND 和 ADV_DIRECT_IND 的解析,每一步都有实操价值。
我个人觉得,抓包是调试 BLE 协议栈最有效的手段。没有之一。你写再多代码,不如亲眼看看空口上到底发了什么。很多连接失败、功耗异常的问题,一抓包就原形毕露。
下次遇到设备连不上的问题,别急着改代码。先抓个包看看,说不定问题就出在广播数据上。