btmonπ
Bluetooth monitorπ
- Authors:
Marcel Holtmann <marcel@holtmann.org>
Tedd Ho-Jeong An <tedd.an@intel.com>
- Copyright:
Free use of this software is granted under the terms of the GNU Lesser General Public Licenses (LGPL).
- Version:
BlueZ
- Date:
April 2021
- Manual section:
1
- Manual group:
Linux System Administration
SYNOPSISπ
btmon [OPTIONS β¦]
DESCRIPTIONπ
The btmon(1) command provides access to the Bluetooth subsystem monitor infrastructure for reading HCI traces.
OPTIONSπ
- -r FILE, --read FILE
Read traces in btsnoop format from FILE.
- -w FILE, --write FILE
Save traces in btsnoop format to FILE.
- -a FILE, --analyze FILE
Analyze traces in btsnoop format from FILE. It displays the devices found in the FILE with its packets by type. If gnuplot is installed on the system it also attempts to plot packet latency graph.
- -s SOCKET, --server SOCKET
Start monitor server socket.
- -p PRIORITY, --priority PRIORITY
Show only priority or lower for user log.
PRIORITY |
NAME |
|---|---|
3 |
Error |
4 |
Warning |
6 |
Information (Default) |
7 |
Debug. debug can be used. |
- -i NUM, --index NUM
Show only specified controller. hciNUM is also acceptable. This is useful to capture the traces from the specific controller when the multiple controllers are presented.
- -d TTY, --tty TTY
Read data from TTY.
- -B SPEED, --rate SPEED
Set TTY speed. The default SPEED is 115300
- -V COMPID, --vendor COMPID
Set the default company identifier. The COMPID is a unique number assigned by the Bluetooth SIG to a member company and can be found/searched from the Bluetooth SIG webpage.
For example, Intel is 2 and Realtek is 93.
- -M, --mgmt
Open channel for mgmt events.
- -K, --kernel
Open kmsg for kernel messages.
- -t, --time
Show a time instead of time offset.
- -T, --date
Show a time and date information instead of time offset.
- -N, --no-time
Suppress the time offset display entirely.
- -S, --sco
Dump SCO traffic in raw hex format.
- -A, --a2dp
Dump A2DP stream traffic in a raw hex format.
- -I, --iso
Dump ISO stream traffic in raw hex format. Required to see LE Audio isochronous data in the output.
- -E IP, --ellisys IP
Send Ellisys HCI Injection.
- -P, --no-pager
Disable pager usage while reading the log file.
- -J OPTIONS, --jlink OPTIONS
Read data from RTT. Each options are comma(,) separated without spaces.
OPTIONS |
Description |
|---|---|
DEVICE |
Required. Set the target device. |
SERIALNO |
(Optional) Set the USB serial number. Default is 0. |
INTERFACE |
(Optional) Target interface. Default is swd. |
SPEED |
(Optional) Set target interface speed in kHz. Default is 1000. |
- -R OPTIONS, --rtt OPTIONS
RTT control block parameters. Each options are comma(,) separated without spaces.
OPTIONS |
Description |
|---|---|
ADDRESS |
(Optional) Address of RTT buffer. Default is 0x00 |
AREA |
(Optional) Size of range to search in RTT buffer. Default is 0 |
NAME |
(Optional) Buffer name. Default is btmonitor |
- -C WIDTH, --columns WIDTH
Output width if not a terminal
- -c MODE, --color MODE
Set output color. The possible MODE values are: auto|always|never.
Default value is auto
- -v, --version
Show version
- -h, --help
Show help options
READING THE OUTPUTπ
btmon output is organized as a stream of frames, each representing a single event in the Bluetooth subsystem. Understanding the output format is essential for debugging Bluetooth issues.
Line Prefixesπ
Every frame begins with a single-character prefix that identifies its source and type:
Prefix |
Meaning |
Description |
|---|---|---|
|
HCI Command / Data TX |
Sent from host to controller (outgoing). HCI commands, ACL/SCO/ISO data transmitted to the controller. |
|
HCI Event / Data RX |
Received from controller to host (incoming). HCI events, ACL/SCO/ISO data received from the controller. |
|
Management traffic |
Management interface (MGMT) commands and events between bluetoothd and the kernel management layer. |
|
System notes |
System-level annotations: kernel information, index changes, process log messages, and D-Bus signals. |
HCI Traffic (< and >)π
HCI frames represent the actual communication between the host software and the Bluetooth controller hardware.
Anatomy of an HCI command line:
< HCI Command: Reset (0x03|0x0003) plen 0 #5 [hci0] 12:35:01.843185
β β β β β β β β
β β β β β β β ββ Timestamp
β β β β β β ββ Controller
β β β β β ββ Frame number
β β β β ββ Parameter length (bytes)
β β β ββ Full opcode (16-bit)
β β ββ OGF|OCF (Opcode Group / Command Field)
β ββ Command name (human-readable)
ββ Direction: < = Host to Controller (outgoing)
Anatomy of an HCI event line:
> HCI Event: Command Complete (0x0e) plen 4 #6 [hci0] 12:35:01.864922
β β β β β β
β β β β β ββ Timestamp
β β β β ββ Controller
β β β ββ Frame number
β β ββ Parameter length
β ββ Event code
β
ββ Direction: > = Controller to Host (incoming)
The < direction means the host is sending to the controller (commands
and data). The > direction means the controller is sending to the host
(events and data). Think of it from the controllerβs perspective: < is
input going into the controller, > is output coming from it.
HCI commands with parameters are followed by indented detail lines:
< HCI Command: LE Set Extende.. (0x08|0x0039) plen 2 #1 [hci0] 12:35:01.738352
Extended advertising: Disabled (0x00)
Number of sets: Disable all sets (0x00)
HCI event responses reference the command they complete:
> HCI Event: Command Complete (0x0e) plen 4 #6 [hci0] 12:35:01.864922
Reset (0x03|0x0003) ncmd 2
Status: Success (0x00)
Here ncmd 2 indicates the controller can accept 2 more commands
(HCI flow control). The indented body shows the command this event
completes and the result status.
LE Meta Events contain a subevent type:
> HCI Event: LE Meta Event (0x3e) plen 31 #487 [hci0] 12:36:18.974201
LE Enhanced Connection Complete (0x0a)
Status: Success (0x00)
Handle: 2048
Role: Peripheral (0x01)
Peer address type: Public (0x00)
Peer address: AA:BB:CC:DD:EE:FF (OUI Company)
Connection interval: 60.00 msec (0x0030)
Connection latency: 0 (0x0000)
Supervision timeout: 9600 msec (0x03c0)
ACL Data shows data plane traffic with handle and protocol decoding:
< LE-ACL: Handle 2048 [66:B0:26:F1:D3:BC] [1/6] flags 0x00 dlen 16 #493 [hci0] 12:36:18.977915
β β β β β β β β β β
β β β β β β β β β ββ Timestamp
β β β β β β β β ββ Controller
β β β β β β β ββ Frame number
β β β β β β ββ Data length
β β β β β ββ flags
β β β β ββ Buffer tracking (optional)
β β β ββ Peer address (optional)
β β ββ Handle number
β ββ Connection-type-aware label (e.g. BR-ACL, LE-ACL, BR-SCO, LE-ISO)
ββ Direction marker: '<' = host->controller (TX), '>' = controller->host (RX)
ACL data is automatically decoded into higher-layer protocols:
< LE-ACL: Handle 2048 [2/6] flags 0x00 dlen 7 #494 [hci0] 12:36:18.978488
ATT: Exchange MTU Request (0x02) len 2
Client RX MTU: 517
> LE-ACL: Handle 2048 flags 0x02 dlen 11 #497 [hci0] 12:36:19.000048
SMP: Pairing Request (0x01) len 6
IO capability: NoInputNoOutput (0x03)
OOB data: Authentication data not present (0x00)
Authentication requirement: Bonding, MITM, SC, No Keypresses, CT2 (0x2d)
Max encryption key size: 16
Management Traffic (@)π
Lines starting with @ show management interface traffic β the structured
command/event protocol between bluetoothd and the kernel (see
doc/mgmt-protocol.rst).
Anatomy of a management line:
@ MGMT Command: Set Powered (0x0005) plen 1 {0x0001} [hci0] 12:35:04.033564
β β β β β β
β β β β β ββ Timestamp
β β β β ββ Controller
β β β ββ MGMT socket ID
β β ββ Parameter length
β ββ MGMT opcode
ββ @ = Management channel
The {0x0001} is the management socket identifier β it distinguishes
between multiple management clients (e.g. bluetoothd and btmgmt running
simultaneously).
MGMT Open/Close track when processes connect to the management channel:
@ MGMT Open: bluetoothd (privileged) version 1.23 {0x0001} 12:34:49.881936
@ MGMT Close: bluetoothd {0x0001} 12:35:01.866256
These show the process name, privilege level, and protocol version.
MGMT commands with parameters:
@ MGMT Command: Set Powered (0x0005) plen 1 {0x0001} [hci0] 12:35:04.033564
Powered: Enabled (0x01)
MGMT events (responses and notifications):
@ MGMT Event: Command Complete (0x0001) plen 7 {0x0001} [hci0] 12:35:04.114789
Set Powered (0x0005) plen 4
Status: Success (0x00)
Current settings: 0x004e0ac1
Powered
Secure Simple Pairing
MGMT without controller index (global operations):
@ MGMT Command: Read Management Ver.. (0x0001) plen 0 {0x0001} 12:35:04.027771
@ MGMT Event: Command Complete (0x0001) plen 6 {0x0001} 12:35:04.027776
Notice there is no [hci0] β these operate at the system level,
not on a specific controller.
System Notes (=)π
Lines starting with = are system-level annotations injected by the
kernel or by processes via the monitor channel. They are not HCI or
MGMT protocol traffic.
Kernel information (shown at startup):
= Note: Linux version 6.16.0-rc6-0903 (x86_64) 12:34:49.881926
= Note: Bluetooth subsystem version 2.22 12:34:49.881930
Index lifecycle (controller added/removed/opened/closed):
= New Index: 00:11:22:33:44:55 (Primary,USB,hci0) [hci0] 12:34:49.881932
= Open Index: 00:11:22:33:44:55 [hci0] 12:34:49.881933
= Index Info: 00:11:22:33:44:55 (OUI Company) [hci0] 12:34:49.881934
= Close Index: 00:11:22:33:44:55 [hci0] 12:35:01.865125
New Indexβ a controller was registered with the kernelOpen Indexβ a controller was activatedIndex Infoβ controller vendor informationClose Indexβ a controller was deactivated
Process log messages (debug output from bluetoothd and other daemons):
= bluetoothd: src/adapter.c:connected_callback() hci0 devic.. 12:36:18.975307
β β β
β β ββ Timestamp
β ββ Source file, function, and message (may be truncated)
ββ Process name
These appear when bluetoothd is running with debug enabled (-d)
or when a process writes to the kernel logging channel. They show the
source file path, function name, and a log message β invaluable for
correlating daemon-internal decisions with the HCI traffic around them.
D-Bus activity (signals and method calls):
= bluetoothd: [:1.21220:method_call] > org.freedesktop.DBus.. 12:34:53.912508
= bluetoothd: [:1.21220:method_return] < [#5] 12:34:53.912546
= bluetoothd: [signal] org.freedesktop.DBus.ObjectManager.I.. 12:36:18.975691
The format is [bus_name:message_type] followed by > (outgoing) or
< (incoming). Note that > and < within D-Bus system notes
indicate D-Bus message direction, not HCI direction.
Right-Side Metadataπ
Every line has metadata right-aligned at the end. The exact fields depend on the line type:
ββ Main content (left-aligned, variable width)
β ββ Frame # ββ βControllerβ ββ Timestamp ββ
β β β β β β β
< HCI Command: Reset (0x03|0x0003) plen 0 #5 [hci0] 12:35:01.843185
> HCI Event: Command Complete (0x0e) plen 4 #6 [hci0] 12:35:01.864922
@ MGMT Command: Set Powered (0x0005) plen 1 {0x0001} [hci0] 12:35:04.033564
= Note: Linux version 6.16.0-rc6-0903 (x86_64) 12:34:49.881926
= Open Index: 00:11:22:33:44:55 [hci0] 12:34:49.881933
Frame number (#N): Sequential counter for HCI frames only. Useful
for identifying specific packets in a trace. Only HCI traffic (< and
>) gets frame numbers β MGMT (@) and system notes (=) do not.
Controller ([hciN]): Identifies which Bluetooth controller the
frame belongs to. Absent for global operations (kernel notes, MGMT
commands without a controller index).
MGMT socket ID ({0xNNNN}): Shown on @ lines instead of frame
numbers. Identifies which management socket (process) sent the command.
Timestamp: Always the rightmost field. The format depends on the command-line option used:
Option |
Format |
Example |
|---|---|---|
(default) |
Seconds since trace start |
|
|
Time of day (HH:MM:SS.usec) |
|
|
Full date and time |
|
Indented Detail Linesπ
Lines indented below a frame header contain the decoded payload of that frame. The indentation level indicates the protocol layer:
First level (6 spaces): direct payload of the HCI/MGMT frame
Second level (8 spaces): decoded fields within the payload
Third level (10+ spaces): nested protocol data (e.g. L2CAP inside ACL, ATT inside L2CAP)
Example of protocol layering in ACL data:
> ACL: Handle 2048 flags 0x02 dlen 11 #497 [hci0] 12:36:19.000048
SMP: Pairing Request (0x01) len 6 β L2CAP/SMP layer
IO capability: NoInputNoOutput (0x03) β SMP fields
OOB data: Authentication data not present (0x00)
Authentication requirement: Bonding, MITM, SC (0x2d)
Max encryption key size: 16
Timestamp Notesπ
When reading btsnoop files with -t or -T, timestamps reflect the
wall-clock time recorded in the btsnoop file. The precision depends on
the source:
Live capture (
btmonmonitor channel): Microsecond precision from the kernel.btsnoop files: The btsnoop format stores timestamps as microseconds since epoch, so full microsecond precision is preserved. Trailing zeros in the display (e.g.,
14:38:46.589000) indicate the original capture source had millisecond granularity.
The default timestamp mode shows seconds elapsed since the first packet in the trace, which is useful for measuring intervals between events without needing to know the absolute time.
Frame Numbers vs Line Numbersπ
btmon assigns sequential frame numbers (#N) to HCI packets.
These are stable identifiers for specific packets regardless of output
formatting. However, when processing btmon text output with tools like
grep or sed, the relevant unit is line numbers in the output
file. The two are unrelated:
A single frame may produce many output lines (header + decoded fields).
Frame numbers only apply to HCI traffic (
<and>). MGMT (@) and system notes (=) do not have frame numbers.When referencing specific packets, prefer frame numbers (
#487) over line numbers, as frame numbers are stable across different terminal widths and formatting options.
Practical Reading Guideπ
Typical command-response pair:
< HCI Command: Read BD ADDR (0x04|0x0009) plen 0 #13 [hci0] 12:35:04.057866
> HCI Event: Command Complete (0x0e) plen 10 #14 [hci0] 12:35:04.058750
Read BD ADDR (0x04|0x0009) ncmd 1
Status: Success (0x00)
Address: 00:11:22:33:44:55 (OUI Company)
Read this as: Frame #13, the host asked the controller for its Bluetooth
address. Frame #14, the controller replied with success and the address
00:11:22:33:44:55. The response arrived ~0.9ms later.
Typical MGMT flow showing relation to HCI:
@ MGMT Command: Set Powered (0x0005) plen 1 {0x0001} [hci0] 12:35:04.033564
Powered: Enabled (0x01)
< HCI Command: Reset (0x03|0x0003) plen 0 #7 [hci0] 12:35:04.033907
> HCI Event: Command Complete (0x0e) plen 4 #8 [hci0] 12:35:04.055753
Reset (0x03|0x0003) ncmd 2
Status: Success (0x00)
... (more HCI commands to configure the controller) ...
@ MGMT Event: Command Complete (0x0001) plen 7 {0x0001} [hci0] 12:35:04.114789
Set Powered (0x0005) plen 4
Status: Success (0x00)
Read this as: bluetoothd sent Set Powered via MGMT. The kernel
translated this into a sequence of HCI commands (Reset, then
configuration). After all HCI commands completed, the kernel sent the
MGMT Command Complete event back to bluetoothd.
Connection establishment flow:
> HCI Event: LE Meta Event (0x3e) plen 31 #487 [hci0] 12:36:18.974201
LE Enhanced Connection Complete (0x0a)
Status: Success (0x00)
Handle: 2048
Role: Peripheral (0x01)
Peer address: AA:BB:CC:DD:EE:FF (OUI Company)
@ MGMT Event: Device Connec.. (0x000b) plen 13 {0x0001} [hci0] 12:36:18.974319
= bluetoothd: src/adapter.c:connected_callback() hci0 devic.. 12:36:18.975307
< ACL: Handle 2048 [1.. flags 0x00 dlen 16 #493 [hci0] 12:36:18.977915
LE L2CAP: Connection Parameter Update Request (0x12) ident 1 len 8
< ACL: Handle 2048 [2/6] flags 0x00 dlen 7 #494 [hci0] 12:36:18.978488
ATT: Exchange MTU Request (0x02) len 2
Client RX MTU: 517
Read this as: The controller reported a new LE connection (HCI event).
The kernel forwarded this as a MGMT Device Connected event. bluetoothd
logged its connected_callback(). Then data exchange began β an L2CAP
parameter update and ATT MTU negotiation over the new ACL connection.
CONNECTION TRACKINGπ
HCI uses connection handles (16-bit integers) to identify individual connections. Understanding how handles map to devices is essential for reading traces.
Handle Typesπ
Different connection types use different handle ranges, but these ranges are controller-specific and not standardized. The connection type can be determined by looking at the event that created the handle:
Type |
Creation Event |
Description |
|---|---|---|
BR/EDR ACL |
Connection Complete |
Classic Bluetooth data connection |
LE ACL |
LE (Enhanced) Connection Complete |
Low Energy data connection |
CIS |
LE CIS Established |
Connected Isochronous Stream (LE Audio) |
BIS |
LE BIG Complete |
Broadcast Isochronous Stream (LE Audio) |
SCO/eSCO |
Synchronous Connection Complete |
Voice/audio synchronous connection (classic) |
A single device may have multiple handles simultaneously. For example,
an LE Audio device will have an LE ACL handle for control traffic and
one or more CIS handles for audio streams. The LE CIS Established
event includes the ACL connection handle that the CIS is associated
with.
Controller Buffer Trackingπ
Buffer tracking may show a indicator in square brackets:
< ACL: Handle 2048 [1/6] flags 0x00 dlen 16
The [1/6] means this is buffer slot 1 of 6 available controller
ACL buffers. This reflects the host-side HCI flow control: the host
tracks how many buffers the controller has available and shows the
current usage. When the controller sends Number of Completed Packets
events, buffers are freed and the count decreases.
HCI ERROR AND DISCONNECT REASON CODESπ
HCI status and disconnect reason codes use the same code space. These
appear in Status: and Reason: fields throughout the trace.
btmon decodes them automatically, but the hex values are useful for
searching and filtering.
Common Disconnect Reasonsπ
Code |
Name |
Diagnostic Meaning |
|---|---|---|
0x05 |
Authentication Failure |
Pairing or encryption setup failed. Key may be stale or devices have mismatched security databases. |
0x08 |
Connection Timeout |
The supervision timer expired. The remote device moved out of range or stopped responding. This is an RF link loss. |
0x13 |
Remote User Terminated Connection |
The remote device intentionally disconnected. This is the normal graceful disconnect. |
0x14 |
Remote Device Terminated due to Low Resources |
The remote device ran out of resources (memory, connection slots). |
0x15 |
Remote Device Terminated due to Power Off |
The remote device is powering down. |
0x16 |
Connection Terminated By Local Host |
The local BlueZ stack intentionally disconnected. Normal when bluetoothd initiates disconnect. |
0x1f |
Unspecified Error |
Generic error. Often indicates a firmware issue. |
0x22 |
LMP/LL Response Timeout |
Link layer procedure timed out. The remote device stopped responding to LL control PDUs. |
0x28 |
Instant Passed |
A timing-critical operation missed its deadline. Often seen with connection parameter updates. |
0x2f |
Insufficient Security |
The required security level (encryption, MITM protection) was not met. |
0x3b |
Unacceptable Connection Parameters |
The remote rejected a connection parameter update. |
0x3d |
Connection Terminated due to MIC Failure |
Encryption integrity check failed. Possible key mismatch or corruption. |
0x3e |
Connection Failed to be Established |
Connection attempt failed entirely (e.g., the remote device did not respond to connection requests). |
0x3f |
MAC Connection Failed |
MAC-level connection failure. |
0x44 |
Operation Cancelled by Host |
The host cancelled the operation before it completed. |
Full Error Code Tableπ
The complete set of HCI error codes (0x00-0x45) is defined in the
Bluetooth Core Specification, Volume 1, Part F. btmon decodes all
of them automatically in Status: and Reason: fields. The
source mapping is in monitor/packet.c (error2str_table).
ANALYZE MODEπ
The -a (--analyze) option reads a btsnoop file and produces a
statistical summary instead of the full decoded trace.
Usageπ
$ btmon -a hcidump.log
Output Contentsπ
Analyze mode reports, for each controller found in the trace:
Packet counts: Total HCI packets broken down by type (commands, events, ACL, SCO, ISO, vendor diagnostics, system notes, user logs, control messages).
Per-connection statistics: For each connection handle found:
Connection type (BR-ACL, LE-ACL, BR-SCO, BR-ESCO, LE-ISO)
Device address
TX and RX packet counts and completion counts
Latency statistics (min, max, median) in milliseconds
Packet size statistics (min, max, average) in octets
Throughput estimate in Kb/s
Per-channel statistics: For each L2CAP channel within a connection, the same packet/latency/size statistics.
Latency plots: If
gnuplotis installed, ASCII-art latency distribution plots are rendered in the terminal.
EXAMPLESπ
Capture the traces from hci0 to hcidump.log fileπ
$ btmon -i hci0 -w hcidump.log
Open the trace fileπ
$ btmon -r hcidump.log
Open the trace file with wall-clock timestampsπ
$ btmon -t -r hcidump.log
Open the trace file with full date and timeπ
$ btmon -T -r hcidump.log
AUTOMATED TRACE ANALYSISπ
This section provides guidance for analyzing btmon traces programmatically or with AI assistance.
Recommended Workflowπ
Get an overview: Start with
btmon -a <file>to see packet counts, connection handles, device addresses, and traffic volumes.Decode with timestamps: Use
btmon -t -r <file> > output.txtto produce a text file with wall-clock timestamps for analysis.Identify connections: Search for connection establishment events to build a handle-to-address mapping:
grep -n "Connection Complete\|Enhanced Connection Complete\|CIS Established" output.txt
Track disconnections: Search for disconnect events and their reasons:
grep -n "Disconnect Complete" output.txt
Then examine the lines following each match for the
Reason:field.Identify LE Audio: Search for ASCS and CIS activity:
grep -n "ASE Control Point\|CIG Parameters\|Create Connected Isochronous\|CIS Established\|Setup ISO Data Path" output.txt
Check for errors: Search for non-success status codes:
grep -n "Status:" output.txt | grep -v "Success"
Key Patterns for Connection Lifecycleπ
A complete connection lifecycle for an LE ACL connection follows this pattern in the trace:
LE Enhanced Connection Completeβ connection established, note the Handle and Peer addressLE Connection Update Completeβ connection parameters changed (may occur zero or more times)Encryption Changeβ link encrypted (may show encryption algorithm)ACL Data with ATT/SMP/L2CAP β service discovery and data exchange
Disconnect Completeβ connection ended, check Reason field
For LE Audio connections, additional steps appear between 3 and 5:
ATT operations on PACS/ASCS characteristics (codec negotiation)
LE Set CIG Parameterscommand and responseLE Create CIScommandLE CIS Establishedevent (note the CIS handle)LE Setup ISO Data PathcommandISO Data TX/RX (audio streaming)
Disconnect Completeon CIS handle (stream ended)LE Remove CIG(group removed)
Vendor-Specific Eventsπ
Vendor-specific HCI events (event code 0xFF) contain
controller-manufacturer diagnostic data. btmon decodes some vendor
events for known manufacturers (Intel, Broadcom, etc.) but many
sub-events show as Unknown with raw hex data. These are expected
and generally not actionable without vendor documentation.
Intel controllers emit extended telemetry events (subevent 0x8780)
that include connection quality metrics, error counters, and firmware
state. Partial decoding is available in monitor/intel.c.
RESOURCESπ
REPORTING BUGSπ
SEE ALSOπ
btsnoop(7)