Capturing BLE Traffic
This guide shows how to capture BLE traffic for debugging and protocol analysis.
Methods
Section titled “Methods”| Method | Platform | Captures |
|---|---|---|
| btmon/btsnoop | Linux | All HCI traffic |
| Android HCI log | Android | Phone ↔ Device |
| Wireshark + nRF Sniffer | Any | Over-the-air |
Linux: btmon
Section titled “Linux: btmon”The easiest method on Linux is using btmon to capture HCI traffic.
Start Capture
Section titled “Start Capture”-
Open a terminal for btmon
Terminal window sudo btmon -w capture.btsnoop -
In another terminal, connect to the device
Terminal window bluetoothctl connect 5B:A6:86:38:FA:CA -
Perform operations (measurements, commands, etc.)
-
Stop capture with Ctrl+C
Analyze Capture
Section titled “Analyze Capture”# View packet summarybtmon -r capture.btsnoop | head -100
# Filter to ATT packets onlybtmon -r capture.btsnoop | grep -E "(ATT|Write|Notify)"
# Export to pcap for Wiresharkbtmon -r capture.btsnoop -w capture.pcapExample Output
Section titled “Example Output”> HCI Event: LE Meta Event (0x3e) plen 10 LE Connection Complete (0x01) Status: Success (0x00) Handle: 64 Address: 5B:A6:86:38:FA:CA (Random)
> ACL Data TX: Handle 64 flags 0x00 dlen 9 ATT: Write Command (0x52) len 4 Handle: 0x000a Data: f1030205 ← GET_DEVICE_MAC command
< ACL Data RX: Handle 64 flags 0x02 dlen 22 ATT: Handle Value Notification (0x1b) len 17 Handle: 0x000c Data: f103000c356261363836333866616361 ← ResponseAndroid: HCI Snoop Log
Section titled “Android: HCI Snoop Log”Enable Bluetooth HCI logging on your Android device.
-
Enable Developer Options
- Settings → About Phone → Tap “Build Number” 7 times
-
Enable HCI Snoop Log
- Settings → Developer Options → Enable Bluetooth HCI Snoop Log
-
Reproduce the behavior in the Huepar app
-
Disable logging when done
-
Pull the log file
Terminal window adb pull /data/misc/bluetooth/logs/btsnoop_hci.log
Wireshark Analysis
Section titled “Wireshark Analysis”Open .btsnoop or .pcap files in Wireshark for detailed analysis.
Useful Filters
Section titled “Useful Filters”# All ATT protocol packetsbtatt
# Write operations onlybtatt.opcode == 0x52 || btatt.opcode == 0x12
# Notifications onlybtatt.opcode == 0x1b
# Specific handle (0xAE01 characteristic)btatt.handle == 0x000a
# Packets containing F1 (our protocol header)btatt.value contains f1Decoding Packets
Section titled “Decoding Packets”Wireshark shows ATT layer details:
Bluetooth Attribute Protocol Opcode: Handle Value Notification (0x1b) Handle: 0x000c (Characteristic Value) Value: f103000c356261363836333866616361 │ │ └─ "5ba68638faca" ASCII │ └──── Length: 12 └────────── Response type: MACMCP Bluetooth Tools
Section titled “MCP Bluetooth Tools”If you have the mcbluetooth MCP server configured, you can capture directly:
# Start capturebt_capture_start --output capture.btsnoop --adapter hci0
# ... perform operations ...
# Stop and get resultsbt_capture_stop --capture-id <id>
# Parse the capturebt_capture_parse --filepath capture.btsnoop --max-packets 100Packet Structure Reference
Section titled “Packet Structure Reference”Command Packet (App → Device)
Section titled “Command Packet (App → Device)”ATT Write Command to handle 0x000A:┌────────────────────────────────────────┐│ F1 │ Type │ Sub │ Param │ Checksum │└────────────────────────────────────────┘Response Packet (Device → App)
Section titled “Response Packet (Device → App)”ATT Handle Value Notification from 0x000C:┌─────────────────────────────────────────────┐│ F1 │ Response │ Status │ Data... │ Checksum │└─────────────────────────────────────────────┘Tips for Analysis
Section titled “Tips for Analysis”-
Correlate commands with responses - Match TX packets with subsequent RX
-
Check checksums - Verify
sum(bytes[1:]) % 256 -
Note timing - Device may timeout if commands are slow
-
Compare with app - Use Android HCI log alongside btmon for reference
-
Focus on data bytes - Ignore ATT headers, focus on payload
Example Analysis Session
Section titled “Example Analysis Session”# Terminal 1: Start capturesudo btmon -w session.btsnoop
# Terminal 2: Connect and interactbluetoothctl connect 5B:A6:86:38:FA:CA
# Use Python to send commandspython3 -c "import asynciofrom bleak import BleakClient
async def main(): async with BleakClient('5B:A6:86:38:FA:CA') as c: await c.write_gatt_char('0000ae01-...', bytes([0xF1,0x03,0x02,0x05])) await asyncio.sleep(1)
asyncio.run(main())"
# Terminal 1: Ctrl+C to stop, then analyzebtmon -r session.btsnoop | grep -A2 "Write\|Notify"Related Pages
Section titled “Related Pages”- Command Reference - Understand what you’re capturing
- Response Reference - Decode response packets
- Connecting Guide - Connection setup