btmon(1) Linux System Administration btmon(1) Name btmon - Bluetooth monitor 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 | Sent from host to | | | TX | 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 o New Index -- a controller was registered with the kernel o Open Index -- a controller was activated o Index Info -- controller vendor information o Close 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 | 0.881932 | | | start | | +----------+---------------------+-----------------+ |-t | Time of day | 12:35:01.843185 | | | (HH:MM:SS.usec) | | +----------+---------------------+-----------------+ |-T | Full date and time | 2026-01-13 | | | | 12:34:49.881926 | +----------+---------------------+-----------------+ Indented Detail Lines Lines indented below a frame header contain the decoded payload of that frame. The indentation level indicates the protocol layer: o First level (6 spaces): direct payload of the HCI/MGMT frame o Second level (8 spaces): decoded fields within the payload o 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: o Live capture (btmon monitor channel): Microsecond precision from the kernel. o 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: o A single frame may produce many output lines (header + decoded fields). o Frame numbers only apply to HCI traffic (< and >). MGMT (@) and system notes (=) do not have frame numbers. o 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. 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: o Packet counts: Total HCI packets broken down by type (commands, events, ACL, SCO, ISO, vendor diagnostics, system notes, user logs, control messages). o Per-connection statistics: For each connection handle found: o Connection type (BR-ACL, LE-ACL, BR-SCO, BR-ESCO, LE-ISO) o Device address o TX and RX packet counts and completion counts o Latency statistics (min, max, median) in milliseconds o Packet size statistics (min, max, average) in octets o Throughput estimate in Kb/s o Per-channel statistics: For each L2CAP channel within a connection, the same packet/latency/size statistics. o Latency plots: If gnuplot is installed, ASCII-art latency distribution plots are rendered in the terminal. PROTOCOL ERROR CODES btmon automatically decodes error codes from multiple protocol layers. This section provides a reference for interpreting errors seen across ATT, SMP, and L2CAP layers. ATT Error Codes ATT errors appear in Error Response (0x01) PDUs. Beyond the GATT discovery context (where Attribute Not Found is normal), these errors indicate real problems: +----------+---------------------+----------------------+ |Code | Error | Diagnostic Meaning | +----------+---------------------+----------------------+ |0x01 | Invalid Handle | Client used a handle | | | | that does not exist | +----------+---------------------+----------------------+ |0x02 | Read Not Permitted | Characteristic does | | | | not allow reads | +----------+---------------------+----------------------+ |0x03 | Write Not Permitted | Characteristic does | | | | not allow writes | +----------+---------------------+----------------------+ |0x05 | Authentication | Operation requires | | | Insufficient | an authenticated | | | | (MITM-protected) | | | | bond. Triggers SMP | | | | pairing if not yet | | | | bonded. | +----------+---------------------+----------------------+ |0x06 | Request Not | Server does not | | | Supported | support this ATT | | | | operation | +----------+---------------------+----------------------+ |0x07 | Invalid Offset | Read/write blob | | | | offset exceeds | | | | attribute length | +----------+---------------------+----------------------+ |0x08 | Authorization | Server requires | | | Insufficient | additional | | | | authorization | +----------+---------------------+----------------------+ |0x09 | Prepare Queue Full | Too many prepared | | | | writes queued | +----------+---------------------+----------------------+ |0x0a | Attribute Not Found | No attributes in | | | | requested range. | | | | Normal termination | | | | for GATT discovery | | | | procedures. | +----------+---------------------+----------------------+ |0x0b | Attribute Not Long | Attribute cannot be | | | | read with Read Blob | +----------+---------------------+----------------------+ |0x0c | Insufficient | Encryption key is | | | Encryption Key Size | too short | +----------+---------------------+----------------------+ |0x0d | Invalid Attribute | Write value length | | | Value Length | is incorrect for | | | | this attribute | +----------+---------------------+----------------------+ |0x0e | Unlikely Error | Generic unlikely | | | | error | +----------+---------------------+----------------------+ |0x0f | Insufficient | Link is not | | | Encryption | encrypted. Triggers | | | | encryption setup. | +----------+---------------------+----------------------+ |0x10 | Unsupported Group | Attribute type is | | | Type | not a valid grouping | | | | type | +----------+---------------------+----------------------+ |0x11 | Insufficient | Server out of | | | Resources | resources | +----------+---------------------+----------------------+ |0x12 | Value Not Allowed | Value is not within | | | | permitted range | +----------+---------------------+----------------------+ |0x80-0x9f | Application Error | Application-specific | | | | error; meaning | | | | depends on the | | | | profile/service. | | | | ASCS uses these for | | | | ASE-specific errors. | +----------+---------------------+----------------------+ |0xfc | Write Request | Write rejected | | | Rejected | (CSIP, ASCS) | +----------+---------------------+----------------------+ |0xfd | CCC Descriptor | CCC must be enabled | | | Improperly | before certain | | | Configured | operations | +----------+---------------------+----------------------+ |0xfe | Procedure Already | Another procedure is | | | in Progress | already running | +----------+---------------------+----------------------+ |0xff | Out of Range | Value is outside | | | | valid range | +----------+---------------------+----------------------+ L2CAP Connection Response Results L2CAP Connection Response and LE Connection Response include a result code: +-------+---------------------+---------------------+ |Code | Result | Diagnostic Meaning | +-------+---------------------+---------------------+ |0x0000 | Connection | Channel established | | | successful | normally | +-------+---------------------+---------------------+ |0x0001 | Connection pending | Connection in | | | | progress (BR/EDR | | | | only) | +-------+---------------------+---------------------+ |0x0002 | Connection refused | Remote does not | | | - PSM not supported | have a server for | | | | this protocol | +-------+---------------------+---------------------+ |0x0003 | Connection refused | Security | | | - security block | requirements not | | | | met | +-------+---------------------+---------------------+ |0x0004 | Connection refused | Remote ran out of | | | - no resources | channel resources | +-------+---------------------+---------------------+ |0x0005 | Connection refused | Source CID is | | | - invalid Source | invalid or already | | | CID | in use | +-------+---------------------+---------------------+ |0x0006 | Connection refused | CID collision | | | - Source CID | | | | already allocated | | +-------+---------------------+---------------------+ |0x0007 | Connection refused | LE credit-based: | | | - unacceptable | MTU, MPS, or | | | parameters | credits | | | | unacceptable | +-------+---------------------+---------------------+ |0x0008 | Connection refused | Parameter values | | | - invalid | are invalid | | | parameters | | +-------+---------------------+---------------------+ |0x0009 | Connection refused | Not authenticated | | | - insufficient | | | | authentication | | +-------+---------------------+---------------------+ |0x000a | Connection refused | Not authorized | | | - insufficient | | | | authorization | | +-------+---------------------+---------------------+ |0x000b | Connection refused | Encryption key too | | | - insufficient | short | | | encryption key size | | +-------+---------------------+---------------------+ |0x000c | Connection refused | Link not encrypted | | | - insufficient | | | | encryption | | +-------+---------------------+---------------------+ Automating Error Detection Find all ATT errors (excluding normal discovery termination): grep -n "Error Response" output.txt Then check whether each error is Attribute Not Found (0x0a) within a discovery sequence (normal) or a different error code (problem). Find all authentication/encryption related errors: grep -n "Authentication Insufficient\|Insufficient Encryption\|Insufficient Security\|security block" output.txt These indicate the link needs pairing or encryption. Check whether SMP pairing follows. Find all L2CAP channel rejections: grep -n "Connection refused" output.txt Cross-layer error correlation: Errors often cascade across layers. Common patterns: 1. ATT Insufficient Encryption (0x0f) -> triggers HCI LE Start Encryption -> Encryption Change success -> ATT operation retried 2. ATT Authentication Insufficient (0x05) -> triggers SMP Pairing Request -> pairing completes -> ATT operation retried 3. SMP Pairing Failed -> Disconnect Complete with reason Authentication Failure (0x05) 4. L2CAP Connection refused - security block -> triggers SMP pairing PROTOCOL FLOWS HCI INITIALIZATION SEQUENCE Every btsnoop trace that captures controller startup begins with a dense block of HCI commands and events. This is the kernel's Bluetooth subsystem initializing the controller through a multi-stage sequence defined in net/bluetooth/hci_sync.c. Understanding this sequence helps distinguish normal initialization traffic from application-level issues. Overview The kernel initializes a Bluetooth controller in four stages after opening the HCI device. Each stage sends a batch of HCI commands and waits for their completion before proceeding to the next. The full call chain is: hci_power_on_sync hci_dev_open_sync hci_dev_init_sync hci_dev_setup_sync (driver setup + quirks) hci_init_sync Stage 1: Reset + identity Stage 2: Capabilities + buffer sizes Stage 3: Event masks + policy Stage 4: Final configuration After all four stages complete, a post-init phase (hci_powered_update_sync) configures runtime parameters like SSP, advertising, and scan settings. For unconfigured devices (e.g. controllers that need firmware or a BD address programmed), only a minimal Stage 0 runs to identify the hardware. Stage 0: Reset and Basic Identity (Unconfigured Only) This stage runs only for unconfigured controllers that need setup before full initialization. Commands sent: +-----------------------------------+----------------------------+ |HCI Command | Purpose | +-----------------------------------+----------------------------+ |HCI_Reset | Reset the controller | | | (skipped if RESET_ON_CLOSE | | | quirk) | +-----------------------------------+----------------------------+ |HCI_Read_Local_Version_Information | Read hardware/firmware | | | version | +-----------------------------------+----------------------------+ |HCI_Read_BD_ADDR | Read the controller's | | | Bluetooth address | +-----------------------------------+----------------------------+ Stage 1: Reset and Read Local Features Resets the controller and reads core identity and capability information. Commands sent: +-----------------------------------+---------------------------+ |HCI Command | Purpose | +-----------------------------------+---------------------------+ |HCI_Reset | Reset the controller | +-----------------------------------+---------------------------+ |HCI_Read_Local_Supported_Features | Read LMP feature bitmask | | | (BR/EDR, LE, SSP, etc.) | +-----------------------------------+---------------------------+ |HCI_Read_Local_Version_Information | Read HCI version, LMP | | | version, manufacturer | +-----------------------------------+---------------------------+ |HCI_Read_BD_ADDR | Read the public Bluetooth | | | address | +-----------------------------------+---------------------------+ Stage 2: Read Capabilities and Setup Reads detailed capabilities, enables core features, and reads buffer sizes. This stage has three phases: common commands, BR/EDR-specific commands, and LE-specific commands. Common Commands +-----------------------------------------------+----------------------------+ |HCI Command | Purpose | +-----------------------------------------------+----------------------------+ |HCI_Read_Local_Supported_Commands | Read the supported command | | | bitmask (HCI 1.2+) | +-----------------------------------------------+----------------------------+ |HCI_Write_Simple_Pairing_Mode (enable) | Enable SSP if supported | | | and configured | +-----------------------------------------------+----------------------------+ |HCI_Write_Extended_Inquiry_Response (clear) | Clear EIR data when SSP is | | | disabled | +-----------------------------------------------+----------------------------+ |HCI_Write_Inquiry_Mode | Set inquiry mode (RSSI or | | | Extended, based on | | | features) | +-----------------------------------------------+----------------------------+ |HCI_Read_Inquiry_Response_Transmit_Power_Level | Read inquiry TX power if | | | supported | +-----------------------------------------------+----------------------------+ |HCI_Read_Local_Extended_Features (page 1) | Read extended feature page | | | 1 (SSP host, LE host, | | | etc.) | +-----------------------------------------------+----------------------------+ |HCI_Write_Authentication_Enable | Sync authentication state | | | with LINK_SECURITY flag | +-----------------------------------------------+----------------------------+ BR/EDR Commands (if BR/EDR capable) +------------------------------------------+----------------------------+ |HCI Command | Purpose | +------------------------------------------+----------------------------+ |HCI_Read_Buffer_Size | Read ACL/SCO buffer sizes | | | and count | +------------------------------------------+----------------------------+ |HCI_Read_Class_of_Device | Read current device class | +------------------------------------------+----------------------------+ |HCI_Read_Local_Name | Read the stored local name | +------------------------------------------+----------------------------+ |HCI_Read_Voice_Setting | Read SCO voice setting (if | | | supported) | +------------------------------------------+----------------------------+ |HCI_Read_Number_of_Supported_IAC | Read number of supported | | | inquiry access codes | +------------------------------------------+----------------------------+ |HCI_Read_Current_IAC_LAP | Read current IAC LAP | | | values | +------------------------------------------+----------------------------+ |HCI_Set_Event_Filter (clear all) | Clear any stored event | | | filters | +------------------------------------------+----------------------------+ |HCI_Write_Connection_Accept_Timeout | Set connection accept | | | timeout (~20 seconds) | +------------------------------------------+----------------------------+ |HCI_Write_Synchronous_Flow_Control_Enable | Enable SCO flow control if | | | supported | +------------------------------------------+----------------------------+ LE Commands (if LE capable) +-------------------------------------+----------------------------+ |HCI Command | Purpose | +-------------------------------------+----------------------------+ |LE_Read_Local_Supported_Features | Read LE feature bitmask | +-------------------------------------+----------------------------+ |LE_Read_All_Local_Supported_Features | Read extended LE features | | | (if supported) | +-------------------------------------+----------------------------+ |LE_Read_Buffer_Size [v2] or [v1] | Read LE ACL (and ISO) | | | buffer sizes; v2 used when | | | ISO capable | +-------------------------------------+----------------------------+ |LE_Read_Supported_States | Read the LE state | | | combination table | +-------------------------------------+----------------------------+ Stage 3: Event Masks, Link Policy, and Features Configures which events the controller should report, sets link policy, and reads extended feature pages. This is the longest stage. Event Masks and Link Policy +------------------------------------------+---------------------------+ |HCI Command | Purpose | +------------------------------------------+---------------------------+ |HCI_Set_Event_Mask | Configure the main event | | | mask based on controller | | | capabilities | +------------------------------------------+---------------------------+ |HCI_Read_Stored_Link_Key | Read all stored link keys | +------------------------------------------+---------------------------+ |HCI_Write_Default_Link_Policy_Settings | Enable role switch, hold, | | | sniff, park based on LMP | | | features | +------------------------------------------+---------------------------+ |HCI_Read_Page_Scan_Activity | Read page scan interval | | | and window | +------------------------------------------+---------------------------+ |HCI_Read_Default_Erroneous_Data_Reporting | Read error data reporting | | | state (for wideband | | | speech) | +------------------------------------------+---------------------------+ |HCI_Read_Page_Scan_Type | Read page scan type | | | (standard or interlaced) | +------------------------------------------+---------------------------+ |HCI_Read_Local_Extended_Features (pages | Read all remaining | |2..N) | extended feature pages | +------------------------------------------+---------------------------+ Event mask details: For dual-mode controllers the kernel enables events for inquiry results (RSSI and extended), SSP (IO capability, user confirmation, passkey), synchronous connections, sniff subrating, encryption refresh, link supervision, and LE meta-events. For LE-only controllers a minimal mask covers only command completion, hardware errors, disconnection, and encryption changes. LE Event Mask and Capabilities +---------------------------------------------+---------------------------+ |HCI Command | Purpose | +---------------------------------------------+---------------------------+ |LE_Set_Event_Mask | Configure which LE | | | sub-events are reported | +---------------------------------------------+---------------------------+ |LE_Read_Advertising_Channel_Tx_Power | Read advertising TX power | | | (legacy advertising only) | +---------------------------------------------+---------------------------+ |LE_Read_Transmit_Power | Read min/max transmit | | | power range | +---------------------------------------------+---------------------------+ |LE_Read_Accept_List_Size | Read filter accept list | | | capacity | +---------------------------------------------+---------------------------+ |LE_Clear_Accept_List | Clear the filter accept | | | list | +---------------------------------------------+---------------------------+ |LE_Read_Resolving_List_Size | Read resolving list | | | capacity (LL Privacy) | +---------------------------------------------+---------------------------+ |LE_Clear_Resolving_List | Clear the resolving list | +---------------------------------------------+---------------------------+ |LE_Set_Resolvable_Private_Address_Timeout | Set RPA rotation timeout | +---------------------------------------------+---------------------------+ |LE_Read_Maximum_Data_Length | Read max TX/RX octets and | | | time (Data Length | | | Extension) | +---------------------------------------------+---------------------------+ |LE_Read_Suggested_Default_Data_Length | Read current default data | | | length | +---------------------------------------------+---------------------------+ |LE_Read_Number_of_Supported_Advertising_Sets | Read extended advertising | | | set capacity | +---------------------------------------------+---------------------------+ |HCI_Write_LE_Host_Supported | Notify controller of host | | | LE support (dual-mode | | | only) | +---------------------------------------------+---------------------------+ |LE_Set_Host_Feature | Enable CIS Central (bit | | | 32) and/or Channel | | | Sounding (bit 47) | +---------------------------------------------+---------------------------+ LE event mask details: The kernel enables LE sub-events based on features: connection complete (enhanced if available), advertising reports (extended if available), long term key request, connection parameter request, data length change, PHY update, channel selection algorithm, periodic advertising events, CIS established/request (if CIS capable), BIG create/sync/info (if BIS capable), and channel sounding events (if CS capable). Stage 4: Final Configuration Performs final setup: deletes stale keys, sets event mask page 2, reads codec information, enables Secure Connections, and configures LE data length and PHY defaults. Keys, Codecs, and Secure Connections +-------------------------------------------+----------------------------+ |HCI Command | Purpose | +-------------------------------------------+----------------------------+ |HCI_Delete_Stored_Link_Key (all) | Delete all stored link | | | keys from controller | +-------------------------------------------+----------------------------+ |HCI_Set_Event_Mask_Page_2 | Enable page 2 events | | | (authenticated payload | | | timeout, etc.) | +-------------------------------------------+----------------------------+ |HCI_Read_Local_Supported_Codecs [v2] or | Read supported codec IDs; | |[v1] | v2 includes transport type | | | info | +-------------------------------------------+----------------------------+ |HCI_Read_Local_Pairing_Options | Read default pairing | | | options (max encryption | | | key size) | +-------------------------------------------+----------------------------+ |HCI_Get_MWS_Transport_Layer_Configuration | Read MWS coexistence | | | config if supported | +-------------------------------------------+----------------------------+ |HCI_Read_Synchronization_Train_Parameters | Read sync train params | | | (Connectionless Peripheral | | | Broadcast) | +-------------------------------------------+----------------------------+ |HCI_Write_Secure_Connections_Support | Enable Secure Connections | |(enable) | if SSP active | +-------------------------------------------+----------------------------+ |HCI_Write_Default_Erroneous_Data_Reporting | Enable/disable based on | | | wideband speech setting | +-------------------------------------------+----------------------------+ LE Data Length and PHY Defaults +---------------------------------------+----------------------------+ |HCI Command | Purpose | +---------------------------------------+----------------------------+ |LE_Write_Suggested_Default_Data_Length | Set default TX octets/time | | | for new connections | +---------------------------------------+----------------------------+ |LE_Set_Default_PHY | Set preferred PHY (1M | | | always; 2M and Coded if | | | supported) | +---------------------------------------+----------------------------+ Post-Initialization After the four stages complete, hci_powered_update_sync runs to apply runtime configuration: +--------------------------------+----------------------------+ |Action | Purpose | +--------------------------------+----------------------------+ |HCI_Write_Simple_Pairing_Mode | Re-enable SSP + Secure | | | Connections if configured | +--------------------------------+----------------------------+ |HCI_Write_LE_Host_Supported | Sync LE host support state | +--------------------------------+----------------------------+ |LE advertising setup | Configure advertising | | | parameters and data | +--------------------------------+----------------------------+ |HCI_Write_Authentication_Enable | Sync authentication enable | | | state | +--------------------------------+----------------------------+ |Scan/class/name/EIR updates | Configure page scan, | | | device class, local name, | | | EIR data | +--------------------------------+----------------------------+ |LE_Set_Random_Address | Set static random address | | | if no public address | +--------------------------------+----------------------------+ Reading the Init Sequence in a Trace When examining a btsnoop trace, the initialization block is the first thing after the controller is opened. A typical dual-mode controller trace starts with: < HCI Command: Reset > HCI Event: Command Complete (Reset) < HCI Command: Read Local Supported Features > HCI Event: Command Complete (Read Local Supported Features) < HCI Command: Read Local Version Information > HCI Event: Command Complete (Read Local Version Information) < HCI Command: Read BD ADDR > HCI Event: Command Complete (Read BD ADDR) ... [Stage 2-4 commands follow] Key things to look for: o Missing commands: If expected commands are absent, the controller may not support the corresponding feature. For example, no LE_Read_Buffer_Size means the controller is BR/EDR only. o Command failures: A Status other than 0x00 in a Command Complete event during init usually indicates a broken controller or unsupported feature. The kernel handles most gracefully, but persistent errors may prevent the adapter from functioning. o Buffer sizes: The values returned by Read_Buffer_Size and LE_Read_Buffer_Size determine how many in-flight packets the controller can hold. Small buffer counts can cause throughput issues. o Feature bits: The Read_Local_Supported_Features response reveals what the controller supports (LE, SSP, eSCO, etc.). Cross reference with the commands that follow -- the kernel only sends commands for features the controller reports supporting. o Event mask: The Set_Event_Mask command shows exactly which events the host wants to receive. If an expected event never appears in the trace, check whether it was enabled in the mask. o LE-only controllers: These skip all BR/EDR commands (Read_Buffer_Size, Read_Local_Name, link policy, etc.) and use a minimal event mask. The trace will be noticeably shorter. o Vendor commands: Some controllers (Intel, Broadcom, Qualcomm, Realtek, MediaTek) insert vendor-specific HCI commands between stages for firmware download, configuration, or patch application. These appear as opcode groups 0x3F (vendor) and are driver-specific. 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) | Low Energy data | | | Connection Complete | connection | +-----------+---------------------+--------------------+ |CIS | LE CIS Established | Connected | | | | Isochronous Stream | | | | (LE Audio) | +-----------+---------------------+--------------------+ |BIS | LE BIG Complete | Broadcast | | | | Isochronous Stream | | | | (LE Audio) | +-----------+---------------------+--------------------+ |SCO/eSCO | Synchronous | Voice/audio | | | Connection Complete | 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 | Pairing or | | | Failure | 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 | The remote device | | | Terminated | intentionally | | | Connection | disconnected. This | | | | is the normal | | | | graceful | | | | disconnect. | +-----+---------------------+---------------------+ |0x14 | Remote Device | The remote device | | | Terminated due to | ran out of | | | Low Resources | resources (memory, | | | | connection slots). | +-----+---------------------+---------------------+ |0x15 | Remote Device | The remote device | | | Terminated due to | is powering down. | | | Power Off | | +-----+---------------------+---------------------+ |0x16 | Connection | The local BlueZ | | | Terminated By Local | stack intentionally | | | Host | disconnected. | | | | Normal when | | | | bluetoothd | | | | initiates | | | | disconnect. | +-----+---------------------+---------------------+ |0x1f | Unspecified Error | Generic error. | | | | Often indicates a | | | | firmware issue. | +-----+---------------------+---------------------+ |0x22 | LMP/LL Response | Link layer | | | Timeout | 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 | The required | | | Security | security level | | | | (encryption, MITM | | | | protection) was not | | | | met. | +-----+---------------------+---------------------+ |0x3b | Unacceptable | The remote rejected | | | Connection | a connection | | | Parameters | parameter update. | +-----+---------------------+---------------------+ |0x3d | Connection | Encryption | | | Terminated due to | integrity check | | | MIC Failure | failed. Possible | | | | key mismatch or | | | | corruption. | +-----+---------------------+---------------------+ |0x3e | Connection Failed | Connection attempt | | | to be Established | failed entirely | | | | (e.g., the remote | | | | device did not | | | | respond to | | | | connection | | | | requests). | +-----+---------------------+---------------------+ |0x3f | MAC Connection | MAC-level | | | Failed | connection failure. | +-----+---------------------+---------------------+ |0x44 | Operation Cancelled | The host cancelled | | | by Host | 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). RECONSTRUCTING A GATT DATABASE FROM SNOOP TRACES A btsnoop trace contains the complete ATT protocol exchange used by GATT clients and servers to discover each other's services. By reading the discovery requests and responses, it is possible to reconstruct the full GATT database of a remote device -- even without access to the device itself. This section explains the GATT discovery procedure and how each ATT operation appears in btmon output. Overview of GATT Discovery GATT discovery is a multi-phase process where a client queries the server's attribute database using ATT protocol operations. The phases are: 1. Primary Service Discovery -- Find all primary services and their handle ranges. 2. Secondary Service Discovery -- Find any secondary (included-only) services. 3. Included Service Discovery -- Find which services include other services. 4. Characteristic Discovery -- Find all characteristics within each service. 5. Descriptor Discovery -- Find all descriptors for each characteristic. 6. Characteristic Value Reading -- Read the values of readable characteristics. Each phase uses a specific ATT operation and produces a request/response pattern in the trace. The client repeats each request with advancing handle ranges until the server responds with Attribute Not Found, indicating the end of that phase. Phase 1: Primary Service Discovery (Read By Group Type) The client discovers primary services using Read By Group Type Request with the Primary Service UUID (0x2800) as the group type. Request: < ACL Data TX: Handle 2048 flags 0x00 dlen 11 #516 [hci0] 0.124726 ATT: Read By Group Type Request (0x10) len 6 Handle range: 0x0001-0xffff Attribute group type: Primary Service (0x2800) The first request always starts at handle 0x0001 and searches through 0xffff (the entire handle space). Response: > ACL Data RX: Handle 2048 flags 0x02 dlen 42 #523 [hci0] 0.240151 ATT: Read By Group Type Response (0x11) len 37 Attribute data length: 6 Attribute group list: 6 entries Handle range: 0x0001-0x0009 UUID: Generic Access Profile (0x1800) Handle range: 0x000a-0x0011 UUID: Generic Attribute Profile (0x1801) Handle range: 0x0012-0x0014 UUID: Device Information (0x180a) Handle range: 0x0015-0x0039 UUID: Generic Telephony Bearer (0x184c) Handle range: 0x003a-0x0059 UUID: Generic Media Control (0x1849) Handle range: 0x005a-0x005c UUID: Telephony and Media Audio (0x1855) Each entry provides: o Handle range -- The start and end handle of the service. All attributes belonging to this service (characteristics, descriptors) have handles within this range. o UUID -- The service UUID. Standard 16-bit UUIDs are shown with their name (e.g., Generic Access Profile). 128-bit vendor-specific UUIDs appear as full UUID strings. The client continues by sending another request starting after the last handle in the response: < ACL Data TX: Handle 2048 flags 0x00 dlen 11 #525 [hci0] 0.240641 ATT: Read By Group Type Request (0x10) len 6 Handle range: 0x005d-0xffff Attribute group type: Primary Service (0x2800) This continues until the server responds with Attribute Not Found: > ACL Data RX: Handle 2048 flags 0x02 dlen 9 #532 [hci0] 0.360069 ATT: Error Response (0x01) len 4 Read By Group Type Request (0x10) Handle: 0x005d Error: Attribute Not Found (0x0a) This error indicates that no more primary services exist beyond handle 0x005d. The client now has the complete list of primary services. Note: The Attribute data length field indicates the size of each entry in the response. A value of 6 means 16-bit UUIDs (2 bytes start handle + 2 bytes end handle + 2 bytes UUID). A value of 20 means 128-bit UUIDs (2 + 2 + 16). If the server has both 16-bit and 128-bit service UUIDs, they are returned in separate responses because all entries in a single response must have the same length. Phase 2: Secondary Service Discovery After primary services, the client may discover secondary services using the same Read By Group Type Request but with the Secondary Service UUID (0x2801): < ACL Data TX: Handle 2048 flags 0x00 dlen 11 #534 [hci0] 0.360752 ATT: Read By Group Type Request (0x10) len 6 Handle range: 0x0001-0xffff Attribute group type: Secondary Service (0x2801) If no secondary services exist, the server responds with Attribute Not Found. Secondary services are not directly accessible to clients -- they are only reachable via include references from primary services. Phase 3: Included Service Discovery (Read By Type) To discover which services include other services, the client uses Read By Type Request with the Include UUID (0x2802): < ACL Data TX: Handle 2048 flags 0x00 dlen 11 #540 [hci0] 0.480731 ATT: Read By Type Request (0x08) len 6 Handle range: 0x0001-0x005c Attribute type: Include (0x2802) The handle range typically spans the entire discovered database. Each include declaration in the response identifies a service that is included by the service containing that handle. Phase 4: Characteristic Discovery (Read By Type) For each service, the client discovers its characteristics using Read By Type Request with the Characteristic UUID (0x2803). The handle range is limited to the service's handle range. Request: > ACL Data RX: Handle 2048 flags 0x02 dlen 11 #531 [hci0] 0.360063 ATT: Read By Type Request (0x08) len 6 Handle range: 0x0008-0x0011 Attribute type: Characteristic (0x2803) Response: < ACL Data TX: Handle 2048 flags 0x00 dlen 27 #533 [hci0] 0.360714 ATT: Read By Type Response (0x09) len 22 Attribute data length: 7 Attribute data list: 3 entries Handle: 0x0009 Value[5]: 200a00052a Properties: 0x20 Indicate (0x20) Value Handle: 0x000a Value UUID: Service Changed (0x2a05) Handle: 0x000c Value[5]: 0a0d00292b Properties: 0x0a Read (0x02) Write (0x08) Value Handle: 0x000d Value UUID: Client Supported Features (0x2b29) Handle: 0x000e Value[5]: 020f002a2b Properties: 0x02 Read (0x02) Value Handle: 0x000f Value UUID: Database Hash (0x2b2a) Each characteristic entry provides: o Handle -- The handle of the characteristic declaration attribute. o Properties -- A bitmask indicating supported operations: +-----+---------------------+---------------------+ |Bit | Property | Description | +-----+---------------------+---------------------+ |0x01 | Broadcast | Can be broadcast in | | | | advertising data | +-----+---------------------+---------------------+ |0x02 | Read | Can be read | +-----+---------------------+---------------------+ |0x04 | Write Without | Can be written | | | Response | without | | | | acknowledgment | +-----+---------------------+---------------------+ |0x08 | Write | Can be written with | | | | acknowledgment | +-----+---------------------+---------------------+ |0x10 | Notify | Server can send | | | | notifications | +-----+---------------------+---------------------+ |0x20 | Indicate | Server can send | | | | indications | +-----+---------------------+---------------------+ |0x40 | Authenticated | Supports signed | | | Signed Writes | write commands | +-----+---------------------+---------------------+ |0x80 | Extended Properties | Has extended | | | | properties | | | | descriptor | +-----+---------------------+---------------------+ o Value Handle -- The handle where the characteristic's value is stored (always declaration handle + 1). o Value UUID -- The UUID identifying the characteristic type. The client continues with advancing handle ranges until it receives Attribute Not Found: > ACL Data RX: Handle 2048 flags 0x02 dlen 9 #572 [hci0] 1.200228 ATT: Error Response (0x01) len 4 Read By Type Request (0x08) Handle: 0x005c Error: Attribute Not Found (0x0a) Phase 5: Descriptor Discovery (Find Information) Descriptors occupy the handles between a characteristic's value handle and the next characteristic declaration (or end of service). The client discovers them using Find Information Request. Request: > ACL Data RX: Handle 2048 flags 0x02 dlen 9 #556 [hci0] 0.959965 ATT: Find Information Request (0x04) len 4 Handle range: 0x000b-0x000b The handle range covers the gap between the characteristic value handle and the next characteristic declaration handle. Response: < ACL Data TX: Handle 2048 flags 0x00 dlen 10 #561 [hci0] 0.961049 ATT: Find Information Response (0x05) len 5 Format: UUID-16 (0x01) Handle: 0x000b UUID: Client Characteristic Configuration (0x2902) Common descriptor UUIDs: +-------+---------------------+---------------------+ |UUID | Name | Purpose | +-------+---------------------+---------------------+ |0x2900 | Characteristic | Additional property | | | Extended Properties | bits | +-------+---------------------+---------------------+ |0x2901 | Characteristic User | Human-readable | | | Description | description string | +-------+---------------------+---------------------+ |0x2902 | Client | Enable/disable | | | Characteristic | notifications or | | | Configuration (CCC) | indications | +-------+---------------------+---------------------+ |0x2903 | Server | Server-side | | | Characteristic | broadcast | | | Configuration | configuration | +-------+---------------------+---------------------+ |0x2904 | Characteristic | Data format, | | | Presentation Format | exponent, unit | +-------+---------------------+---------------------+ Phase 6: Reading Characteristic Values After discovery, the client may read characteristic values using Read Request: > ACL Data RX: Handle 2048 flags 0x02 dlen 7 #577 [hci0] 1.380203 ATT: Read Request (0x0a) len 2 Handle: 0x000f < ACL Data TX: Handle 2048 flags 0x00 dlen 21 #579 [hci0] 1.380774 ATT: Read Response (0x0b) len 16 Value[16]: a470d508da8751a2a50b79da0250bfda The Handle in the request corresponds to a characteristic value handle from the discovery phase. btmon shows the raw value bytes; the interpretation depends on the characteristic UUID. Find By Type Value (Targeted Service Search) In addition to discovering all services, a client can search for a specific service UUID using Find By Type Value Request: > ACL Data RX: Handle 2048 flags 0x02 dlen 13 #513 [hci0] 0.124195 ATT: Find By Type Value Request (0x06) len 8 Handle range: 0x0001-0xffff Attribute type: Primary Service (0x2800) UUID: Generic Attribute Profile (0x1801) < ACL Data TX: Handle 2048 flags 0x00 dlen 9 #515 [hci0] 0.124684 ATT: Find By Type Value Response (0x07) len 4 Handle range: 0x0008-0x0011 This returns only the handle range for the matching service, without iterating through all services. If the service is not found: < ACL Data TX: Handle 2048 flags 0x00 dlen 9 #524 [hci0] 0.240607 ATT: Error Response (0x01) len 4 Find By Type Value Request (0x06) Handle: 0x0012 Error: Attribute Not Found (0x0a) Bidirectional Discovery Both devices in a connection can act as GATT client and server simultaneously. In a btsnoop trace, you may see interleaved discovery in both directions: o TX (``<``) requests + RX (``>``) responses -- The local device (whose trace this is) is acting as a GATT client, discovering the remote device's services. o RX (``>``) requests + TX (``<``) responses -- The remote device is acting as a GATT client, discovering the local device's services. For example, the local server responding to the remote's discovery: > ACL Data RX: Handle 2048 flags 0x02 dlen 11 #584 [hci0] 1.512006 ATT: Read By Group Type Request (0x10) len 6 Handle range: 0x0001-0xffff Attribute group type: Primary Service (0x2800) < ACL Data TX: Handle 2048 flags 0x00 dlen 66 #586 [hci0] 1.518778 ATT: Read By Group Type Response (0x11) len 61 Attribute data length: 6 Attribute group list: 10 entries Handle range: 0x0001-0x0007 UUID: Generic Access Profile (0x1800) Handle range: 0x0008-0x0011 UUID: Generic Attribute Profile (0x1801) Handle range: 0x0012-0x0014 UUID: Device Information (0x180a) Handle range: 0x0015-0x001e UUID: Coordinated Set Identification (0x1846) Handle range: 0x001f-0x0020 UUID: Common Audio (0x1853) Handle range: 0x0021-0x0024 UUID: Microphone Control (0x184d) Handle range: 0x0041-0x004b UUID: Volume Control (0x1844) Handle range: 0x006b-0x0073 UUID: Broadcast Audio Scan (0x184f) Handle range: 0x0074-0x0086 UUID: Published Audio Capabilities (0x1850) Handle range: 0x0087-0x0096 UUID: Audio Stream Control (0x184e) This shows the local device's own GATT database as seen by the remote. To reconstruct the remote device's database, focus on the TX requests and RX responses (the local device acting as client). Building the Attribute Table To reconstruct the GATT database, extract the discovery responses and organize them into a table. Using the trace above as an example, the remote device at address 00:11:22:33:44:55 has: Services (from Read By Group Type Response): Handle Range UUID Service Name 0x0001-0x0009 0x1800 Generic Access Profile 0x000a-0x0011 0x1801 Generic Attribute Profile 0x0012-0x0014 0x180a Device Information 0x0015-0x0039 0x184c Generic Telephony Bearer 0x003a-0x0059 0x1849 Generic Media Control 0x005a-0x005c 0x1855 Telephony and Media Audio Characteristics (from Read By Type Response, within GAP 0x0001-0x0009): Handle Value Handle Properties UUID Name 0x0002 0x0003 Read 0x2a00 Device Name 0x0004 0x0005 Read 0x2a01 Appearance 0x0006 0x0007 Read 0x2a04 Peripheral Preferred Conn Params 0x0008 0x0009 Read 0x2aa6 Central Address Resolution Characteristics (within GATT 0x000a-0x0011): Handle Value Handle Properties UUID Name 0x000b 0x000c Indicate 0x2a05 Service Changed 0x000e 0x000f Read, Write 0x2b29 Client Supported Features 0x0010 0x0011 Read 0x2b2a Database Hash Descriptors (from Find Information Response): Handle UUID Name 0x000d 0x2902 Client Characteristic Configuration The CCC descriptor at handle 0x000d belongs to the Service Changed characteristic (0x000c), because it falls between that value handle and the next characteristic declaration at 0x000e. SMP PAIRING FLOW The Security Manager Protocol (SMP) handles pairing, key generation, and key distribution between Bluetooth devices. SMP traffic appears inside L2CAP on fixed CID 0x0006 (LE) or CID 0x0007 (BR/EDR). btmon decodes all SMP operations automatically. Pairing Phases SMP pairing proceeds in three phases. Each phase produces a distinct pattern in the btmon output. Phase 1: Feature Exchange Pairing begins when one device sends a Security Request (peripheral) or the host initiates pairing directly. The initiator sends a Pairing Request and the responder replies with a Pairing Response: > ACL Data RX: Handle 2048 flags 0x02 dlen 11 #497 [hci0] 0.026107 SMP: Pairing Request (0x01) len 6 IO capability: NoInputNoOutput (0x03) OOB data: Authentication data not present (0x00) Authentication requirement: Bonding, MITM, SC, CT2 (0x2d) Max encryption key size: 16 Initiator key distribution: IdKey Sign (0x06) Responder key distribution: IdKey Sign (0x06) < ACL Data TX: Handle 2048 flags 0x00 dlen 11 #499 [hci0] 0.026894 SMP: Pairing Response (0x02) len 6 IO capability: KeyboardDisplay (0x04) OOB data: Authentication data not present (0x00) Authentication requirement: Bonding, SC, CT2 (0x29) Max encryption key size: 16 Initiator key distribution: IdKey (0x02) Responder key distribution: IdKey (0x02) Key fields to check: o Authentication requirement -- The SC flag indicates Secure Connections. Its absence means Legacy Pairing. o IO capability -- Determines the association model (Just Works, Passkey Entry, Numeric Comparison, OOB). o Key distribution -- Which keys each side will send after encryption is established. IdKey = Identity Resolving Key (IRK), EncKey = Long Term Key (legacy only), Sign = CSRK. Phase 2: Authentication (Secure Connections) For Secure Connections pairing (SC flag set), both devices exchange public keys, then perform confirm/random value exchange: > ACL Data RX: Handle 2048 flags 0x02 dlen 69 #501 [hci0] 0.098224 SMP: Pairing Public Key (0x0c) len 64 X: 1a2b3c4d... Y: 5e6f7a8b... < ACL Data TX: Handle 2048 flags 0x00 dlen 69 #503 [hci0] 0.148556 SMP: Pairing Public Key (0x0c) len 64 X: 9c8d7e6f... Y: 0a1b2c3d... < ACL Data TX: Handle 2048 flags 0x00 dlen 21 #505 [hci0] 0.149003 SMP: Pairing Confirm (0x03) len 16 Confirm value: a1b2c3d4e5f6... > ACL Data RX: Handle 2048 flags 0x02 dlen 21 #507 [hci0] 0.212884 SMP: Pairing Random (0x04) len 16 Random value: 1122334455... < ACL Data TX: Handle 2048 flags 0x00 dlen 21 #509 [hci0] 0.213100 SMP: Pairing Random (0x04) len 16 Random value: 6677889900... > ACL Data RX: Handle 2048 flags 0x02 dlen 21 #511 [hci0] 0.278003 SMP: Pairing DHKey Check (0x0d) len 16 E: aabbccddee... < ACL Data TX: Handle 2048 flags 0x00 dlen 21 #513 [hci0] 0.278450 SMP: Pairing DHKey Check (0x0d) len 16 E: ffeeddccbb... After DHKey Check, the initiator starts encryption at the HCI level: < HCI Command: LE Start Encryption (0x08|0x0019) plen 28 #515 [hci0] 0.279002 > HCI Event: Encryption Change (0x08) plen 4 #517 [hci0] 0.342556 Status: Success (0x00) Handle: 2048 Encryption: Enabled with AES-CCM (0x01) Phase 2: Authentication (Legacy Pairing) Legacy pairing (no SC flag) skips the Public Key and DHKey Check exchanges. Only Confirm and Random values are exchanged: < ACL Data TX: Handle 2048 flags 0x00 dlen 21 #501 [hci0] 0.098224 SMP: Pairing Confirm (0x03) len 16 Confirm value: ... > ACL Data RX: Handle 2048 flags 0x02 dlen 21 #503 [hci0] 0.162556 SMP: Pairing Confirm (0x03) len 16 Confirm value: ... < ACL Data TX: Handle 2048 flags 0x00 dlen 21 #505 [hci0] 0.163003 SMP: Pairing Random (0x04) len 16 Random value: ... > ACL Data RX: Handle 2048 flags 0x02 dlen 21 #507 [hci0] 0.228884 SMP: Pairing Random (0x04) len 16 Random value: ... Phase 3: Key Distribution After encryption is established, each device distributes keys as negotiated in Phase 1: > ACL Data RX: Handle 2048 flags 0x02 dlen 21 #519 [hci0] 0.343002 SMP: Identity Information (0x08) len 16 Identity resolving key: 00112233445566778899aabbccddeeff > ACL Data RX: Handle 2048 flags 0x02 dlen 12 #521 [hci0] 0.343556 SMP: Identity Address Information (0x09) len 7 Address type: Public (0x00) Address: 00:11:22:33:44:55 The Identity Address Information reveals the device's true public or static random address (as opposed to a Resolvable Private Address used during connection). For Legacy Pairing, LTK distribution also appears: > ACL Data RX: Handle 2048 flags 0x02 dlen 21 #519 [hci0] 0.343002 SMP: Encryption Information (0x06) len 16 Long term key: 00112233... > ACL Data RX: Handle 2048 flags 0x02 dlen 15 #521 [hci0] 0.343556 SMP: Central Identification (0x07) len 10 EDIV: 0x1234 Rand: 0x0123456789abcdef Pairing Failure When pairing fails, one device sends a Pairing Failed PDU: > ACL Data RX: Handle 2048 flags 0x02 dlen 6 #505 [hci0] 0.213002 SMP: Pairing Failed (0x05) len 1 Reason: Authentication requirements (0x03) SMP failure reasons: +-----+---------------------+---------------------+ |Code | Reason | Diagnostic Meaning | +-----+---------------------+---------------------+ |0x01 | Passkey Entry | User cancelled or | | | Failed | entered wrong | | | | passkey | +-----+---------------------+---------------------+ |0x02 | OOB Not Available | OOB data expected | | | | but not provided | +-----+---------------------+---------------------+ |0x03 | Authentication | Devices cannot | | | Requirements | agree on security | | | | level (e.g., one | | | | requires MITM but | | | | IO caps only allow | | | | Just Works) | +-----+---------------------+---------------------+ |0x04 | Confirm Value | Cryptographic check | | | Failed | failed; possible | | | | MITM attack | +-----+---------------------+---------------------+ |0x05 | Pairing Not | Remote does not | | | Supported | support pairing | +-----+---------------------+---------------------+ |0x06 | Encryption Key Size | Cannot agree on key | | | | size | +-----+---------------------+---------------------+ |0x07 | Command Not | Received | | | Supported | unrecognized SMP | | | | command | +-----+---------------------+---------------------+ |0x08 | Unspecified Reason | Generic failure | +-----+---------------------+---------------------+ |0x09 | Repeated Attempts | Pairing | | | | rate-limited; wait | | | | before retry | +-----+---------------------+---------------------+ |0x0a | Invalid Parameters | Invalid fields in | | | | SMP command | +-----+---------------------+---------------------+ |0x0b | DHKey Check Failed | ECDH key agreement | | | | failed (SC only) | +-----+---------------------+---------------------+ |0x0c | Numeric Comparison | User rejected | | | Failed | numeric comparison | +-----+---------------------+---------------------+ |0x0d | BR/EDR Pairing In | Classic pairing | | | Progress | already active | +-----+---------------------+---------------------+ |0x0e | Cross-Transport Key | CTKD rejected by | | | Derivation Not | policy | | | Allowed | | +-----+---------------------+---------------------+ Automating Pairing Analysis Identify all pairing attempts: grep -n "Pairing Request\|Pairing Response\|Pairing Failed\|Pairing Public Key\|DHKey Check" output.txt Check pairing method (Secure Connections vs Legacy): o If Pairing Public Key appears between Request/Response and Confirm: Secure Connections. o If only Confirm/Random follow Request/Response: Legacy Pairing. o Check the Authentication requirement line for the SC flag. Detect pairing failures: grep -n "Pairing Failed" output.txt Correlate pairing with encryption: After successful pairing, expect Encryption Change with Status: Success. Search for: grep -n "Encryption Change\|Encryption:" output.txt Identify re-pairing on reconnect: Reconnections to a bonded device should show Encryption Change without SMP traffic (using stored keys). If SMP Pairing Request appears on reconnection, the bond was lost on one side. Full pairing diagnosis pattern: 1. Find Pairing Request -- note the handle, IO capabilities, auth requirements 2. Find Pairing Response -- compare IO capabilities to determine association model 3. Check for Pairing Failed -- if present, the reason code identifies the failure 4. Check for Encryption Change with Status: Success -- confirms pairing completed 5. Check for Identity Address Information -- reveals the device's true address L2CAP CHANNEL TRACKING L2CAP (Logical Link Control and Adaptation Protocol) multiplexes multiple logical channels over a single ACL connection. btmon decodes L2CAP signaling automatically and routes data to higher-layer protocol decoders based on the channel. Fixed Channels Fixed channels have pre-assigned Channel Identifiers (CIDs) and do not require signaling to establish: +-------+-----------------+--------------------+ |CID | Protocol | Description | +-------+-----------------+--------------------+ |0x0001 | L2CAP Signaling | Channel management | | | (BR/EDR) | for classic | | | | connections | +-------+-----------------+--------------------+ |0x0002 | Connectionless | Connectionless | | | Reception | L2CAP data | +-------+-----------------+--------------------+ |0x0003 | AMP Manager | AMP (Alternate | | | | MAC/PHY) control | +-------+-----------------+--------------------+ |0x0004 | ATT | Attribute Protocol | | | | (GATT operations) | +-------+-----------------+--------------------+ |0x0005 | L2CAP Signaling | Channel management | | | (LE) | for LE connections | +-------+-----------------+--------------------+ |0x0006 | SMP (LE) | Security Manager | | | | Protocol | +-------+-----------------+--------------------+ |0x0007 | SMP (BR/EDR) | Security Manager | | | | over classic | | | | transport | +-------+-----------------+--------------------+ In btmon output, fixed channel traffic is decoded directly without any L2CAP signaling preamble. For example, ATT on CID 0x0004 appears as: < ACL Data TX: Handle 2048 flags 0x00 dlen 7 #494 [hci0] 0.004488 ATT: Exchange MTU Request (0x02) len 2 Client RX MTU: 517 Dynamic Channels (BR/EDR) Classic Bluetooth uses L2CAP signaling on CID 0x0001 to establish dynamic channels. Each channel is identified by a PSM (Protocol/Service Multiplexer) that determines which protocol runs on it. Channel establishment: > ACL Data RX: Handle 256 flags 0x02 dlen 16 #142 [hci0] 2.034556 L2CAP: Connection Request (0x02) ident 3 len 4 PSM: 25 (0x0019) Source CID: 0x0040 < ACL Data TX: Handle 256 flags 0x00 dlen 20 #144 [hci0] 2.035002 L2CAP: Connection Response (0x03) ident 3 len 8 Destination CID: 0x0041 Source CID: 0x0040 Result: Connection successful (0x0000) Status: No further information available (0x0000) After connection, configuration is exchanged: > ACL Data RX: Handle 256 flags 0x02 dlen 20 #146 [hci0] 2.035556 L2CAP: Configure Request (0x04) ident 4 len 8 Destination CID: 0x0041 Flags: 0x0000 Option: MTU (0x01) [2] MTU: 1024 < ACL Data TX: Handle 256 flags 0x00 dlen 18 #148 [hci0] 2.036003 L2CAP: Configure Response (0x05) ident 4 len 6 Source CID: 0x0040 Flags: 0x0000 Result: Success (0x0000) Common PSM-to-protocol mappings: +-------+----------------+---------------------+ |PSM | Protocol | Description | +-------+----------------+---------------------+ |0x0001 | SDP | Service Discovery | | | | Protocol | +-------+----------------+---------------------+ |0x0003 | RFCOMM | Serial port | | | | emulation (SPP, | | | | HFP, etc.) | +-------+----------------+---------------------+ |0x000f | BNEP | Bluetooth Network | | | | Encapsulation | | | | Protocol | +-------+----------------+---------------------+ |0x0017 | AVCTP | Audio/Video Control | | | | Transport (AVRCP) | +-------+----------------+---------------------+ |0x0019 | AVDTP | Audio/Video | | | | Distribution | | | | Transport (A2DP) | +-------+----------------+---------------------+ |0x001b | AVCTP Browsing | AVRCP browsing | | | | channel | +-------+----------------+---------------------+ |0x001f | ATT (BR/EDR) | Attribute Protocol | | | | over classic | | | | transport | +-------+----------------+---------------------+ |0x0027 | EATT | Enhanced Attribute | | | | Protocol | +-------+----------------+---------------------+ LE Credit-Based Channels LE connections use L2CAP signaling on CID 0x0005 for dynamic channels. The LE Credit Based Connection mechanism provides flow control: < ACL Data TX: Handle 2048 flags 0x00 dlen 18 #600 [hci0] 1.824003 LE L2CAP: LE Connection Request (0x14) ident 1 len 10 PSM: 39 (0x0027) Source CID: 0x0040 MTU: 517 MPS: 251 Credits: 10 > ACL Data RX: Handle 2048 flags 0x02 dlen 18 #602 [hci0] 1.886556 LE L2CAP: LE Connection Response (0x15) ident 1 len 10 Destination CID: 0x0041 MTU: 517 MPS: 251 Credits: 10 Result: Connection successful (0x0000) EATT (Enhanced ATT) uses PSM 0x0027 over LE Credit-Based channels to provide multiple parallel ATT bearers. Connection Parameter Updates LE peripherals frequently request connection parameter changes via L2CAP signaling: < ACL Data TX: Handle 2048 flags 0x00 dlen 16 #493 [hci0] 0.003915 LE L2CAP: Connection Parameter Update Request (0x12) ident 1 len 8 Min interval: 24 Max interval: 40 Peripheral latency: 0 Timeout multiplier: 256 > ACL Data RX: Handle 2048 flags 0x02 dlen 10 #495 [hci0] 0.066003 LE L2CAP: Connection Parameter Update Response (0x13) ident 1 len 2 Result: Connection Parameters accepted (0x0000) A result of Connection Parameters rejected (0x0001) means the central denied the request. Automating L2CAP Analysis Find all L2CAP channel establishments: grep -n "Connection Request\|Connection Response\|LE Connection Request\|LE Connection Response" output.txt Track PSM usage (identifies which protocols are active): grep -n "PSM:" output.txt Find connection parameter update issues: grep -n "Parameter Update Request\|Parameter Update Response\|Parameters rejected" output.txt Find EATT channel setup: grep -n "PSM: 39\|Enhanced Credit" output.txt Trace a specific L2CAP channel: To follow traffic on a dynamic channel, note the Source CID and Destination CID from the Connection Request/Response pair. Then search for those CIDs in subsequent data frames. Throughput Estimation btmon's --analyze (-a) mode computes per-channel statistics including throughput. For each L2CAP channel it reports: o Speed: Computed as bytes * 8 / latency_sum_ms where latency_sum_ms is the sum of inter-packet deltas (not wall-clock duration). This means idle gaps are excluded, so the figure represents the active sending rate rather than application-level throughput. o Min/Avg/Max latency: Per-packet inter-arrival time range. Example output: Found TX L2CAP channel with CID 64 PSM 128 (0x0080) Mode: LE Credit MTU: 672 MPS: 490 TX packets: 29120/29114 TX Latency: 1-79 msec (~29 msec) TX size: 494-494 octets (~494 octets) TX speed: ~571 Kb/s Channel details shown in analyze mode: o Fixed channels (CID <= 7) display their protocol name (e.g., ATT, L2CAP Signaling (LE)). o PSM is shown in both decimal and hexadecimal. o Mode is decoded from Configure Request options (BR/EDR) or LE signaling (Basic, ERTM, LE Credit, Enhanced Credit, etc.). o MTU and MPS are extracted from signaling exchanges. Throughput caveats: 1. The speed value uses inter-packet latency sums as the denominator, not wall-clock elapsed time. If the sender pauses (e.g., waiting for credits), the idle period is not counted, which inflates the reported speed relative to overall throughput. 2. TX latency is measured from command submission to completion event. RX latency is the inter-arrival time between consecutive packets. These measure different things, so TX and RX speeds for the same channel are not directly comparable. 3. For windowed throughput (min/avg/max), btsnoop-analyzer uses 1-second sampling windows over wall-clock time, which provides a more realistic view of application-level bandwidth variation. Automated throughput extraction from btmon analyze output: btmon -a trace.btsnoop 2>/dev/null | grep -E "speed:|Mode:|MTU:|MPS:|PSM" LE AUDIO PROTOCOL FLOW LE Audio uses a multi-layer protocol stack visible in btmon traces. The setup sequence involves ATT operations on specific GATT characteristics (PACS, ASCS) followed by HCI-level CIS/BIG management. btmon fully decodes all layers. PACS: Published Audio Capabilities Before audio streaming begins, devices exchange codec capabilities via the Published Audio Capabilities Service (PACS). The client reads PACS characteristics to learn what the remote device supports. Sink PAC read (remote device's receive capabilities): < ACL Data TX: Handle 2048 flags 0x00 dlen 7 #550 [hci0] 0.824003 ATT: Read Request (0x0a) len 2 Handle: 0x0075 > ACL Data RX: Handle 2048 flags 0x02 dlen 30 #552 [hci0] 0.886556 ATT: Read Response (0x0b) len 25 Handle: 0x0075 Number of PAC(s): 1 Codec: LC3 (0x06) Codec Specific Capabilities: #0 Sampling Frequency: 8000 Hz 16000 Hz 24000 Hz 32000 Hz 48000 Hz Frame Duration: 7.5 ms 10 ms Audio Channel Counts: 1 Frame Length: 26 - 240 The PAC record shows codec capabilities using LTV (Length-Type-Value) encoding. Key fields: o Codec -- LC3 (0x06) is the mandatory LE Audio codec o Sampling Frequency -- Supported sample rates (bitmask) o Frame Duration -- Supported frame durations (7.5 ms and/or 10 ms) o Audio Channel Counts -- Supported channel counts o Frame Length -- Min and max octets per codec frame Audio Locations (channel assignment): > ACL Data RX: Handle 2048 flags 0x02 dlen 9 #554 [hci0] 0.948003 ATT: Read Response (0x0b) len 4 Handle: 0x0077 Location: Front Left Available Audio Contexts (current use cases): > ACL Data RX: Handle 2048 flags 0x02 dlen 9 #558 [hci0] 1.012556 ATT: Read Response (0x0b) len 4 Handle: 0x007b Sink Context: Media Conversational Source Context: Unspecified ASCS: Audio Stream Control The Audio Stream Control Service (ASCS) manages the ASE (Audio Stream Endpoint) state machine. Each ASE transitions through a defined set of states as streaming is set up and torn down. ASE State Machine: Idle Codec Configured QoS Configured Enabling Streaming | Idle Releasing Disabling ASE Status notification (state change): > ACL Data RX: Handle 2048 flags 0x02 dlen 20 #580 [hci0] 1.456003 ATT: Handle Value Notification (0x1b) len 15 Handle: 0x0088 ASE ID: 0x01 State: Codec Configured (0x01) Framing: Unframed PDUs supported (0x00) PHY: 0x02 LE 2M PHY (0x02) RTN: 2 Max Transport Latency: 10 Presentation Delay Min: 20000 us Presentation Delay Max: 40000 us Preferred Presentation Delay Min: 20000 us Preferred Presentation Delay Max: 40000 us Codec: LC3 (0x06) Sampling Frequency: 48000 Hz Frame Duration: 10 ms Audio Channel Allocation: Front Left Frame Length: 120 ASE Control Point operations drive state transitions. The client writes to the ASE Control Point characteristic to issue commands: < ACL Data TX: Handle 2048 flags 0x00 dlen 25 #582 [hci0] 1.518003 ATT: Write Request (0x12) len 20 Handle: 0x008b ASE Control Point: Config Codec (0x01) ASE ID: 0x01 Target Latency: Low Latency (0x01) PHY: LE 2M PHY Codec: LC3 (0x06) Sampling Frequency: 48000 Hz Frame Duration: 10 ms Audio Channel Allocation: Front Left Frame Length: 120 ASE Control Point commands: +-------+---------------------+---------------------+ |Opcode | Command | Purpose | +-------+---------------------+---------------------+ |0x01 | Config Codec | Select codec and | | | | parameters (Idle -> | | | | Codec Configured) | +-------+---------------------+---------------------+ |0x02 | Config QoS | Set CIG/CIS IDs and | | | | QoS params (Codec | | | | Configured -> QoS | | | | Configured) | +-------+---------------------+---------------------+ |0x03 | Enable | Start ASE with | | | | metadata (QoS | | | | Configured -> | | | | Enabling) | +-------+---------------------+---------------------+ |0x04 | Receiver Start | Signal receiver | | | Ready | readiness (Enabling | | | | -> Streaming, | | | | server-side) | +-------+---------------------+---------------------+ |0x05 | Disable | Stop streaming | | | | (Streaming -> | | | | Disabling) | +-------+---------------------+---------------------+ |0x06 | Receiver Stop Ready | Signal receiver | | | | stopped | +-------+---------------------+---------------------+ |0x07 | Update Metadata | Change metadata | | | | during streaming | +-------+---------------------+---------------------+ |0x08 | Release | Tear down ASE (any | | | | -> Releasing -> | | | | Idle) | +-------+---------------------+---------------------+ Bidirectional Streams (Source + Sink) A device may expose multiple ASEs with different directions. In the conversational (telephony) use case, the remote device typically has at least one Sink ASE (receives audio, e.g., speaker) and one Source ASE (sends audio, e.g., microphone). Both ASEs share the same CIG and often the same CIS, using the bidirectional capability of Connected Isochronous Streams. Direction indicators in btmon traces: o The Receiver Start Ready command is only sent for Source ASEs (ASEs that send audio toward the local device). The server issues this command to indicate it is ready to transmit. o The Receiver Stop Ready command likewise applies to Source ASEs. o Sink ASEs transition directly from Enabling to Streaming without Receiver Start Ready. Typical bidirectional setup sequence (two ASEs on one CIS): Config Codec ASE ID=1 (Sink) -> Codec Configured Config Codec ASE ID=3 (Source) -> Codec Configured Config QoS ASE ID=1 -> QoS Configured (CIG=X, CIS=Y) Config QoS ASE ID=3 -> QoS Configured (CIG=X, CIS=Y) Enable ASE ID=1 -> Enabling -> Streaming (immediate) Enable ASE ID=3 -> Enabling CIS Established (Success) Setup ISO Data Path Input (Host->Controller, for Sink) Setup ISO Data Path Output (Controller->Host, for Source) Receiver Start Ready ASE ID=3 -> Streaming Both ASEs may reach Streaming at different times. The Sink ASE can start receiving audio as soon as CIS is established, while the Source ASE waits for the Receiver Start Ready handshake. Note: This is normal behavior. Seeing one Source ASE and one Sink ASE on the same connection is the standard bidirectional (conversational) configuration. It is not an error or misconfiguration. Both directions sharing a single CIS is efficient and expected. Multiple ASEs per direction are also valid. For example, a stereo headset may expose two Sink ASEs (left and right channels) and one Source ASE (mono microphone), each with its own GATT handle for ASE state notifications. CIS Setup and Teardown After ASE QoS Configuration, the host creates Connected Isochronous Streams (CIS) at the HCI level. CIG Parameters (configure the CIS group): < HCI Command: LE Set CIG Parameters (0x08|0x0062) plen 26 #590 [hci0] 1.624003 CIG ID: 0x00 Central to Peripheral SDU Interval: 10000 us Peripheral to Central SDU Interval: 10000 us SCA: 0x00 Packing: Sequential (0x00) Framing: Unframed (0x00) Central to Peripheral Max Latency: 10 ms Peripheral to Central Max Latency: 10 ms Number of CIS: 1 CIS ID: 0x00 Central to Peripheral Max SDU: 120 Peripheral to Central Max SDU: 0 Central to Peripheral PHY: LE 2M PHY Peripheral to Central PHY: LE 2M PHY Central to Peripheral RTN: 2 Peripheral to Central RTN: 2 > HCI Event: Command Complete (0x0e) plen 8 #592 [hci0] 1.624556 LE Set CIG Parameters (0x08|0x0062) ncmd 1 Status: Success (0x00) CIG ID: 0x00 Number of Handles: 1 Connection Handle: 2064 CIS Creation: < HCI Command: LE Create CIS (0x08|0x0064) plen 9 #594 [hci0] 1.688003 Number of CIS: 1 CIS Handle: 2064 ACL Handle: 2048 > HCI Event: LE Meta Event (0x3e) plen 29 #596 [hci0] 1.756556 LE CIS Established (0x19) Status: Success (0x00) Connection Handle: 2064 CIG Sync Delay: 5000 us CIS Sync Delay: 5000 us Central to Peripheral Latency: 10000 us Peripheral to Central Latency: 10000 us Central to Peripheral PHY: LE 2M PHY Peripheral to Central PHY: LE 2M PHY NSE: 3 Central to Peripheral BN: 1 Peripheral to Central BN: 0 Central to Peripheral FT: 2 Peripheral to Central FT: 2 Max PDU C to P: 120 Max PDU P to C: 0 ISO Interval: 10.00 msec (0x0008) Note that the CIS Handle (2064) is different from the ACL Handle (2048). CIS data packets use the CIS handle. ISO Data Path Setup: < HCI Command: LE Setup ISO Data Path (0x08|0x006e) plen 13 #598 [hci0] 1.820003 Handle: 2064 Data Path Direction: Input (Host to Controller) (0x00) Data Path ID: HCI (0x00) Coding Format: LC3 (0x06) Company ID: 0x0000 Vendor Codec ID: 0x0000 Controller Delay: 0 us After this, ISO data packets flow on the CIS handle: < ISO Data TS: Handle 2064 flags 0x02 dlen 124 #600 [hci0] 1.884003 Broadcast Audio (BIG) Broadcast Isochronous Streams use BIG (Broadcast Isochronous Group) instead of CIS. The setup involves periodic advertising with BASE (Broadcast Audio Source Endpoint) announcements. BASE announcement (in periodic advertising data): > HCI Event: LE Meta Event (0x3e) plen 80 #200 [hci0] 0.500003 LE Periodic Advertising Report (0x0f) ... Service Data: Basic Audio Announcement (0x1851) Presentation Delay: 40000 us Number of Subgroups: 1 Number of BIS: 2 Codec: LC3 (0x06) Sampling Frequency: 48000 Hz Frame Duration: 10 ms Frame Length: 120 BIS #1 Audio Channel Allocation: Front Left BIS #2 Audio Channel Allocation: Front Right BIG creation (source side): < HCI Command: LE Create BIG (0x08|0x0068) plen 31 #210 [hci0] 0.600003 BIG Handle: 0x00 Advertising Handle: 0x01 Number of BIS: 2 SDU Interval: 10000 us Max SDU: 120 Max Latency: 10 ms RTN: 2 PHY: LE 2M PHY Packing: Sequential (0x00) Framing: Unframed (0x00) Encryption: Unencrypted (0x00) BIG sync (receiver side): < HCI Command: LE BIG Create Sync (0x08|0x006b) plen 15 #220 [hci0] 0.700003 BIG Handle: 0x00 Sync Handle: 0x0001 Encryption: Unencrypted (0x00) Number of BIS: 2 BIS: 0x01 BIS: 0x02 BIG Sync Receiver Flow A receiver must complete a specific sequence of steps before it can receive broadcast audio. The critical prerequisite chain is: 1. Synchronize to periodic advertising -- the receiver must first discover and sync to the broadcaster's periodic advertising train. 2. Receive PA Reports with BASE -- the periodic advertising data contains the BASE (Broadcast Audio Source Endpoint) structure describing the broadcast's codec configuration. 3. Receive BIG Info Advertising Report -- this event tells the receiver that a BIG exists on the periodic advertising train and provides its parameters (number of BIS, encryption, SDU interval, etc.). This is the critical gate: without receiving BIG Info, the receiver cannot issue LE BIG Create Sync. 4. Issue LE BIG Create Sync -- using the sync handle from step 1 and parameters from step 3. 5. Receive BIG Sync Established -- the controller confirms sync with BIS connection handles. 6. Setup ISO Data Path -- configure the data path for each BIS. 7. ISO Data flows -- broadcast audio packets arrive. If any step fails or is missing, the subsequent steps cannot proceed. The most common failure pattern is that BIG Info is never received (e.g., the periodic advertising data does not contain a BIG, or PA sync was lost before BIG Info arrived), which means LE BIG Create Sync is never sent. Without PAST (Direct PA Sync) When the receiver scans for and syncs to periodic advertising directly (without assistance from a Broadcast Assistant): Step 1 -- Create PA sync: < HCI Command: LE Periodic Advertising Create Sync (0x08|0x0044) plen 14 #100 [hci0] 0.100003 Options: 0x0000 SID: 0x01 Adv Address Type: Public (0x00) Adv Address: XX:XX:XX:XX:XX:XX Skip: 0x0000 Sync Timeout: 2000 msec (0x00c8) Sync CTE Type: 0x0000 Step 2 -- PA Sync Established (sync handle assigned): > HCI Event: LE Meta Event (0x3e) plen 16 #105 [hci0] 0.150003 LE Periodic Advertising Sync Established (0x0e) Status: Success (0x00) Sync Handle: 0x0001 Advertising SID: 0x01 Advertiser Address Type: Public (0x00) Advertiser Address: XX:XX:XX:XX:XX:XX Advertiser PHY: LE 2M PHY (0x02) Periodic Advertising Interval: 10.000 msec (0x0008) Advertiser Clock Accuracy: 0x05 Step 3 -- PA Reports (contain BASE data): > HCI Event: LE Meta Event (0x3e) plen 80 #110 [hci0] 0.200003 LE Periodic Advertising Report (0x0f) Sync Handle: 0x0001 ... Service Data: Basic Audio Announcement (0x1851) Step 4 -- BIG Info Advertising Report (critical gate): > HCI Event: LE Meta Event (0x3e) plen 24 #120 [hci0] 0.300003 LE BIG Info Advertising Report (0x22) Sync Handle: 0x0001 Number BIS: 2 NSE: 4 ISO Interval: 10.000 msec (0x0008) BN: 2 PTO: 1 IRC: 2 Maximum PDU: 120 SDU Interval: 10000 us Maximum SDU: 120 PHY: LE 2M PHY (0x02) Framing: Unframed (0x00) Encryption: 0x00 This event is generated by the controller each time it receives a periodic advertising packet that contains BIG Info. It provides all parameters the receiver needs to decide whether to sync to the BIG. Key fields: o Number BIS -- how many BIS streams are available. o SDU Interval and Maximum SDU -- audio frame timing and size. o Encryption -- whether a Broadcast Code is required (0x01) or not (0x00). If encrypted, the receiver must supply the correct Broadcast Code in LE BIG Create Sync. o Sync Handle -- must match a currently active PA sync. Step 5 -- BIG Create Sync (using sync handle + BIG Info): < HCI Command: LE BIG Create Sync (0x08|0x006b) plen 15 #130 [hci0] 0.400003 BIG Handle: 0x00 BIG Sync Handle: 0x0001 Encryption: Unencrypted (0x00) Broadcast Code: 00000000000000000000000000000000 Maximum Number Subevents: 0x00 Timeout: 2000 ms (0x00c8) Number of BIS: 2 BIS: 0x01 BIS: 0x02 Step 6 -- BIG Sync Established: > HCI Event: LE Meta Event (0x3e) plen 20 #135 [hci0] 0.450003 LE BIG Sync Established (0x1d) Status: Success (0x00) BIG Handle: 0x00 Transport Latency: 10000 us NSE: 4 BN: 2 PTO: 1 IRC: 2 Maximum PDU: 120 ISO Interval: 10.000 msec (0x0008) Connection Handle: 0x0010 Connection Handle: 0x0011 On success, the controller assigns BIS connection handles (0x0010, 0x0011 above). A non-zero Status indicates failure -- common errors: o 0x3e (Connection Failed to be Established) -- BIG parameters do not match or the BIG is no longer present. o 0x3f (Limit Reached) -- controller resources exhausted. Step 7 -- Setup ISO Data Path (for each BIS): < HCI Command: LE Setup ISO Data Path (0x08|0x006e) plen 13 #140 [hci0] 0.500003 Connection Handle: 0x0010 Data Path Direction: Output (Controller to Host) (0x01) Data Path ID: HCI (0x00) < HCI Command: LE Setup ISO Data Path (0x08|0x006e) plen 13 #145 [hci0] 0.550003 Connection Handle: 0x0011 Data Path Direction: Output (Controller to Host) (0x01) Data Path ID: HCI (0x00) Step 8 -- ISO Data flows on BIS handles: > ISO Data: Handle 0x0010 flags 0x02 dlen 124 #150 [hci0] 0.600003 > ISO Data: Handle 0x0011 flags 0x02 dlen 124 #151 [hci0] 0.600003 With PAST (Periodic Advertising Sync Transfer) When a Broadcast Assistant (e.g., a phone) helps a Scan Delegator (e.g., a hearing aid) sync to a broadcast, it can transfer the PA sync via PAST over an existing ACL connection. This avoids the delegator having to scan for and sync to the PA train itself. The BASS (Broadcast Audio Scan Service) protocol coordinates this: 1. The assistant writes an Add Source operation to the delegator's BASS control point with PA Sync set to 0x01 (Synchronize via PAST). 2. The delegator prepares to receive the transfer by setting PAST parameters. 3. The assistant transfers its PA sync to the delegator. 4. The delegator receives the PAST event with a sync handle. 5. From here, the flow continues as in the non-PAST case (PA Reports -> BIG Info -> BIG Create Sync -> etc.). BASS Add Source (assistant writes to delegator, seen in ATT): < ACL Data TX: Handle 64 flags 0x00 dlen 27 #300 [hci0] 1.000003 ATT: Write Command (0x52) len 22 Handle: 0x0025 Data: 04... Opcode: Add Source (0x04) Advertiser Address Type: Public (0x00) Advertiser Address: XX:XX:XX:XX:XX:XX Advertising SID: 0x01 PA Sync: Synchronize to PA - PAST (0x01) PA Interval: 0x0008 Number of Subgroups: 1 BIS Sync: 0x00000003 Metadata Length: 0 PA Sync values in the Add Source operation: o 0x00 -- Do not synchronize to PA o 0x01 -- Synchronize to PA, PAST available o 0x02 -- Synchronize to PA, PAST not available (delegator must scan and sync directly) PAST Parameters (delegator prepares to receive transfer): < HCI Command: LE Periodic Advertising Sync Transfer Parameters (0x08|0x005c) plen 8 #310 [hci0] 1.100003 Connection handle: 64 Mode: Enabled with report events enabled (0x02) Skip: 0x00 Sync timeout: 2000 msec (0x00c8) Sync CTE Type: 0x0000 PAST Transfer (assistant sends its PA sync): < HCI Command: LE Periodic Advertising Sync Transfer (0x08|0x005a) plen 6 #320 [hci0] 1.200003 Connection handle: 64 Service data: 0x0001 Sync handle: 1 PAST Received (delegator gets the sync handle): > HCI Event: LE Meta Event (0x3e) plen 19 #325 [hci0] 1.250003 LE Periodic Advertising Sync Transfer Received (0x18) Status: Success (0x00) Handle: 64 Connection handle: 64 Service data: 0x0001 Sync handle: 1 SID: 0x01 Address type: Public (0x00) Address: XX:XX:XX:XX:XX:XX PHY: LE 2M PHY (0x02) Periodic advertising Interval: 10.000 Clock Accuracy: 0x05 On success, the delegator now has a PA sync (Sync handle: 1) and will begin receiving PA Reports and BIG Info events, continuing from step 3 of the non-PAST flow above. Note: Race condition: The PAST Parameters command must be sent before the assistant sends the PAST Transfer. In BlueZ, the PA sync state in BASS is set after probing completes to avoid the remote sending PAST before the kernel has enabled PAST Parameters on the HCI level. BIG Sync Teardown Receiver-initiated teardown -- the receiver terminates its BIG sync: < HCI Command: LE BIG Terminate Sync (0x08|0x006c) plen 1 #500 [hci0] 5.000003 BIG Handle: 0x00 > HCI Event: Command Complete (0x0e) plen 5 #501 [hci0] 5.001003 LE BIG Terminate Sync (0x08|0x006c) ncmd 1 Status: Success (0x00) BIG Handle: 0x00 Broadcaster-initiated teardown -- the broadcaster terminates its BIG, and the receiver gets a BIG Sync Lost event: > HCI Event: LE Meta Event (0x3e) plen 2 #510 [hci0] 6.000003 LE BIG Sync Lost (0x1e) BIG Handle: 0x00 Reason: Connection Terminated By Local Host (0x16) The Reason field indicates why sync was lost: o 0x08 (Connection Timeout) -- BIG packets not received within the sync timeout. o 0x13 (Remote User Terminated Connection) -- broadcaster stopped the BIG intentionally. o 0x16 (Connection Terminated By Local Host) -- local controller terminated. o 0x3e (Connection Failed to be Established) -- could not establish sync initially. Source-side BIG termination (broadcaster tears down): < HCI Command: LE Terminate BIG (0x08|0x006a) plen 2 #520 [hci0] 7.000003 BIG Handle: 0x00 Reason: Connection Terminated By Local Host (0x16) > HCI Event: LE Meta Event (0x3e) plen 2 #521 [hci0] 7.001003 LE BIG Terminate (0x1c) BIG Handle: 0x00 Reason: Connection Terminated By Local Host (0x16) BIG Sync Failure Diagnosis When analyzing a trace where BIG sync fails, check the following in order: 1. Is PA sync established? -- Look for LE Periodic Advertising Sync Established with Status: Success. If missing, the receiver never synced to the PA train. 2. Are PA Reports arriving? -- Look for LE Periodic Advertising Report events. If absent after PA sync, the PA train may have been lost. 3. Is BIG Info received? -- Look for LE BIG Info Advertising Report. If this event never appears, the BIG does not exist on this PA train, or the broadcaster has not yet started it. Without BIG Info, LE BIG Create Sync cannot be sent. 4. Is BIG Create Sync sent? -- If BIG Info was received but LE BIG Create Sync was never sent, the host-side logic failed to act on the BIG Info (e.g., mismatched codec, encryption mismatch, application-level issue). 5. Does BIG Sync Established succeed? -- Check the Status field. A non-zero status means the controller could not sync to the BIG. 6. Is ISO Data Path set up? -- Look for LE Setup ISO Data Path for each BIS handle from BIG Sync Established. 7. Is ISO Data flowing? -- Look for ISO Data packets on the BIS handles. Automating LE Audio Analysis Identify LE Audio activity: grep -n "ASE Control Point\|ASE ID\|State:.*Codec Configured\|State:.*QoS Configured\|State:.*Enabling\|State:.*Streaming\|State:.*Releasing" output.txt Track ASE state transitions for a specific ASE: grep -n "ASE ID:" output.txt Then examine the State: line following each ASE ID match. Check codec configuration: grep -n "Codec: LC3\|Sampling Frequency:\|Frame Duration:\|Frame Length:\|Audio Channel" output.txt Verify CIS establishment: grep -n "Set CIG Parameters\|Create CIS\|CIS Established\|Setup ISO Data Path" output.txt Detect CIS failures -- check the Status field after CIS Established: grep -n "CIS Established" output.txt Then examine the following line for Status:. Detect broadcast audio: grep -n "Basic Audio Announcement\|Create BIG\|BIG Complete\|BIG Create Sync\|BIG Sync\|BIG Info\|BIG Terminate\|BIG Sync Lost" output.txt Trace BIG Sync receiver flow -- verify each prerequisite step: grep -n "Periodic Advertising Create Sync\|Periodic Advertising Sync Established\|BIG Info Advertising Report\|BIG Create Sync\|BIG Sync Established\|BIG Sync Lost\|BIG Terminate" output.txt Detect PAST-based sync -- check for Periodic Advertising Sync Transfer: grep -n "Sync Transfer Parameters\|Sync Transfer (0x08\|PAST Received\|PA Sync:.*PAST\|Add Source" output.txt Check BIG Info arrival -- the critical gate for BIG sync. If this is absent, the receiver has no BIG to sync to: grep -n "BIG Info Advertising Report" output.txt Full LE Audio diagnosis pattern: Unicast (CIS) flow: 1. Find PACS reads -- verify codec compatibility between devices 2. Find ASE Control Point writes -- trace the Config Codec -> Config QoS -> Enable sequence 3. Find ASE state notifications -- verify each transition succeeds 4. Find CIG Parameters and CIS creation -- verify HCI-level setup 5. Find CIS Established -- check Status for success 6. Find Setup ISO Data Path -- verify data path configuration 7. Find ISO Data packets -- confirm audio is flowing 8. On failure, check ASE Control Point notification responses for error codes (Response Code and Response Reason fields) Broadcast (BIG) receiver flow: 1. Find Periodic Advertising Create Sync or PAST Received -- how did PA sync start? 2. Find Periodic Advertising Sync Established or PAST Received with Status: Success -- is PA synced? 3. Find Periodic Advertising Report with Basic Audio Announcement -- is BASE data arriving? 4. Find BIG Info Advertising Report -- critical: does the BIG exist? If missing, the BIG cannot be synced. 5. Find BIG Create Sync -- did the host request BIG sync? 6. Find BIG Sync Established -- check Status for success. 7. Find Setup ISO Data Path for each BIS handle. 8. Find ISO Data on BIS handles -- confirm audio is flowing. 9. On failure, check for BIG Sync Lost and examine Reason. CHANNEL SOUNDING PROTOCOL FLOW Channel Sounding (CS) enables precise distance measurement between two Bluetooth LE devices. It uses dedicated HCI commands and events to configure and execute measurement procedures that exchange tones and timing packets on multiple channels. btmon fully decodes all CS operations including step-level result data. CS uses two roles: the Initiator sends CS packets first in each step, and the Reflector responds. Both devices must support CS (feature bits 46--48 in the LE feature set). Capability Exchange Before any CS activity, both devices must learn each other's CS capabilities. The local controller's capabilities are read once, and the remote device's capabilities are fetched over the air. Read local CS capabilities: < HCI Command: LE CS Read Local Supported Capabilities (0x08|0x0089) plen 0 #100 [hci0] > HCI Event: Command Complete (0x0e) plen 42 #101 [hci0] LE CS Read Local Supported Capabilities (0x08|0x0089) ncmd 1 Status: Success (0x00) Num Config Supported: 4 Max Consecutive Procedures Supported: 255 Num Antennas Supported: 2 Max Antenna Paths Supported: 4 Roles Supported: 0x03 Initiator Reflector Modes Supported: 0x03 RTT Capability: 0x03 RTT AA Only N: 10 RTT Sounding N: 10 RTT Random Payload N: 10 CS Sync PHYs Supported: 0x02 LE 2M T_IP1 Times Supported: 0x0005 10 us 30 us T_IP2 Times Supported: 0x0005 10 us 30 us T_FCS Times Supported: 0x0009 15 us 50 us T_PM Times Supported: 0x0003 10 us 20 us Key capability fields: o Roles Supported -- Bitmask: bit 0 = Initiator, bit 1 = Reflector. A device must support at least one role. o Modes Supported -- Bitmask of CS measurement modes the controller can perform (Mode 1 = RTT, Mode 2 = PBR tone, Mode 3 = both). o CS Sync PHYs -- Physical layers available for CS sync exchange. LE 2M is the most common. o Num Antennas / Max Antenna Paths -- Determines multi-antenna Phase-Based Ranging capability. o T_IP / T_FCS / T_PM times -- Timing parameters the controller supports for inter-step and tone durations. Read remote CS capabilities (over the air via LL): < HCI Command: LE CS Read Remote Supported Capabilities (0x08|0x008a) plen 2 #110 [hci0] Handle: 2048 > HCI Event: Command Status (0x0f) plen 4 #111 [hci0] LE CS Read Remote Supported Capabilities (0x08|0x008a) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 42 #115 [hci0] LE CS Read Remote Supported Capabilities Complete (0x2c) Status: Success (0x00) Handle: 2048 Num Config Supported: 4 Max Consecutive Procedures Supported: 128 Num Antennas Supported: 1 Max Antenna Paths Supported: 1 Roles Supported: 0x03 Initiator Reflector Modes Supported: 0x03 ... This is an asynchronous command -- the controller sends Command Status immediately, then the completion event arrives after the LL exchange. If this fails with a non-zero status, the remote device may not support CS or the connection may have dropped. Cached capabilities can be written directly instead of reading over the air, using LE CS Write Cached Remote Supported Capabilities. Security Enable CS security must be enabled on the connection before creating configurations. This performs a CS security start procedure over the LL to exchange nonces: < HCI Command: LE CS Security Enable (0x08|0x008c) plen 2 #120 [hci0] Handle: 2048 > HCI Event: Command Status (0x0f) plen 4 #121 [hci0] LE CS Security Enable (0x08|0x008c) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 3 #125 [hci0] LE CS Security Enable Complete (0x2e) Status: Success (0x00) Handle: 2048 Security Enable must complete successfully before configuration or procedure commands. If this fails, the link may lack encryption or the remote does not support CS security. Default Settings Default settings configure which roles the local device is willing to accept and the antenna/power preferences for this connection: < HCI Command: LE CS Set Default Settings (0x08|0x008d) plen 5 #130 [hci0] Handle: 2048 Role Enable: 0x03 Initiator Reflector CS Sync Antenna Selection: 0x01 Max TX Power: 20 > HCI Event: Command Complete (0x0e) plen 5 #131 [hci0] LE CS Set Default Settings (0x08|0x008d) ncmd 1 Status: Success (0x00) Handle: 2048 o Role Enable -- Bitmask of roles the device is willing to perform. Both sides typically enable both roles for flexibility. o CS Sync Antenna Selection -- Preferred antenna for CS sync exchange. o Max TX Power -- Upper bound on transmit power for CS procedures (dBm, signed). FAE Table Exchange The Frequency Actuation Error (FAE) table contains per-channel calibration data that improves distance accuracy. Like capabilities, it can be read from the remote or written from a cache. Read remote FAE table: < HCI Command: LE CS Read Remote FAE Table (0x08|0x008e) plen 2 #135 [hci0] Handle: 2048 > HCI Event: Command Status (0x0f) plen 4 #136 [hci0] LE CS Read Remote FAE Table (0x08|0x008e) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 75 #140 [hci0] LE CS Read Remote FAE Table Complete (0x2d) Status: Success (0x00) Handle: 2048 The FAE table is 72 bytes (one byte per channel). Values are signed offsets in 0.5 ppm units. A value of 0x7f means the channel is unused or not measured. Configuration A CS configuration defines the measurement parameters: mode, role, channel map, and step counts. Up to 4 configurations can exist simultaneously per connection (config_id 0--3). Create a CS configuration: < HCI Command: LE CS Create Config (0x08|0x0090) plen 20 #150 [hci0] Handle: 2048 Config ID: 0 Create Context: 0x00 Main Mode Type: 0x01 Sub Mode Type: 0xff Min Main Mode Steps: 2 Max Main Mode Steps: 5 Main Mode Repetition: 0 Mode 0 Steps: 3 Role: Initiator (0x00) RTT Type: 0x01 CS Sync PHY: LE 2M (0x01) Channel Map: ffffffffff7f0000000000000000 Channel Map Repetition: 1 Channel Selection Type: 0x00 Ch3c Shape: 0x00 Ch3c Jump: 0x00 > HCI Event: Command Status (0x0f) plen 4 #151 [hci0] LE CS Create Config (0x08|0x0090) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 30 #155 [hci0] LE CS Config Complete (0x2f) Status: Success (0x00) Handle: 2048 Config ID: 0 Action: 0x00 Main Mode Type: 0x01 Sub Mode Type: 0xff Min Main Mode Steps: 2 Max Main Mode Steps: 5 Main Mode Repetition: 0 Mode 0 Steps: 3 Role: Initiator (0x00) RTT Type: 0x01 CS Sync PHY: LE 2M (0x01) Channel Map: ffffffffff7f0000000000000000 Channel Map Repetition: 1 Channel Selection Type: 0x00 Ch3c Shape: 0x00 Ch3c Jump: 0x00 T_IP1 Time: 30 us T_IP2 Time: 30 us T_FCS Time: 50 us T_PM Time: 10 us Key configuration fields: o Main Mode Type -- The primary CS measurement mode: 0x01 = Mode 1 (RTT only), 0x02 = Mode 2 (PBR/tone only), 0x03 = Mode 3 (RTT + PBR combined). o Sub Mode Type -- Secondary mode interleaved with main mode. 0xff = no sub mode. o Mode 0 Steps -- Number of frequency calibration (sync) steps per subevent. Mode 0 is always present for frequency offset compensation. o Main/Min/Max Mode Steps -- Controls how many measurement steps are performed per subevent. o Role -- 0x00 = Initiator, 0x01 = Reflector. This is the local device's role in this configuration. o RTT Type -- Round-trip time measurement variant (AA only, sounding sequence, random sequence). o Channel Map -- 10-byte bitmask of channels available for CS. Must have at least 15 channels enabled. o T_IP1/T_IP2/T_FCS/T_PM -- Timing parameters selected by the controller from the intersection of both devices' capabilities. Reported in the Config Complete event. The Config Complete event confirms the negotiated parameters. The controller may adjust timing values based on both devices' capabilities. Remove a CS configuration: < HCI Command: LE CS Remove Config (0x08|0x0091) plen 3 #160 [hci0] Handle: 2048 Config ID: 0 > HCI Event: Command Status (0x0f) plen 4 #161 [hci0] LE CS Remove Config (0x08|0x0091) ncmd 1 Status: Success (0x00) Procedure Parameters Before enabling a procedure, its scheduling and antenna parameters are configured: < HCI Command: LE CS Set Procedure Parameters (0x08|0x0093) plen 16 #170 [hci0] Handle: 2048 Config ID: 0 Max Procedure Len: 200 Min Procedure Interval: 10 Max Procedure Interval: 20 Max Procedure Count: 0 Min Subevent Len: 5000 us Max Subevent Len: 10000 us Tone Antenna Config Selection: 0x01 PHY: LE 2M (0x02) TX Power Delta: 0 Preferred Peer Antenna: 0x01 SNR Control Initiator: 0x00 SNR Control Reflector: 0x00 > HCI Event: Command Complete (0x0e) plen 5 #171 [hci0] LE CS Set Procedure Parameters (0x08|0x0093) ncmd 1 Status: Success (0x00) Handle: 2048 o Max Procedure Len -- Maximum duration of a single CS procedure in units of 0.625 ms. o Procedure Interval -- Spacing between repeated procedures (in connection events). o Max Procedure Count -- 0 means indefinite repetition until explicitly disabled. o Subevent Len -- Duration bounds for each subevent within a procedure (in microseconds, 24-bit). o Tone Antenna Config Selection -- Which antenna pattern to use for tone exchange. o SNR Control -- Signal-to-noise ratio requirements for Initiator and Reflector. Procedure Enable / Disable Once configuration and parameters are set, the CS procedure is started and stopped with enable/disable commands. Enable a CS procedure: < HCI Command: LE CS Procedure Enable (0x08|0x0094) plen 4 #180 [hci0] Handle: 2048 Config ID: 0 Enable: 0x01 > HCI Event: Command Status (0x0f) plen 4 #181 [hci0] LE CS Procedure Enable (0x08|0x0094) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 20 #185 [hci0] LE CS Procedure Enable Complete (0x30) Status: Success (0x00) Handle: 2048 Config ID: 0 State: 0x01 Tone Antenna Config Selection: 0x01 Selected TX Power: 12 Subevent Len: 5000 us Subevents Per Event: 2 Subevent Interval: 3750 Event Interval: 10 Procedure Interval: 10 Procedure Count: 100 Max Procedure Len: 200 The Procedure Enable Complete event confirms the actual scheduling parameters chosen by the controller. Important fields: o State -- 0x01 = procedure enabled, 0x00 = disabled. o Subevents Per Event -- How many subevents fit in each connection event. o Procedure Count -- Actual number of procedures that will be executed (may differ from the requested maximum). Disable a CS procedure: < HCI Command: LE CS Procedure Enable (0x08|0x0094) plen 4 #300 [hci0] Handle: 2048 Config ID: 0 Enable: 0x00 > HCI Event: Command Status (0x0f) plen 4 #301 [hci0] LE CS Procedure Enable (0x08|0x0094) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 20 #305 [hci0] LE CS Procedure Enable Complete (0x30) Status: Success (0x00) Handle: 2048 Config ID: 0 State: 0x00 ... Channel Classification The host can restrict which channels CS uses by marking noisy channels as unused: < HCI Command: LE CS Set Channel Classification (0x08|0x0092) plen 10 #145 [hci0] Channel Map: ffffffffff7f0000000000 > HCI Event: Command Complete (0x0e) plen 1 #146 [hci0] LE CS Set Channel Classification (0x08|0x0092) ncmd 1 Status: Success (0x00) The channel map is a 10-byte (80-bit) bitmask. Bit N = 1 means channel N is available for CS. At least 15 channels must remain enabled or the procedure will abort. Subevent Results While a CS procedure is running, the controller reports measurement results via subevent result events. Each subevent contains multiple steps, and each step contains mode-specific measurement data. Subevent Result: > HCI Event: LE Meta Event (0x3e) plen 50 #200 [hci0] LE CS Subevent Result (0x31) Handle: 2048 Config ID: 0 Start ACL Conn Event Counter: 1200 Procedure Counter: 0 Frequency Compensation: 0x0000 Reference Power Level: -20 Procedure Done Status: Partial results (0x01) Subevent Done Status: All results complete (0x00) Abort Reason: 0x00 Num Antenna Paths: 1 Num Steps Reported: 8 Step Data: Mode: 0 Channel: 10 Length: 5 Packet Quality: 0x00 Packet RSSI: -45 Packet Antenna: 0 Measured Freq Offset: 150 Mode: 1 Channel: 20 Length: 6 Packet Quality: 0x00 Packet NADM: Attack is extremely unlikely (0x00) Packet RSSI: -42 ToA/ToD: 1234 Packet Antenna: 0 Mode: 2 Channel: 30 Length: 5 Antenna Permutation Index: 0 PCT[0]: I=1024, Q=-512 Tone Quality: High (0x00) ... Result events can be split across multiple events when data is large: Subevent Result Continue (continuation fragment): > HCI Event: LE Meta Event (0x3e) plen 40 #202 [hci0] LE CS Subevent Result Continue (0x32) Handle: 2048 Config ID: 0 Procedure Done Status: Partial results (0x01) Subevent Done Status: All results complete (0x00) Abort Reason: 0x00 Num Antenna Paths: 1 Num Steps Reported: 4 Step Data: ... CS Step Modes Each CS subevent consists of steps executed on different channels. Each step operates in one of four modes: Mode 0 -- Frequency Calibration (CS Sync) Mode 0 steps are always present at the start of each subevent. They exchange a known CS sync sequence to calibrate frequency offsets between the two devices. Fields reported: o Packet Quality -- 0x00 = CS Access Address matched, 0x01 = bit errors detected, 0x02 = not found. o Packet RSSI -- Received signal strength (signed, dBm). o Packet Antenna -- Antenna index used. o Measured Freq Offset -- Frequency offset in 0.01 ppm units (15-bit value). Only present when data length is 5. Mode 1 -- Round-Trip Time (RTT) Mode 1 measures the time-of-arrival and time-of-departure to compute round-trip delay for distance estimation. Fields reported: o Packet Quality -- Same as Mode 0. o Packet NADM -- Normalized Attack Detector Metric, indicates likelihood that the RTT measurement has been tampered with: o 0x00 = attack extremely unlikely o 0x01 = attack very unlikely o 0x02 = attack unlikely o 0x03 = attack possible o 0x04 = attack likely o 0x05 = attack very likely o 0x06 = attack extremely likely o 0xff = unknown o ToA/ToD -- Time-of-Arrival minus Time-of-Departure difference (signed 16-bit). 0x8000 = measurement not available. o PCT1/PCT2 -- Phase Correction Terms (I/Q, 12 bits each). Present only with certain RTT types. Mode 2 -- Phase-Based Ranging (PBR / Tone Exchange) Mode 2 exchanges tones for high-precision phase measurement. Multiple antenna paths can be measured simultaneously. Fields reported: o Antenna Permutation Index -- Identifies the antenna switching pattern used. o PCT (per antenna path) -- Phase Correction Term with I component (bits 0--11) and Q component (bits 12--23). o Tone Quality Indicator -- Low nibble: o 0x00 = high quality o 0x01 = medium quality o 0x02 = low quality o 0x03 = not available High nibble (tone extension slot): o 0x00 = not a tone extension slot o 0x01 = tone extension slot, tone not expected o 0x02 = tone extension slot, tone expected Mode 3 -- Combined RTT + Tone Mode 3 combines Mode 1 and Mode 2 in a single step. The initial fields match Mode 1 (quality, NADM, RSSI, ToA/ToD, antenna), followed by Mode 2 tone data. Result Status Fields Each subevent result event contains status fields that indicate whether the procedure and subevent completed normally. Procedure Done Status: o 0x00 -- All results complete for this CS procedure o 0x01 -- Partial results, more events will follow o 0x0f -- All subsequent procedures aborted Subevent Done Status: o 0x00 -- All results complete for this subevent o 0x01 -- Partial results, continuation event will follow o 0x0f -- Current subevent aborted Abort Reason (packed byte): Low nibble (procedure abort reason): o 0x00 -- No abort o 0x01 -- Aborted by local Host or remote request o 0x02 -- Channel map has fewer than 15 channels o 0x03 -- Channel map update instant has passed o 0x0f -- Unspecified reason High nibble (subevent abort reason): o 0x00 -- No abort o 0x01 -- Aborted by local Host or remote request o 0x02 -- No CS_SYNC (Mode 0) received o 0x03 -- Scheduling conflict or limited resources o 0x0f -- Unspecified reason CS State Machine A CS configuration transitions through these states on each device. The state is not reported explicitly in a single field -- it is inferred from the sequence of HCI commands and events: | IDLE | | LE CS Read Local/Remote Supported Capabilities | LE CS Security Enable Complete | LE CS Set Default Settings | CAPABILITIES | Both devices' CS parameters are known. | EXCHANGED | Security is established. | LE CS Create Config | LE CS Config Complete (status=0x00) | CONFIGURED | Config ID N exists with negotiated params. | (config_id=N) | Can create up to 4 configs simultaneously. | LE CS Set Procedure Parameters | PARAMETERS SET | Scheduling and antenna params are locked. | (config_id=N) | | LE CS Procedure Enable (enable=1) | LE CS Procedure Enable Complete (state=1) | PROCEDURE | Controller is actively measuring. | RUNNING | Subevent Result events stream in. | (config_id=N) | | LE CS Procedure Enable (enable=0) | LE CS Procedure Enable Complete (state=0) | CONFIGURED | Config still exists, can re-enable. | (config_id=N) | | LE CS Remove Config | IDLE | Multiple configurations can coexist. Removing one config does not affect others. Typical CS Setup Sequence A complete HCI-only CS distance measurement session follows this flow. The left column shows the Host Controller commands, and the right column shows the resulting state: Host Controller State LE CS Read Local Supported Capabilities IDLE Command Complete (capabilities) | LE CS Read Remote Supported Capabilities | Command Status | LE CS Read Remote Supp. Cap. Complete | | LE CS Security Enable | Command Status | LE CS Security Enable Complete | | LE CS Set Default Settings | Command Complete CAPABILITIES EXCHANGED LE CS Read Remote FAE Table (optional) | LE CS Read Remote FAE Complete | | LE CS Set Channel Classification (optional) | Command Complete | | LE CS Create Config (config_id=0) | Command Status | LE CS Config Complete CONFIGURED (id=0) LE CS Set Procedure Parameters (config_id=0) | Command Complete PARAMETERS SET (id=0) LE CS Procedure Enable (id=0, enable=1) | Command Status | LE CS Procedure Enable Complete (state=1) PROCEDURE RUNNING (id=0) LE CS Subevent Result | LE CS Subevent Result Cont. |(repeated) | LE CS Subevent Result | | LE CS Procedure Enable (id=0, enable=0) | Command Status | LE CS Procedure Enable Complete (state=0) CONFIGURED (id=0) LE CS Remove Config (id=0) (optional) | Command Status IDLE Steps above the first LE CS Create Config are one-time setup per connection. The config/params/enable/disable cycle can be repeated. CS Test Mode CS Test mode allows the controller to run CS procedures without a remote device, for manufacturing and validation purposes: < HCI Command: LE CS Test (0x08|0x0095) plen 34 #400 [hci0] Main Mode Type: 0x01 Sub Mode Type: 0xff Main Mode Repetition: 0 Mode 0 Steps: 3 Role: Initiator (0x00) RTT Type: 0x01 CS Sync PHY: LE 2M (0x01) CS Sync Antenna Selection: 0x01 Subevent Len: 5000 us Subevent Interval: 0 Max Num Subevents: 1 Transmit Power Level: 10 T_IP1 Time: 30 us T_IP2 Time: 30 us T_FCS Time: 50 us T_PM Time: 10 us T_SW Time: 0 us Tone Antenna Config Selection: 0x01 SNR Control Initiator: 0x00 SNR Control Reflector: 0x00 DRBG Nonce: 0x0000 Channel Map Repetition: 1 Override Config: 0x0000 > HCI Event: Command Complete (0x0e) plen 5 #401 [hci0] LE CS Test (0x08|0x0095) ncmd 1 Status: Success (0x00) Results arrive as normal LE CS Subevent Result events. The test is terminated with: < HCI Command: LE CS Test End (0x08|0x0096) plen 0 #450 [hci0] > HCI Event: LE Meta Event (0x3e) plen 1 #451 [hci0] LE CS Test End Complete (0x33) Status: Success (0x00) Common Issues Security Enable fails The connection must be encrypted before CS Security Enable. Check that SMP pairing and LE Encrypt have completed. Also verify both devices advertise CS support in their LE feature set. Config Complete with error The controller may reject a configuration if the requested parameters are incompatible with the intersection of both devices' capabilities. Check that main mode, PHY, and timing parameters fall within both devices' supported ranges. Channel map too small CS requires at least 15 channels. If channel classification or interference eliminates too many channels, the procedure aborts with abort reason 0x02 (low nibble). No Mode 0 sync received Subevent abort reason 0x02 (high nibble) means the Initiator's Mode 0 sync packet was not received by the Reflector (or vice versa). This indicates an RF issue, scheduling miss, or device out of range. Procedure aborted by host Abort reason 0x01 in either nibble means the local host or remote device requested termination, typically via Procedure Enable with enable=0. ToA/ToD not available (0x8000) The controller could not compute a valid time measurement for this step. Common with weak signals or when the CS Access Address was not detected (packet quality = 0x02). RANGING SERVICE (RAS) / RANGING PROFILE (RAP) The Ranging Service (RAS) is a GATT service that transfers CS measurement data between devices at the application layer. It complements the HCI-level CS procedure by providing a standardized way to exchange, acknowledge, and retrieve ranging results over ATT. The Ranging Profile (RAP) defines how a device discovers and interacts with RAS on a remote device. btmon decodes all RAS characteristics automatically when it sees ATT operations on the RAS UUIDs. RAS Service UUID: 0x185B RAS Characteristics +-----------------+--------+------------------+-----------------+ |Characteristic | UUID | Properties | Description | +-----------------+--------+------------------+-----------------+ |RAS Features | 0x2C14 | Read | Bitmask of | | | | | supported RAS | | | | | capabilities | +-----------------+--------+------------------+-----------------+ |RAS Real-time | 0x2C15 | Notify, Indicate | Streaming | |Ranging Data | | | ranging results | | | | | as they are | | | | | produced | +-----------------+--------+------------------+-----------------+ |RAS On-demand | 0x2C16 | Notify, Indicate | Ranging results | |Ranging Data | | | retrieved on | | | | | request | +-----------------+--------+------------------+-----------------+ |RAS Control | 0x2C17 | Write Without | Command | |Point | | Response, | interface for | | | | Indicate | data retrieval | | | | | and filtering | +-----------------+--------+------------------+-----------------+ |RAS Ranging Data | 0x2C18 | Read, Notify, | Signals that a | |Ready | | Indicate | new ranging | | | | | dataset is | | | | | available | +-----------------+--------+------------------+-----------------+ |RAS Ranging Data | 0x2C19 | Read, Notify, | Signals that a | |Overwritten | | Indicate | stored dataset | | | | | was overwritten | +-----------------+--------+------------------+-----------------+ All characteristics except RAS Features use Client Characteristic Configuration (CCC) descriptors to enable notifications/indications. The typical GATT attribute layout uses 18 handles total. RAS Features The RAS Features characteristic is a 4-byte bitmask read by the client to discover the server's capabilities: > ACL Data RX: Handle 2048 flags 0x02 dlen 11 #200 [hci0] ATT: Read Response (0x0b) len 4 Handle: 0x0003 Features: 0x0000000f Real-time Ranging Data (0x00000001) Retrieve Lost Ranging Data Segments (0x00000002) Abort Operation (0x00000004) Filter Ranging Data (0x00000008) Feature bits: o Bit 0 -- Real-time Ranging Data: the server can stream results via the Real-time Ranging Data characteristic as CS procedures run. o Bit 1 -- Retrieve Lost Ranging Data Segments: the client can request retransmission of missing data segments. o Bit 2 -- Abort Operation: the client can cancel an in-progress data transfer. o Bit 3 -- Filter Ranging Data: the client can configure which fields are included in ranging data notifications. RAS Ranging Data Ready When a CS procedure completes and results are stored, the server notifies the client that data is available for retrieval: > ACL Data RX: Handle 2048 flags 0x02 dlen 9 #250 [hci0] ATT: Handle Value Notification (0x1b) len 2 Handle: 0x000e Counter: 42 The counter value identifies the specific ranging dataset. The client uses this counter in subsequent Control Point commands to request or acknowledge the data. RAS Ranging Data Overwritten If the server's buffer is full and older results are discarded, this characteristic notifies the client: > ACL Data RX: Handle 2048 flags 0x02 dlen 9 #260 [hci0] ATT: Handle Value Notification (0x1b) len 2 Handle: 0x0011 Overwritten Count: 38 This tells the client that ranging data with counter value 38 (and possibly earlier) has been overwritten and can no longer be retrieved. RAS Control Point The RAS Control Point is the command interface for managing ranging data transfers. The client writes commands, and the server responds via indications on the same characteristic. Opcodes: +-------+------------------+---------------------+ |Opcode | Command | Description | +-------+------------------+---------------------+ |0x00 | Get Ranging Data | Request on-demand | | | | transfer of a | | | | specific dataset | +-------+------------------+---------------------+ |0x01 | ACK Ranging Data | Acknowledge receipt | | | | of a dataset | +-------+------------------+---------------------+ |0x02 | Retrieve Lost | Re-request specific | | | Ranging Data | missing segments | | | Segments | | +-------+------------------+---------------------+ |0x03 | Abort Operation | Cancel an | | | | in-progress data | | | | transfer | +-------+------------------+---------------------+ |0x04 | Set Filter | Configure which | | | | data fields are | | | | included | +-------+------------------+---------------------+ Get Ranging Data -- requests transfer of a stored dataset: < ACL Data TX: Handle 2048 flags 0x00 dlen 10 #270 [hci0] ATT: Write Command (0x52) len 3 Handle: 0x000b Opcode: Get Ranging Data (0x00) Ranging Counter: 0x002a After this command, the server sends the data as a sequence of notifications on the On-demand Ranging Data characteristic (0x2C16). ACK Ranging Data -- confirms the client received a complete dataset, allowing the server to free the buffer: < ACL Data TX: Handle 2048 flags 0x00 dlen 10 #290 [hci0] ATT: Write Command (0x52) len 3 Handle: 0x000b Opcode: ACK Ranging Data (0x01) Ranging Counter: 0x002a Retrieve Lost Ranging Data Segments -- requests retransmission of specific segments that were missed or corrupted: < ACL Data TX: Handle 2048 flags 0x00 dlen 12 #295 [hci0] ATT: Write Command (0x52) len 5 Handle: 0x000b Opcode: Retrieve Lost Ranging Data Segments (0x02) Ranging Counter: 0x002a First Segment Index: 3 Last Segment Index: 5 A Last Segment Index of 0xFF means "all remaining segments from the first index onward." Abort Operation -- cancels any in-progress data transfer: < ACL Data TX: Handle 2048 flags 0x00 dlen 8 #298 [hci0] ATT: Write Command (0x52) len 1 Handle: 0x000b Opcode: Abort Operation (0x03) Set Filter -- configures which fields to include in ranging data notifications: < ACL Data TX: Handle 2048 flags 0x00 dlen 10 #265 [hci0] ATT: Write Command (0x52) len 3 Handle: 0x000b Opcode: Set Filter (0x04) Filter Configuration: 0x0001 Mode: 1 Filter Bit Mask: 0x0000 The filter configuration is a 16-bit value: bits [1:0] select the filter mode, and bits [15:2] provide a field bitmask. Ranging Data Format Both Real-time (0x2C15) and On-demand (0x2C16) Ranging Data characteristics use the same segmented data format. Large datasets are split across multiple ATT notifications. Segmentation Header (1 byte, present in every notification): > ACL Data RX: Handle 2048 flags 0x02 dlen 30 #275 [hci0] ATT: Handle Value Notification (0x1b) len 25 Handle: 0x0005 Segmentation Header: 0x01 First Segment: True Last Segment: False Segment Index: 0 Ranging Data Body: Ranging Counter: 0x02a Configuration ID: 0 Selected TX Power: 12 dBm Antenna Paths Mask: 0x03 Antenna Path 1 (0x01) Antenna Path 2 (0x02) Subevent #0: Start ACL Connection Event: 1200 Frequency Compensation: 150 (0.01 ppm) Ranging Done Status: Partial results (0x1) Subevent Done Status: All results complete (0x0) Ranging Abort Reason: No abort (0x0) Subevent Abort Reason: No abort (0x0) Reference Power Level: -20 dBm Number of Steps Reported: 8 Remaining Ranging Data Segment: ... Segmentation header fields: o First Segment (bit 0) -- True for the first notification of a dataset. Only the first segment contains the Ranging Header. o Last Segment (bit 1) -- True for the final notification. When both bits are set, the entire dataset fits in one notification. o Segment Index (bits [7:2]) -- Sequential index for reassembly. Ranging Header (4 bytes, only in first segment): o Ranging Counter (bits [11:0]) -- Matches the counter from the Data Ready notification; identifies the CS procedure instance. o Configuration ID (bits [15:12]) -- The CS configuration ID (0--3) used for this measurement. o Selected TX Power (1 byte, signed) -- Actual transmit power used, in dBm. o Antenna Paths Mask (1 byte) -- Bitmask indicating which antenna paths have data: bit 0 = path 1, bit 1 = path 2, etc. Subevent Header (per subevent within the ranging data): o Start ACL Connection Event -- The ACL connection event counter at which this CS subevent started. o Frequency Compensation -- Measured frequency offset in 0.01 ppm units (signed 16-bit). o Ranging Done Status -- Same codes as HCI subevent results: 0x0 = complete, 0x1 = partial, 0xF = aborted. o Subevent Done Status -- 0x0 = complete, 0xF = aborted. o Ranging/Subevent Abort Reason -- Same abort reason codes as HCI: 0x0 = no abort, 0x1 = host/remote request, 0x2 = channel map / no sync, 0x3 = scheduling, 0xF = unspecified. o Reference Power Level -- RSSI reference in dBm (signed). o Number of Steps Reported -- Count of CS step results that follow. The step data following the subevent header uses the same mode-specific format as HCI CS Subevent Result events (Mode 0--3), described in the CS Step Modes section above. Continuation segments contain only the Segmentation Header followed by raw ranging data bytes that are reassembled with the previous segments. RAS Data Transfer State Machine The RAS data transfer for a single ranging dataset transitions through these states: | IDLE | No active data transfer. | Server: CS procedure completes (HCI level) | Server: notifies Ranging Data Ready (counter=N) | DATA READY | Dataset N is buffered on server. | (counter=N) | Client has been notified. | Client writes: Get Ranging Data (counter=N) | OR (real-time mode: automatic push) | TRANSFERRING | Server sends segmented notifications. | (counter=N) | Segment Index increments: 0, 1, 2, ... | | Segment lost? Client writes: | | Retrieve Lost Segments (counter=N, first, last) | | Server re-sends missing segments. | | (loops back to TRANSFERRING) | | | | Client writes: Abort Operation | | Last Segment received | | COMPLETE | | ABORTED | | (counter=N) | | | Client writes: | | ACK Ranging Data | | (counter=N) | | IDLE | Server may free buffer for counter=N. If the server's buffer fills before the client retrieves data, a Ranging Data Overwritten notification is sent and the dataset transitions directly from DATA READY to overwritten (lost). Typical RAS Data Flow A complete RAS session for on-demand data retrieval: 1. Client discovers RAS (UUID 0x185B) via GATT primary service discovery 2. Client reads RAS Features (0x2C14) to learn capabilities 3. Client enables CCC notifications on: - RAS Ranging Data Ready (0x2C18) - RAS Ranging Data Overwritten (0x2C19) - RAS On-demand Ranging Data (0x2C16) or RAS Real-time Ranging Data (0x2C15) 4. CS procedure runs (HCI level) 5. Server notifies Ranging Data Ready with counter=N 6. Client writes Control Point: Get Ranging Data (counter=N) 7. Server sends On-demand Ranging Data notifications (segmented) 8. Client writes Control Point: ACK Ranging Data (counter=N) For real-time streaming, step 6 is skipped -- the server pushes data on the Real-time Ranging Data characteristic (0x2C15) as each CS subevent completes, using the same segmented format. If segments are lost (e.g., due to ATT MTU limitations or missed notifications), the client uses Retrieve Lost Ranging Data Segments to request retransmission of specific segment indices. Combined HCI + GATT Flow The following chart shows the full interleaved timeline of HCI CS operations and GATT RAS operations as they appear in a btmon trace. The left column is HCI traffic (< HCI / > HCI), the center shows GATT ATT traffic (< ACL / > ACL), and the right column shows the combined state: HCI (CS) GATT (RAS) State --- One-time connection setup --- < LE CS Read Local Supp. Cap. IDLE > Command Complete | < LE CS Read Remote Supp. Cap. | > Command Status | > LE CS Read Remote Supp. | Cap. Complete | < LE CS Security Enable | > Command Status | > LE CS Security Enable | Complete | < LE CS Set Default Settings | > Command Complete CAPS EXCHANGED < ATT: Find By Type Value | (RAS UUID 0x185B) | > ATT: Find By Type Value | Response | < ATT: Read Request | (RAS Features 0x2C14) | > ATT: Read Response | Features: 0x0000000f | < ATT: Write Request | (CCC: Ready 0x2C18) | > ATT: Write Response | < ATT: Write Request | (CCC: On-demand 0x2C16) | > ATT: Write Response RAS READY --- Per-measurement cycle (repeatable) --- < LE CS Create Config (id=0) | > Command Status | > LE CS Config Complete CONFIGURED (id=0) < LE CS Set Proc. Params (id=0) | > Command Complete PARAMS SET (id=0) < LE CS Proc. Enable | (id=0, enable=1) | > Command Status | > LE CS Proc. Enable | Complete (state=1) PROCEDURE RUNNING > LE CS Subevent Result | > LE CS Subevent Result | (measurement data | Continue | streams from | > LE CS Subevent Result | controller) | > LE CS Subevent Result | | > LE CS Subevent Result | (Procedure Done=0x00) PROCEDURE COMPLETE > ATT: Notification | (Data Ready 0x2C18) | Counter: N DATA READY (N) < ATT: Write Command | (Control Point 0x2C17) | Get Ranging Data | Counter: N TRANSFERRING (N) > ATT: Notification | (On-demand 0x2C16) | Seg[0]: First=T Last=F | Ranging Header + data | > ATT: Notification | (On-demand 0x2C16) | Seg[1]: First=F Last=F | > ATT: Notification | (On-demand 0x2C16) | Seg[2]: First=F Last=T TRANSFER COMPLETE (N) < ATT: Write Command | (Control Point 0x2C17) | ACK Ranging Data | Counter: N IDLE (buffer freed) --- Cleanup (optional) --- < LE CS Remove Config (id=0) > Command Status IDLE Real-time Streaming Flow When the server supports real-time ranging data (Features bit 0), results are pushed immediately as CS subevents complete, without waiting for a Get Ranging Data request: HCI (CS) GATT (RAS) State < LE CS Proc. Enable PARAMS SET (id=0, enable=1) > LE CS Proc. Enable Complete PROCEDURE RUNNING > LE CS Subevent Result | > ATT: Notification | (Real-time 0x2C15) | Seg[0]: First=T Last=T | Ranging Header + | subevent data > LE CS Subevent Result | > ATT: Notification | (Real-time 0x2C15) | Seg[0]: First=T Last=F | > ATT: Notification | (Real-time 0x2C15) | Seg[1]: First=F Last=T > LE CS Subevent Result > ATT: Notification (Real-time 0x2C15) ... > LE CS Subevent Result | (Procedure Done=0x00) PROCEDURE COMPLETE < ATT: Write Command ACK Ranging Data Counter: N IDLE In real-time mode, each HCI Subevent Result triggers one or more GATT notifications immediately. The Ranging Counter in the data header increments with each procedure. If a notification segment is lost, the client can use Retrieve Lost Segments after the procedure completes (if Features bit 1 is set). Lost Segment Recovery Flow When segments are missed during transfer, the client requests retransmission: GATT (RAS) State > ATT: Notification (On-demand 0x2C16) TRANSFERRING Seg[0]: First=T Last=F received > ATT: Notification (On-demand 0x2C16) Seg[1]: First=F Last=F received | Seg[2] LOST (not received) | | > ATT: Notification (On-demand 0x2C16) | Seg[3]: First=F Last=T received | | (Client detects gap: Seg[2] missing) INCOMPLETE < ATT: Write Command (Control Point 0x2C17) Retrieve Lost Ranging Data Segments Counter: N First Segment Index: 2 Last Segment Index: 2 RECOVERING > ATT: Notification (On-demand 0x2C16) Seg[2]: First=F Last=F re-sent TRANSFER COMPLETE < ATT: Write Command (Control Point 0x2C17) ACK Ranging Data Counter: N IDLE RAS Common Issues Features read returns 0x00000000 The server does not support any optional RAS features. Only basic on-demand data retrieval via Control Point is available. Ranging Data Ready not received Check that CCC notifications are enabled on handle 0x2C18. Also verify the CS procedure actually completed -- if the procedure was aborted, no Data Ready notification is sent. Segmentation reassembly errors Verify that Segment Index values are sequential and that the First Segment flag is set on the initial notification. A missing segment triggers the Retrieve Lost Segments mechanism if the server supports it (Features bit 1). Data Overwritten before retrieval The server has limited buffer space. If the client does not retrieve and ACK data promptly, older datasets are overwritten. The Data Overwritten notification indicates the counter value of the lost data. Control Point write rejected The connection must be encrypted. RAS Control Point requires write permission with encryption (WRITE_ENCRYPT). Verify that SMP pairing has completed. CLASSIC AUDIO PROTOCOL FLOW Classic Bluetooth audio uses two main profiles: A2DP for high-quality stereo streaming and HFP for voice calls. Both run over BR/EDR ACL connections and use different transport mechanisms for audio data -- A2DP uses L2CAP-based AVDTP media channels while HFP uses SCO/eSCO synchronous connections. A2DP: Advanced Audio Distribution A2DP uses AVDTP (Audio/Video Distribution Transport Protocol) over L2CAP to negotiate codec parameters and stream high-quality audio. btmon fully decodes AVDTP signaling, codec capabilities, and AVRCP remote control messages. AVDTP Signaling Channel A2DP begins with an L2CAP connection on PSM 25 (0x0019). The first L2CAP connection on this PSM carries AVDTP signaling; a second connection on the same PSM carries media transport data: < ACL Data TX: Handle 1 flags 0x00 dlen 12 L2CAP: Connection Request (0x02) ident 1 len 4 PSM: 25 (0x0019) Source CID: 64 > ACL Data RX: Handle 1 flags 0x02 dlen 16 L2CAP: Connection Response (0x03) ident 1 len 8 Destination CID: 64 Source CID: 64 Result: Connection successful (0x0000) Status: No further information available (0x0000) After L2CAP configuration completes, AVDTP signaling begins on this channel. Stream Endpoint Discovery The initiator discovers available Stream Endpoints (SEPs) on the remote device: < ACL Data TX: Handle 1 flags 0x00 dlen 6 Channel: 64 len 2 [PSM 25 mode Basic (0x00)] {chan 0} AVDTP: Discover (0x01) Command (0x00) type 0x00 label 0 nosp 0 > ACL Data RX: Handle 1 flags 0x02 dlen 10 Channel: 64 len 6 [PSM 25 mode Basic (0x00)] {chan 0} AVDTP: Discover (0x01) Response Accept (0x02) type 0x00 label 0 nosp 0 ACP SEID: 1 Media Type: Audio (0x00) SEP Type: SNK (0x01) In use: No Each SEP has a SEID (Stream Endpoint Identifier), media type, and role (Source or Sink). In use: Yes means the endpoint is already streaming. Codec Capability Discovery After discovering SEIDs, the initiator queries each endpoint's capabilities: < ACL Data TX: Handle 1 flags 0x00 dlen 7 Channel: 64 len 3 [PSM 25 mode Basic (0x00)] {chan 0} AVDTP: Get All Capabilities (0x0c) Command (0x00) type 0x00 label 1 nosp 0 ACP SEID: 1 > ACL Data RX: Handle 1 flags 0x02 dlen 30 Channel: 64 len 26 [PSM 25 mode Basic (0x00)] {chan 0} AVDTP: Get All Capabilities (0x0c) Response Accept (0x02) type 0x00 label 1 nosp 0 Service Category: Media Transport (0x01) Service Category: Media Codec (0x07) Media Type: Audio (0x00) Media Codec: SBC (0x00) Frequency: 0xf0 16000 32000 44100 48000 Channel Mode: 0x0f Mono Dual Channel Stereo Joint Stereo Block Length: 0xf0 4 8 12 16 Subbands: 0x0c 4 8 Allocation Method: 0x03 SNR Loudness Minimum Bitpool: 2 Maximum Bitpool: 53 Service Category: Content Protection (0x04) Content Protection Type: SCMS-T (0x0002) Service Category: Delay Reporting (0x08) Capability responses list all supported values as bitmasks. Key service categories: o Media Transport (0x01) -- Always present, indicates the endpoint supports a media transport channel o Media Codec (0x07) -- Codec type and supported parameters o Content Protection (0x04) -- Copy protection (SCMS-T or DTCP) o Delay Reporting (0x08) -- Endpoint supports delay reporting Supported Codecs btmon decodes several A2DP codecs. Each has a different parameter format. SBC (mandatory A2DP codec): Media Codec: SBC (0x00) Frequency: 44100 (0x20) Channel Mode: Joint Stereo (0x01) Block Length: 16 (0x10) Subbands: 8 (0x04) Allocation Method: Loudness (0x01) Minimum Bitpool: 2 Maximum Bitpool: 53 AAC (MPEG-2,4): Media Codec: MPEG-2,4 AAC (0x02) Object Type: MPEG-4 AAC LC (0x40) Frequency: 44100 (0x0100) Channels: 2 (0x04) Bitrate: 256000bps VBR: No aptX (Qualcomm, vendor-specific): Media Codec: Non-A2DP (0xff) Vendor ID: Qualcomm Technologies International, Ltd. (APT) (0x0000004f) Vendor Specific Codec ID: aptX (0x0001) Frequency: 44100 (0x20) Channel Mode: Stereo (0x02) aptX HD (Qualcomm, vendor-specific): Media Codec: Non-A2DP (0xff) Vendor ID: Qualcomm Technologies, Inc. (0x000000d7) Vendor Specific Codec ID: aptX HD (0x0024) Frequency: 44100 (0x20) Channel Mode: Stereo (0x02) LDAC (Sony, vendor-specific): Media Codec: Non-A2DP (0xff) Vendor ID: Sony Corporation (0x0000012d) Vendor Specific Codec ID: LDAC (0x00aa) Vendor codecs appear as Non-A2DP (0xff) with decoded Vendor ID and Codec ID. Capability responses list all supported values as bitmasks; configuration responses show the single selected value. Stream Configuration After selecting a codec and parameters, the initiator sends Set Configuration: < ACL Data TX: Handle 1 flags 0x00 dlen 20 Channel: 64 len 16 [PSM 25 mode Basic (0x00)] {chan 0} AVDTP: Set Configuration (0x03) Command (0x00) type 0x00 label 2 nosp 0 ACP SEID: 1 INT SEID: 1 Service Category: Media Transport (0x01) Service Category: Media Codec (0x07) Media Type: Audio (0x00) Media Codec: SBC (0x00) Frequency: 44100 (0x20) Channel Mode: Joint Stereo (0x01) Block Length: 16 (0x10) Subbands: 8 (0x04) Allocation Method: Loudness (0x01) Minimum Bitpool: 2 Maximum Bitpool: 53 > ACL Data RX: Handle 1 flags 0x02 dlen 6 Channel: 64 len 2 [PSM 25 mode Basic (0x00)] {chan 0} AVDTP: Set Configuration (0x03) Response Accept (0x02) type 0x00 label 2 nosp 0 Configuration responses show single selected values instead of bitmask lists. ACP SEID is the remote endpoint, INT SEID is the local endpoint. If configuration is rejected: > ACL Data RX: Handle 1 flags 0x02 dlen 8 Channel: 64 len 4 [PSM 25 mode Basic (0x00)] {chan 0} AVDTP: Set Configuration (0x03) Response Reject (0x03) type 0x00 label 2 nosp 0 Service Category: Media Codec (0x07) Error code: Unsupported Configuration (0x29) Common AVDTP error codes: +-----+-------------------+---------------------+ |Code | Name | Meaning | +-----+-------------------+---------------------+ |0x01 | Bad Header Format | Malformed AVDTP | | | | header | +-----+-------------------+---------------------+ |0x11 | Bad ACP SEID | Unknown endpoint ID | +-----+-------------------+---------------------+ |0x12 | SEP In Use | Endpoint already | | | | streaming | +-----+-------------------+---------------------+ |0x13 | SEP Not In Use | Endpoint not | | | | configured | +-----+-------------------+---------------------+ |0x29 | Unsupported | Requested | | | Configuration | parameters not | | | | supported | +-----+-------------------+---------------------+ |0x31 | Bad State | Command not valid | | | | in current state | +-----+-------------------+---------------------+ Open and Start After configuration, the stream is opened and then started: < ACL Data TX: Handle 1 flags 0x00 dlen 7 Channel: 64 len 3 [PSM 25 mode Basic (0x00)] {chan 0} AVDTP: Open (0x06) Command (0x00) type 0x00 label 3 nosp 0 ACP SEID: 1 > ACL Data RX: Handle 1 flags 0x02 dlen 6 Channel: 64 len 2 [PSM 25 mode Basic (0x00)] {chan 0} AVDTP: Open (0x06) Response Accept (0x02) type 0x00 label 3 nosp 0 After Open succeeds, a second L2CAP connection on PSM 25 is established for the media transport channel. Then Start begins streaming: < ACL Data TX: Handle 1 flags 0x00 dlen 7 Channel: 64 len 3 [PSM 25 mode Basic (0x00)] {chan 0} AVDTP: Start (0x07) Command (0x00) type 0x00 label 4 nosp 0 ACP SEID: 1 > ACL Data RX: Handle 1 flags 0x02 dlen 6 Channel: 64 len 2 [PSM 25 mode Basic (0x00)] {chan 0} AVDTP: Start (0x07) Response Accept (0x02) type 0x00 label 4 nosp 0 Media Data After Start, encoded audio flows on the media transport channel (second L2CAP connection on PSM 25). btmon does not decode media packet contents by default -- media data is suppressed. Only the L2CAP channel header is visible when the --show-a2dp-stream filter is enabled, with the payload shown as a raw hex dump. The AVDTP state machine visible in the trace: +-----------+--------------------+---------------------+ |State | Triggered By | Description | +-----------+--------------------+---------------------+ |Idle | Initial / Abort | No stream | | | response | configured | +-----------+--------------------+---------------------+ |Configured | Set Configuration | Codec and | | | accept | parameters selected | +-----------+--------------------+---------------------+ |Open | Open accept / | Transport channel | | | Suspend accept | ready, not | | | | streaming | +-----------+--------------------+---------------------+ |Streaming | Start accept | Audio data flowing | +-----------+--------------------+---------------------+ |Closing | Close command sent | Tearing down stream | +-----------+--------------------+---------------------+ |Aborting | Abort command sent | Forced teardown | +-----------+--------------------+---------------------+ Suspend, Close, and Abort Suspend pauses streaming without tearing down the transport: AVDTP: Suspend (0x09) Command (0x00) type 0x00 label 5 nosp 0 ACP SEID: 1 AVDTP: Suspend (0x09) Response Accept (0x02) type 0x00 label 5 nosp 0 Close tears down the stream (returns to Idle): AVDTP: Close (0x08) Command (0x00) type 0x00 label 6 nosp 0 ACP SEID: 1 AVDTP: Close (0x08) Response Accept (0x02) type 0x00 label 6 nosp 0 Abort forces immediate teardown: AVDTP: Abort (0x0a) Command (0x00) type 0x00 label 7 nosp 0 ACP SEID: 1 AVDTP: Abort (0x0a) Response Accept (0x02) type 0x00 label 7 nosp 0 Delay Reporting When the sink supports delay reporting, it sends a Delay Report to inform the source of its rendering delay: AVDTP: Delay Report (0x0d) Command (0x00) type 0x00 label 8 nosp 0 ACP SEID: 1 Delay: 15.0ms AVDTP: Delay Report (0x0d) Response Accept (0x02) type 0x00 label 8 nosp 0 AVRCP Remote Control AVRCP (Audio/Video Remote Control Profile) uses L2CAP PSM 23 (control) and PSM 27 (browsing). btmon decodes AVCTP framing and AVRCP PDUs. Volume control: < ACL Data TX: Handle 1 flags 0x00 dlen 17 Channel: 66 len 13 [PSM 23 mode Basic (0x00)] {chan 2} AVCTP Control: Response: type 0x00 label 0 PID 0x110e AV/C: Accepted: address 0x48 opcode 0x00 Subunit: Panel Opcode: Vendor Dependent Company ID: 0x001958 AVRCP: SetAbsoluteVolume pt Single len 0x0001 Volume: 50.39% (64/127) Playback status: AVRCP: GetPlayStatus pt Single len 0x0009 SongLength: 0x00038270 (230000 milliseconds) SongPosition: 0x00000000 (0 milliseconds) PlayStatus: 0x01 (PLAYING) Track metadata (GetElementAttributes response): AVRCP: GetElementAttributes pt Single len 0x0050 AttributeCount: 0x02 Attribute: 0x00000001 (Title) CharsetID: 0x006a (UTF-8) AttributeValueLength: 0x000c AttributeValue: My Song Name Attribute: 0x00000002 (Artist) CharsetID: 0x006a (UTF-8) AttributeValueLength: 0x000b AttributeValue: The Artist Passthrough commands (play, pause, skip): AVCTP Control: Command: type 0x00 label 1 PID 0x110e AV/C: Control: address 0x48 opcode 0x7c Subunit: Panel Opcode: Passthrough Operation: 0x44 (PLAY Pressed) Length: 0x00 Event notifications (volume change, track change): AVRCP: RegisterNotification pt Single len 0x0005 EventID: 0x0d (EVENT_VOLUME_CHANGED) Volume: 50.39% (64/127) Automating A2DP Analysis Identify A2DP activity: grep -n "AVDTP:\|Media Codec:" output.txt Track AVDTP state transitions: grep -n "AVDTP:.*Command\|AVDTP:.*Response" output.txt Check codec negotiation (what was selected): grep -n "Set Configuration\|Media Codec:" output.txt Verify stream is flowing -- look for Start accept followed by media data: grep -n "AVDTP: Start\|PSM 25.*chan 1" output.txt Detect codec mismatch -- look for Set Configuration reject: grep -n "Response Reject\|Error code:" output.txt Track AVRCP volume and playback: grep -n "SetAbsoluteVolume\|Volume:\|GetPlayStatus\|PlayStatus:" output.txt Full A2DP diagnosis pattern: 1. Find L2CAP Connection Request for PSM 25 -- confirms AVDTP channel setup 2. Find Discover response -- shows available endpoints and whether any are already in use 3. Find Get All Capabilities response -- verify codec support overlap 4. Find Set Configuration -- verify agreed codec and parameters 5. Find Open and Start -- confirm stream setup succeeded 6. Find second L2CAP connection on PSM 25 -- media transport channel 7. On failure, check for Response Reject with error code 8. If audio cuts out, look for Suspend or Close, or check for ACL disconnection HFP: Hands-Free Profile HFP carries voice audio over SCO/eSCO connections with call control over RFCOMM. btmon decodes RFCOMM framing and SCO/eSCO connection setup. AT commands (the HFP control protocol) appear as raw hex dumps within RFCOMM data frames -- btmon does not parse AT command syntax. SDP Discovery HFP uses SDP to discover the remote device's Hands-Free or Audio Gateway service record and its RFCOMM channel number: < ACL Data TX: Handle 1 flags 0x00 dlen 25 Channel: 64 len 21 [PSM 1 mode Basic (0x00)] {chan 0} SDP: Service Search Attribute Request (0x06) tid 1 len 16 Search pattern: [len 5] Sequence (6) with 3 byte(s) [8 extra bits] len 5 UUID (3) with 2 byte(s) [0 extra bits] len 3 Handsfree Audio Gateway (0x111f) Max record count: 65535 Attribute list: [len 5] Sequence (6) with 3 byte(s) [8 extra bits] len 5 Unsigned Integer (1) with 4 byte(s) [0 extra bits] len 5 0x0000ffff Continuation state: 0 The response contains the service record with the RFCOMM channel: > ACL Data RX: Handle 1 flags 0x02 dlen 89 Channel: 64 len 85 [PSM 1 mode Basic (0x00)] {chan 0} SDP: Service Search Attribute Response (0x07) tid 1 len 80 Attribute bytes: 77 Attribute list: [len 75] {position 0} Attribute: Service Class ID List (0x0001) [len 2] Handsfree Audio Gateway (0x111f) Attribute: Protocol Descriptor List (0x0004) [len 2] L2CAP (0x0100) RFCOMM (0x0003) Channel: 1 Attribute: Bluetooth Profile Descriptor List (0x0009) [len 2] Handsfree (0x111e) Version: 0x0108 Continuation state: 0 Key fields to extract: o Service Class -- Handsfree (0x111e) for HF role, Handsfree Audio Gateway (0x111f) for AG role o RFCOMM Channel -- The channel number under RFCOMM (0x0003) in the Protocol Descriptor List (e.g., channel 1) o Profile Version -- Under the Bluetooth Profile Descriptor List (e.g., 0x0108 = HFP 1.8, 0x0109 = HFP 1.9) RFCOMM Connection Setup RFCOMM runs over L2CAP PSM 3. The connection proceeds in stages: multiplexer session on DLCI 0, parameter negotiation, then the data channel on the target DLCI. L2CAP connection for RFCOMM: < ACL Data TX: Handle 1 flags 0x00 dlen 12 L2CAP: Connection Request (0x02) ident 2 len 4 PSM: 3 (0x0003) Source CID: 65 > ACL Data RX: Handle 1 flags 0x02 dlen 16 L2CAP: Connection Response (0x03) ident 2 len 8 Destination CID: 65 Source CID: 65 Result: Connection successful (0x0000) Status: No further information available (0x0000) SABM/UA on DLCI 0 (multiplexer session): < ACL Data TX: Handle 1 flags 0x00 dlen 12 Channel: 65 len 4 [PSM 3 mode Basic (0x00)] {chan 1} RFCOMM: Set Async Balance Mode (SABM) (0x2f) Address: 0x03 cr 1 dlci 0x00 Control: 0x3f poll/final 1 Length: 0 FCS: 0x1c > ACL Data RX: Handle 1 flags 0x02 dlen 12 Channel: 65 len 4 [PSM 3 mode Basic (0x00)] {chan 1} RFCOMM: Unnumbered Ack (UA) (0x63) Address: 0x03 cr 1 dlci 0x00 Control: 0x73 poll/final 1 Length: 0 FCS: 0xd7 Parameter Negotiation (MCC on DLCI 0): Channel: 65 len 14 [PSM 3 mode Basic (0x00)] {chan 1} RFCOMM: Unnumbered Info with Header Check (UIH) (0xef) Address: 0x03 cr 1 dlci 0x00 Control: 0xef poll/final 0 Length: 10 FCS: 0x70 MCC Message type: DLC Parameter Negotiation CMD (0x20) Length: 8 dlci 2 frame_type 0 credit_flow 15 pri 7 ack_timer 0 frame_size 127 max_retrans 0 credits 7 The DLCI in the PN command identifies the target channel. For RFCOMM channel N, DLCI = N * 2 (or N * 2 + 1 depending on the initiator role). SABM/UA on target DLCI (data channel): Channel: 65 len 4 [PSM 3 mode Basic (0x00)] {chan 1} RFCOMM: Set Async Balance Mode (SABM) (0x2f) Address: 0x0b cr 1 dlci 0x02 Control: 0x3f poll/final 1 Length: 0 FCS: 0x59 Channel: 65 len 4 [PSM 3 mode Basic (0x00)] {chan 1} RFCOMM: Unnumbered Ack (UA) (0x63) Address: 0x0b cr 1 dlci 0x02 Control: 0x73 poll/final 1 Length: 0 FCS: 0x92 Modem Status Command (signals readiness): Channel: 65 len 8 [PSM 3 mode Basic (0x00)] {chan 1} RFCOMM: Unnumbered Info with Header Check (UIH) (0xef) Address: 0x03 cr 1 dlci 0x00 Control: 0xef poll/final 0 Length: 4 FCS: 0x70 MCC Message type: Modem Status Command CMD (0x38) Length: 2 dlci 2 fc 0 rtc 1 rtr 1 ic 0 dv 1 AT Command Exchange (SLC Setup) HFP uses AT commands over RFCOMM for call control and feature negotiation. btmon shows these as RFCOMM UIH frames with the AT command text visible in the hex dump. AT command in RFCOMM UIH frame: Channel: 65 len 21 [PSM 3 mode Basic (0x00)] {chan 1} RFCOMM: Unnumbered Info with Header Check (UIH) (0xef) Address: 0x09 cr 0 dlci 0x02 Control: 0xff poll/final 1 Length: 14 FCS: 0x86 Credits: 1 41 54 2b 42 52 53 46 3d 32 30 35 35 0d AT+BRSF=2055. The AT command text is readable in the ASCII column of the hex dump (right side). The Service Level Connection (SLC) setup sequence exchanges device features and capabilities: 1. AT+BRSF= / +BRSF: -- Supported features bitmask exchange 2. AT+BAC=1,2 -- Available codecs (if codec negotiation supported). Codec IDs: 1 = CVSD, 2 = mSBC, 3 = LC3-SWB 3. AT+CIND=? / +CIND:(...) -- Indicator mapping query 4. AT+CIND? / +CIND:values -- Current indicator values 5. AT+CMER=3,0,0,1 -- Enable indicator status reporting 6. AT+CHLD=? / +CHLD:(0,1,2,3,4) -- Three-way calling support Key HFP feature bits (from AT+BRSF): +----+-------------------+-------------------+ |Bit | HF Feature | AG Feature | +----+-------------------+-------------------+ |0 | EC/NR | Three-way calling | +----+-------------------+-------------------+ |1 | Three-way calling | EC/NR | +----+-------------------+-------------------+ |2 | CLI presentation | Voice recognition | +----+-------------------+-------------------+ |3 | Voice recognition | In-band ring tone | +----+-------------------+-------------------+ |4 | Remote volume | Voice tag | +----+-------------------+-------------------+ |5 | Enhanced call | Reject call | | | status | | +----+-------------------+-------------------+ |6 | Enhanced call | Enhanced call | | | control | status | +----+-------------------+-------------------+ |7 | Codec negotiation | Enhanced call | | | | control | +----+-------------------+-------------------+ |8 | HF indicators | Extended error | | | | codes | +----+-------------------+-------------------+ |9 | eSCO S4 (T2) | Codec negotiation | +----+-------------------+-------------------+ |11 | | eSCO S4 (T2) | +----+-------------------+-------------------+ Codec Connection Setup When both sides support codec negotiation (feature bit 7 on HF, bit 9 on AG), the AG selects a codec before establishing the audio link. This appears as AT commands in RFCOMM UIH frames: AG -> HF: +BCS:2 (select mSBC) HF -> AG: AT+BCS=2 (confirm mSBC) AG -> HF: OK HFP codec IDs (used in AT+BAC and AT+BCS): +---+---------+---------------------+ |ID | Codec | Description | +---+---------+---------------------+ |1 | CVSD | Narrow band (8 | | | | kHz), mandatory | +---+---------+---------------------+ |2 | mSBC | Wide band speech | | | | (16 kHz) | +---+---------+---------------------+ |3 | LC3-SWB | Super wide band (32 | | | | kHz), HFP 1.9+ | +---+---------+---------------------+ These HFP-level codec IDs differ from HCI codec IDs. Voice Setting Before SCO/eSCO setup, the host configures the voice setting. For CVSD, the air coding format is CVSD; for mSBC or LC3-SWB, it must be set to Transparent Data: < HCI Command: Write Voice Setting (0x0c|0x0026) plen 2 Setting: 0x0063 Input Coding: Linear Input Data Format: 2's complement Input Sample Size: 16-bit # of bits padding at MSB: 0 Air Coding Format: Transparent Data For CVSD: < HCI Command: Write Voice Setting (0x0c|0x0026) plen 2 Setting: 0x0060 Input Coding: Linear Input Data Format: 2's complement Input Sample Size: 16-bit # of bits padding at MSB: 0 Air Coding Format: CVSD SCO/eSCO Connection Setup After codec negotiation, the host establishes a synchronous connection for voice audio. Setup Synchronous Connection (basic): < HCI Command: Setup Synchronous Connection (0x01|0x0028) plen 17 Handle: 1 Transmit bandwidth: 8000 Receive bandwidth: 8000 Max latency: 13 Setting: 0x0063 Input Coding: Linear Input Data Format: 2's complement Input Sample Size: 16-bit # of bits padding at MSB: 0 Air Coding Format: Transparent Data Retransmission effort: Optimize for link quality (0x02) Packet type: 0x0008 EV3 may be used Enhanced Setup Synchronous Connection (codec-aware): < HCI Command: Enhanced Setup Synchronous Connection (0x01|0x003d) plen 59 Handle: 1 Transmit bandwidth: 8000 Receive bandwidth: 8000 Transmit Coding Format: Codec: mSBC (0x05) Receive Coding Format: Codec: mSBC (0x05) Transmit Codec Frame Size: 60 Receive Codec Frame Size: 60 Input Coding Format: Codec: mSBC (0x05) Output Coding Format: Codec: mSBC (0x05) Input Coded Data Size: 16 Output Coded Data Size: 16 Input PCM Data Format: 2's complement Output PCM Data Format: 2's complement Input PCM Sample Payload MSB Position: 0 Output PCM Sample Payload MSB Position: 0 Input Data Path: HCI Output Data Path: HCI Input Transport Unit Size: 60 Output Transport Unit Size: 60 Max latency: 13 Packet type: 0x0008 EV3 may be used Retransmission effort: Optimize for link quality (0x02) HCI codec IDs displayed by btmon: +-----+-------------+-------------------+ |ID | btmon Name | Used For | +-----+-------------+-------------------+ |0x02 | CVSD | Narrow band voice | +-----+-------------+-------------------+ |0x03 | Transparent | Transparent data | | | | mode | +-----+-------------+-------------------+ |0x04 | Linear PCM | Uncompressed PCM | | | | input/output | +-----+-------------+-------------------+ |0x05 | mSBC | Wide band speech | +-----+-------------+-------------------+ |0x06 | LC3 | Super wide band | | | | (LC3-SWB) | +-----+-------------+-------------------+ Synchronous Connection Complete (result): > HCI Event: Synchronous Connection Complete (0x2c) plen 17 Status: Success (0x00) Handle: 257 Address: 11:22:33:44:55:66 (OUI 11-22-33) Link type: eSCO (0x02) Transmission interval: 0x0c Retransmission window: 0x06 RX packet length: 60 TX packet length: 60 Air mode: Transparent (0x03) Key fields: o Link type -- SCO (0x00) for legacy, eSCO (0x02) for enhanced (used by mSBC and LC3-SWB) o Air mode -- CVSD (0x02) for narrow band, Transparent (0x03) for mSBC or LC3-SWB o RX/TX packet length -- 60 bytes typical for mSBC T2 settings SCO Data Packets After the synchronous connection is established, voice data flows as SCO/eSCO data packets: > BR-ESCO: Handle 257 flags 0x00 dlen 60 < BR-ESCO: Handle 257 flags 0x00 dlen 60 btmon labels packets based on the connection type established in Synchronous Connection Complete: o BR-SCO -- Legacy SCO connection o BR-ESCO -- Enhanced SCO connection (mSBC, LC3-SWB, or eSCO CVSD) SCO data payload is not displayed by default. It requires the --show-sco-data filter to see the hex dump of voice data. Codec-Specific Connection Summary CVSD (narrow band): o HFP codec ID: 1 o HCI codec: CVSD (0x02) o Voice setting: 0x0060 (Air Coding Format: CVSD) o Air mode: CVSD (0x02) o Link type: SCO or eSCO o Typical packet size: 48 bytes (HV3) or 60 bytes (EV3) mSBC (wide band speech): o HFP codec ID: 2 o HCI codec: mSBC (0x05) o Voice setting: 0x0063 (Air Coding Format: Transparent Data) o Air mode: Transparent (0x03) o Link type: eSCO o Typical packet size: 60 bytes (EV3, T2 settings) LC3-SWB (super wide band): o HFP codec ID: 3 o HCI codec: LC3 (0x06) o Voice setting: 0x0063 (Air Coding Format: Transparent Data) o Air mode: Transparent (0x03) o Link type: eSCO o Note: btmon displays LC3, not LC3-SWB Automating HFP Analysis Identify HFP activity -- look for RFCOMM on PSM 3: grep -n "PSM: 3\|RFCOMM:" output.txt Read AT commands -- search hex dump ASCII for AT command patterns: grep -n "AT+B\|AT+C\|+BRSF\|+CIND\|+CHLD\|+BCS" output.txt Check codec negotiation -- look for BCS (Bluetooth Codec Selection): grep -n "+BCS\|AT+BAC\|AT+BCS" output.txt Verify SCO/eSCO setup: grep -n "Setup Synchronous\|Enhanced Setup Synchronous\|Synchronous Connection Complete\|Write Voice Setting" output.txt Check voice codec -- confirm air mode and coding format: grep -n "Air mode:\|Air Coding Format:\|Codec:" output.txt Detect SCO failures -- check Synchronous Connection Complete status: grep -n "Synchronous Connection Complete" output.txt Then examine the next line for Status:. Common failures: o Connection Rejected due to Limited Resources (0x0d) -- controller cannot allocate bandwidth o SCO Offset Rejected (0x2b) -- timing parameters rejected o SCO Interval Rejected (0x2c) -- interval parameters rejected Track call state -- look for CIEV indicator updates: grep -n "+CIEV\|AT+CHUP\|ATD\|ATA\|AT+CLCC\|RING" output.txt Full HFP diagnosis pattern: 1. Find SDP query for UUID 0x111e/0x111f -- confirms HFP discovery 2. Find L2CAP Connection Request for PSM 3 -- RFCOMM channel setup 3. Find RFCOMM SABM/UA on DLCI 0 then target DLCI -- multiplexer and data channel 4. Find AT+BRSF in hex dumps -- feature exchange, check codec negotiation bit 5. Find AT+BAC in hex dumps -- available codecs reported 6. Find +BCS/AT+BCS in hex dumps -- codec selected for audio 7. Find Write Voice Setting -- verify air coding format matches codec 8. Find Setup Synchronous Connection or Enhanced variant -- SCO setup 9. Find Synchronous Connection Complete -- check Status, Link type, Air mode 10. Find BR-SCO or BR-ESCO packets -- voice data flowing ADVERTISING AND SCANNING btmon decodes advertising data structures automatically. Advertising and scan response data appears in HCI LE advertising report events and in advertising command parameters. Advertising Reports When the controller reports received advertisements: > HCI Event: LE Meta Event (0x3e) plen 43 #120 [hci0] 0.500003 LE Extended Advertising Report (0x0d) Event type: 0x0013 Props: 0x0013 Connectable Scannable Complete Address type: Random (0x01) Address: 00:11:22:33:44:55 Primary PHY: LE 1M Secondary PHY: LE 2M SID: 0x01 TX power: 0 dBm RSSI: -55 dBm (0xc9) Data length: 18 The advertising data (AD) structures within the report are decoded as typed fields: Common AD types btmon decodes: +----------+---------------------+---------------------+ |AD Type | Name | Example in btmon | | | | output | +----------+---------------------+---------------------+ |0x01 | Flags | Flags: 0x06 with | | | | decoded bits (LE | | | | General | | | | Discoverable, | | | | BR/EDR Not | | | | Supported) | +----------+---------------------+---------------------+ |0x02/0x03 | Incomplete/Complete | 16-bit Service | | | 16-bit UUIDs | UUIDs (complete): 2 | | | | entries followed by | | | | UUID list | +----------+---------------------+---------------------+ |0x06/0x07 | Incomplete/Complete | 128-bit Service | | | 128-bit UUIDs | UUIDs (complete): 1 | | | | entry | +----------+---------------------+---------------------+ |0x08/0x09 | Shortened/Complete | Name (complete): | | | Local Name | MyDevice | +----------+---------------------+---------------------+ |0x0a | TX Power Level | TX power: 4 dBm | +----------+---------------------+---------------------+ |0x16 | Service Data | Service Data (UUID | | | (16-bit UUID) | 0x184e): ... with | | | | protocol-specific | | | | decoding | +----------+---------------------+---------------------+ |0xff | Manufacturer | Company: Apple, | | | Specific Data | Inc. (76) followed | | | | by hex data | +----------+---------------------+---------------------+ Typical advertising report: > HCI Event: LE Meta Event (0x3e) plen 38 #120 [hci0] 0.500003 LE Extended Advertising Report (0x0d) Address: 00:11:22:33:44:55 RSSI: -62 dBm (0xc2) Flags: 0x06 LE General Discoverable Mode BR/EDR Not Supported Name (complete): LE-Audio-Left 16-bit Service UUIDs (complete): 3 entries Published Audio Capabilities (0x1850) Audio Stream Control (0x184e) Common Audio (0x1853) Service Data (UUID 0x1852): 01a2b3 Appearance: Earbud (0x0941) Extended Advertising Modern controllers use extended advertising commands and events. The setup sequence in btmon: < HCI Command: LE Set Extended Adv Parameters (0x08|0x0036) plen 25 #50 [hci0] 0.100003 Handle: 0x01 Properties: 0x0000 Min advertising interval: 160.000 msec (0x0100) Max advertising interval: 160.000 msec (0x0100) Channel map: 37, 38, 39 (0x07) Own address type: Random (0x01) Peer address type: Public (0x00) PHY: LE 1M, LE 2M SID: 0x01 TX power: 7 dBm < HCI Command: LE Set Extended Adv Data (0x08|0x0037) plen 35 #52 [hci0] 0.101003 Handle: 0x01 Operation: Complete extended advertising data (0x01) Fragment preference: No fragmentation (0x01) Periodic Advertising (LE Audio) LE Audio broadcast sources use periodic advertising to transmit BASE announcements containing codec configuration: > HCI Event: LE Meta Event (0x3e) plen 80 #200 [hci0] 0.500003 LE Periodic Advertising Report (0x0f) Sync handle: 0x0001 TX power: 0 dBm RSSI: -45 dBm CTE Type: No CTE (0xff) Data status: Complete (0x00) Data length: 60 Service Data: Basic Audio Announcement (0x1851) Presentation Delay: 40000 us Number of Subgroups: 1 Codec: LC3 (0x06) Sampling Frequency: 48000 Hz Frame Duration: 10 ms Frame Length: 120 Automating Advertising Analysis Find all advertising reports (devices seen): grep -n "Advertising Report\|Address:.*RSSI:" output.txt Extract device names: grep -n "Name (complete):\|Name (short):" output.txt Find LE Audio devices (by service UUIDs in advertising): grep -n "Audio Stream Control\|Published Audio Capabilities\|Common Audio\|Basic Audio Announcement\|Broadcast Audio" output.txt Track advertising setup (local device configuring advertising): grep -n "Set Extended Adv\|Set Advertising\|Set Scan Response\|Adv Enable" output.txt Find periodic advertising (broadcast audio): grep -n "Periodic Advertising\|PA Sync\|PA Report\|Basic Audio Announcement\|Broadcast.*Announcement" output.txt Identify devices by appearance: grep -n "Appearance:" output.txt MGMT PROTOCOL FLOWS The Management Interface (MGMT) is the structured command/event protocol between userspace (typically bluetoothd) and the kernel Bluetooth subsystem. In btmon output, MGMT traffic is prefixed with @ and provides insight into adapter configuration, device discovery, pairing, and connection management at a higher level than raw HCI. This section covers common MGMT protocol flows as seen through btmon. For MGMT output format basics (line anatomy, Open/Close, parameters, events), see the "Management Traffic" subsection in READING THE OUTPUT above. Initialization and Version Handshake When bluetoothd starts, it opens a management socket and queries the kernel for protocol version and supported features. This handshake must succeed before any controller operations: @ MGMT Open: bluetoothd (privileged) version 1.23 {0x0001} 12:34:49.881936 @ MGMT Command: Read Management Ver.. (0x0001) plen 0 {0x0001} 12:34:49.882003 @ MGMT Event: Command Complete (0x0001) plen 6 {0x0001} 12:34:49.882010 Read Management Version Information (0x0001) plen 3 Status: Success (0x00) Version: 1.23 @ MGMT Command: Read Management Sup.. (0x0002) plen 0 {0x0001} 12:34:49.882050 @ MGMT Event: Command Complete (0x0001) plen 58 {0x0001} 12:34:49.882055 Read Supported Commands (0x0002) plen 55 Status: Success (0x00) Num of commands: 120 Num of events: 38 After the version check, bluetoothd reads the controller list and queries each controller's information: @ MGMT Command: Read Controller Index List (0x0003) plen 0 {0x0001} 12:34:49.882100 @ MGMT Event: Command Complete (0x0001) plen 7 {0x0001} 12:34:49.882105 Read Controller Index List (0x0003) plen 4 Status: Success (0x00) Num controllers: 1 Controller: hci0 @ MGMT Command: Read Controller Inf.. (0x0004) plen 0 {0x0001} [hci0] 12:34:49.882200 @ MGMT Event: Command Complete (0x0001) plen 283 {0x0001} [hci0] 12:34:49.882210 Read Controller Information (0x0004) plen 280 Status: Success (0x00) Address: 00:11:22:33:44:55 Bluetooth version: 5.4 Manufacturer: Intel (2) Supported settings: 0x003effff Current settings: 0x00000080 Key things to check in the initialization flow: o MGMT Open -- Confirms bluetoothd connected. If missing, the daemon did not start or crashed before reaching MGMT setup. o Version mismatch -- If bluetoothd expects a newer MGMT version than the kernel provides, some features may be unavailable. o Num controllers: 0 -- No Bluetooth hardware detected. Check dmesg for driver issues. o Current settings -- The bitmask shows what is currently enabled on the controller (Powered, LE, BR/EDR, SSP, etc.). Adapter Configuration After reading controller info, bluetoothd configures the adapter with a series of MGMT commands before powering it on. The exact sequence depends on main.conf settings and adapter capabilities. Loading stored keys: @ MGMT Command: Load Link Keys (0x0012) plen 3 {0x0001} [hci0] 12:34:50.001200 Debug keys: Disabled (0x00) Key count: 0 @ MGMT Event: Command Complete (0x0001) plen 4 {0x0001} [hci0] 12:34:50.001220 Load Link Keys (0x0012) plen 1 Status: Success (0x00) @ MGMT Command: Load Long Term Keys (0x0013) plen 2 {0x0001} [hci0] 12:34:50.001300 Key count: 0 @ MGMT Event: Command Complete (0x0001) plen 4 {0x0001} [hci0] 12:34:50.001315 Load Long Term Keys (0x0013) plen 1 Status: Success (0x00) @ MGMT Command: Load Identity Resolving Keys (0x0030) plen 2 {0x0001} [hci0] 12:34:50.001400 Key count: 0 @ MGMT Event: Command Complete (0x0001) plen 4 {0x0001} [hci0] 12:34:50.001415 Load Identity Resolving Keys (0x0030) plen 1 Status: Success (0x00) When bonded devices exist, the Key count will be non-zero and btmon will list each key entry. A large number of keys can indicate many paired devices; this is normal. Setting adapter properties: @ MGMT Command: Set Secure Connections (0x002d) plen 1 {0x0001} [hci0] 12:34:50.002100 Secure connections: Enabled (0x01) @ MGMT Event: Command Complete (0x0001) plen 7 {0x0001} [hci0] 12:34:50.002120 Set Secure Connections (0x002d) plen 4 Status: Success (0x00) Current settings: 0x004e0a81 @ MGMT Command: Set Bondable (0x0009) plen 1 {0x0001} [hci0] 12:34:50.002200 Bondable: Enabled (0x01) @ MGMT Event: Command Complete (0x0001) plen 7 {0x0001} [hci0] 12:34:50.002220 Set Bondable (0x0009) plen 4 Status: Success (0x00) Current settings: 0x004e0a91 Powering on: @ MGMT Command: Set Powered (0x0005) plen 1 {0x0001} [hci0] 12:35:04.033564 Powered: Enabled (0x01) @ MGMT Event: Command Complete (0x0001) plen 7 {0x0001} [hci0] 12:35:04.114789 Set Powered (0x0005) plen 4 Status: Success (0x00) Current settings: 0x004e0ac1 Between the Set Powered command and its response, btmon will show the HCI commands the kernel sends to initialize the radio (see HCI INITIALIZATION SEQUENCE). Discovery Device discovery is initiated through MGMT rather than raw HCI commands. bluetoothd (or btmgmt) sends a Start Discovery command specifying which transport types to scan. Starting discovery: @ MGMT Command: Start Discovery (0x0023) plen 1 {0x0001} [hci0] 12:36:00.100200 Address type: 0x07 BR/EDR LE Public LE Random @ MGMT Event: Command Complete (0x0001) plen 5 {0x0001} [hci0] 12:36:00.100500 Start Discovery (0x0023) plen 2 Status: Success (0x00) Address type: 0x07 After this, btmon shows the HCI-level scan commands the kernel issues (LE Set Scan Parameters, LE Set Scan Enable, and/or Inquiry for BR/EDR). Discovered devices appear as MGMT events: @ MGMT Event: Device Found (0x0012) plen 38 {0x0001} [hci0] 12:36:00.250003 LE Address: AA:BB:CC:DD:EE:FF (Random) RSSI: -62 Flags: 0x0000 EIR Data: Name (complete): My Device TX power: 0 Service discovery uses a filtered variant: @ MGMT Command: Start Service Discovery (0x003a) plen 19 {0x0001} [hci0] 12:36:10.100200 Address type: 0x06 LE Public LE Random RSSI threshold: -127 UUIDs: 1 UUID: Heart Rate (0x180d) @ MGMT Event: Command Complete (0x0001) plen 5 {0x0001} [hci0] 12:36:10.100500 Start Service Discovery (0x003a) plen 2 Status: Success (0x00) Stopping discovery: @ MGMT Command: Stop Discovery (0x0024) plen 1 {0x0001} [hci0] 12:36:15.200100 Address type: 0x07 @ MGMT Event: Command Complete (0x0001) plen 5 {0x0001} [hci0] 12:36:15.200400 Stop Discovery (0x0024) plen 2 Status: Success (0x00) @ MGMT Event: Discovering (0x0013) plen 2 {0x0001} [hci0] 12:36:15.200500 Address type: 0x07 Discovery: Disabled (0x00) Discovery problems to look for: o Status: Busy (0x0a) on Start Discovery -- Another discovery session is already active. o Status: Not Powered (0x0f) -- The adapter is not powered on. o Status: RFKilled (0x12) -- The radio is blocked by rfkill. o No Device Found events -- The remote device may not be advertising, or address type filtering may be wrong. Pairing and Bonding via MGMT MGMT provides a high-level pairing interface. The host sends a Pair Device command; the kernel coordinates SMP or SSP as appropriate and reports the result. Initiating pairing: @ MGMT Command: Pair Device (0x0019) plen 8 {0x0001} [hci0] 12:37:00.500200 LE Address: AA:BB:CC:DD:EE:FF (Random) Capability: KeyboardDisplay (0x04) After this command, btmon shows the underlying SMP or SSP exchange (see SMP PAIRING FLOW and HCI INITIALIZATION SEQUENCE for details). User interaction events may appear: @ MGMT Event: User Confirmation Request (0x000f) plen 12 {0x0001} [hci0] 12:37:01.200100 LE Address: AA:BB:CC:DD:EE:FF (Random) Value: 123456 @ MGMT Command: User Confirmation Reply (0x001e) plen 6 {0x0001} [hci0] 12:37:03.800200 LE Address: AA:BB:CC:DD:EE:FF (Random) @ MGMT Event: Command Complete (0x0001) plen 10 {0x0001} [hci0] 12:37:03.800350 User Confirmation Reply (0x001e) plen 7 Status: Success (0x00) Or for passkey entry: @ MGMT Event: User Passkey Request (0x0010) plen 6 {0x0001} [hci0] 12:37:01.200100 LE Address: AA:BB:CC:DD:EE:FF (Random) @ MGMT Command: User Passkey Reply (0x0020) plen 10 {0x0001} [hci0] 12:37:05.100200 LE Address: AA:BB:CC:DD:EE:FF (Random) Passkey: 123456 Pairing success: @ MGMT Event: New Long Term Key (0x000a) plen 37 {0x0001} [hci0] 12:37:06.100200 Store hint: Yes (0x01) LE Address: AA:BB:CC:DD:EE:FF (Random) Key type: Authenticated P-256 (0x03) Central: 0x00 Encryption size: 16 @ MGMT Event: New Identity Resolving Key (0x0018) plen 30 {0x0001} [hci0] 12:37:06.100300 Store hint: Yes (0x01) Random address: AA:BB:CC:DD:EE:FF LE Address: 11:22:33:44:55:66 (Public) Key: 00112233445566778899aabbccddeeff @ MGMT Event: Command Complete (0x0001) plen 10 {0x0001} [hci0] 12:37:06.100500 Pair Device (0x0019) plen 7 Status: Success (0x00) LE Address: AA:BB:CC:DD:EE:FF (Random) Key events to check after pairing: o New Long Term Key with Store hint: Yes -- The kernel is telling userspace to persist this key for future reconnections. o New Identity Resolving Key -- Reveals the device's real address behind an RPA. This is essential for address resolution on reconnect. o Key type -- Authenticated P-256 indicates Secure Connections with MITM protection. Unauthenticated P-256 means Just Works SC. Authenticated (no P-256) means Legacy with MITM. Pairing failure: @ MGMT Event: Command Complete (0x0001) plen 10 {0x0001} [hci0] 12:37:06.100500 Pair Device (0x0019) plen 7 Status: Authentication Failed (0x05) LE Address: AA:BB:CC:DD:EE:FF (Random) MGMT pairing error codes: +-----+--------------------+---------------------+ |Code | Status | Diagnostic Meaning | +-----+--------------------+---------------------+ |0x03 | Failed | Generic failure; | | | | check SMP or HCI | | | | errors preceding | | | | this | +-----+--------------------+---------------------+ |0x04 | Connect Failed | Could not establish | | | | connection before | | | | pairing | +-----+--------------------+---------------------+ |0x05 | Authentication | SMP or SSP | | | Failed | authentication did | | | | not succeed; check | | | | SMP Pairing Failed | | | | reason or HCI | | | | Authentication | | | | Failure event | +-----+--------------------+---------------------+ |0x08 | Timeout | Pairing timed out; | | | | remote device may | | | | have gone out of | | | | range | +-----+--------------------+---------------------+ |0x0b | Rejected | Remote device | | | | rejected the | | | | pairing request | +-----+--------------------+---------------------+ |0x0d | Invalid Parameters | Bad address type or | | | | capability value in | | | | the Pair Device | | | | command | +-----+--------------------+---------------------+ Device Connection and Disconnection MGMT reports connection lifecycle events that complement the HCI-level events shown elsewhere in the trace. Device connected: @ MGMT Event: Device Connected (0x000b) plen 13 {0x0001} [hci0] 12:36:18.974319 LE Address: AA:BB:CC:DD:EE:FF (Random) Flags: 0x0000 EIR Data Length: 0 This event follows the HCI LE (Enhanced) Connection Complete event. It tells userspace that a new connection is ready. Device disconnected: @ MGMT Event: Device Disconnected (0x000c) plen 8 {0x0001} [hci0] 12:38:20.500200 LE Address: AA:BB:CC:DD:EE:FF (Random) Reason: Connection timeout (0x01) Disconnect reasons reported by MGMT: +-----+---------------------+---------------------+ |Code | Reason | Diagnostic Meaning | +-----+---------------------+---------------------+ |0x00 | Unspecified | No reason provided; | | | | typically a local | | | | disconnect | +-----+---------------------+---------------------+ |0x01 | Connection timeout | Link supervision | | | | timeout expired; | | | | device may be out | | | | of range | +-----+---------------------+---------------------+ |0x02 | Connection | Local side | | | terminated by local | initiated the | | | host | disconnection | +-----+---------------------+---------------------+ |0x03 | Connection | Remote device | | | terminated by | initiated the | | | remote host | disconnection | +-----+---------------------+---------------------+ Unpair Device removes stored keys and optionally disconnects: @ MGMT Command: Unpair Device (0x001a) plen 7 {0x0001} [hci0] 12:39:00.100200 LE Address: AA:BB:CC:DD:EE:FF (Random) Disconnect: Enabled (0x01) @ MGMT Event: Command Complete (0x0001) plen 10 {0x0001} [hci0] 12:39:00.100500 Unpair Device (0x001a) plen 7 Status: Success (0x00) Advertising via MGMT Modern BlueZ configures advertising through MGMT commands rather than sending HCI LE advertising commands directly. This provides a multi-client advertising infrastructure. Adding an advertisement: @ MGMT Command: Add Advertising (0x003e) plen 22 {0x0001} [hci0] 12:40:00.100200 Instance: 1 Flags: 0x0006 The connectable flag will be managed The limited discoverable flag will be managed Duration: 0 Timeout: 0 Advertising data length: 6 Scan response length: 0 @ MGMT Event: Command Complete (0x0001) plen 5 {0x0001} [hci0] 12:40:00.100500 Add Advertising (0x003e) plen 2 Status: Success (0x00) Instance: 1 Removing an advertisement: @ MGMT Command: Remove Advertising (0x003f) plen 1 {0x0001} [hci0] 12:41:00.100200 Instance: 1 @ MGMT Event: Command Complete (0x0001) plen 5 {0x0001} [hci0] 12:41:00.100500 Remove Advertising (0x003f) plen 2 Status: Success (0x00) Instance: 1 For the HCI-level advertising commands that result from these MGMT operations, see ADVERTISING AND SCANNING. Error Diagnosis MGMT Command Status and Command Complete events carry error codes that are distinct from HCI error codes. When diagnosing failures, check both layers. MGMT error in Command Complete: @ MGMT Event: Command Complete (0x0001) plen 4 {0x0001} [hci0] 12:42:00.100200 Set Powered (0x0005) plen 1 Status: RFKilled (0x12) MGMT Command Status (asynchronous command accepted or rejected): @ MGMT Event: Command Status (0x0002) plen 3 {0x0001} [hci0] 12:42:01.100200 Start Discovery (0x0023) plen 0 Status: Busy (0x0a) MGMT error codes: +-----+--------------------+---------------------+ |Code | Status | Diagnostic Meaning | +-----+--------------------+---------------------+ |0x00 | Success | Command completed | | | | successfully | +-----+--------------------+---------------------+ |0x01 | Unknown Command | Kernel does not | | | | recognize the | | | | command; MGMT | | | | version may be too | | | | old | +-----+--------------------+---------------------+ |0x02 | Not Connected | Operation requires | | | | an active | | | | connection that | | | | does not exist | +-----+--------------------+---------------------+ |0x03 | Failed | Generic failure; | | | | check HCI events | | | | for root cause | +-----+--------------------+---------------------+ |0x04 | Connect Failed | Connection attempt | | | | failed at HCI level | +-----+--------------------+---------------------+ |0x05 | Authentication | Pairing or | | | Failed | authentication | | | | procedure failed | +-----+--------------------+---------------------+ |0x06 | Not Paired | Operation requires | | | | an existing bond; | | | | device not paired | +-----+--------------------+---------------------+ |0x07 | No Resources | Kernel ran out of | | | | resources (memory, | | | | handles, etc.) | +-----+--------------------+---------------------+ |0x08 | Timeout | Operation timed out | +-----+--------------------+---------------------+ |0x09 | Already Connected | Connection already | | | | exists to target | | | | device | +-----+--------------------+---------------------+ |0x0a | Busy | Another operation | | | | is in progress | | | | (e.g., discovery | | | | running) | +-----+--------------------+---------------------+ |0x0b | Rejected | Operation rejected | | | | by remote device or | | | | policy | +-----+--------------------+---------------------+ |0x0c | Not Supported | Feature not | | | | supported by this | | | | controller or | | | | kernel version | +-----+--------------------+---------------------+ |0x0d | Invalid Parameters | Bad parameters in | | | | the command | +-----+--------------------+---------------------+ |0x0e | Disconnected | Connection was lost | | | | during the | | | | operation | +-----+--------------------+---------------------+ |0x0f | Not Powered | Controller is not | | | | powered on; call | | | | Set Powered first | +-----+--------------------+---------------------+ |0x10 | Cancelled | Operation was | | | | cancelled by the | | | | user or another | | | | command | +-----+--------------------+---------------------+ |0x11 | Invalid Index | Controller index | | | | does not exist | +-----+--------------------+---------------------+ |0x12 | RFKilled | Radio is disabled | | | | by rfkill; unblock | | | | with rfkill unblock | | | | bluetooth | +-----+--------------------+---------------------+ |0x13 | Already Paired | Device is already | | | | paired; unpair | | | | first if re-pairing | | | | is needed | +-----+--------------------+---------------------+ |0x14 | Permission Denied | Process lacks | | | | required privileges | | | | (CAP_NET_ADMIN) | +-----+--------------------+---------------------+ Correlating MGMT and HCI errors: When MGMT reports Failed (0x03) or Authentication Failed (0x05), look at the HCI events immediately preceding the MGMT response. The HCI-level error (e.g., Authentication Failure (0x05), Connection Timeout (0x08)) provides the specific hardware-level cause. Automating MGMT Analysis List all MGMT commands and events: grep -n "@ MGMT" output.txt Find MGMT errors (non-zero status): grep -n "@ MGMT" output.txt | grep -v "Status: Success" Track adapter power state changes: grep -n "Set Powered\|RFKilled\|Not Powered" output.txt Find all discovery activity: grep -n "Start Discovery\|Stop Discovery\|Device Found\|Discovering" output.txt Find pairing activity via MGMT: grep -n "Pair Device\|User Confirmation\|User Passkey\|New Long Term Key\|New Identity Resolving Key\|Authentication Failed" output.txt Find connection lifecycle events: grep -n "Device Connected\|Device Disconnected\|Unpair Device" output.txt Identify which MGMT clients are active: grep -n "@ MGMT Open\|@ MGMT Close" output.txt Full MGMT diagnosis pattern: 1. Find MGMT Open -- confirm bluetoothd connected and note socket ID 2. Check Read Controller Information -- verify address, version, and current settings 3. Find Set Powered -- confirm the adapter was powered on successfully 4. Search for non-Success status codes -- these indicate failures 5. For pairing issues, find Pair Device and trace forward to its Command Complete response 6. For connection issues, find Device Connected/Device Disconnected and check the disconnect reason 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. Each topic references the detailed protocol section earlier in this document. Recommended Workflow 1. Get an overview: Start with btmon -a to see packet counts, connection handles, device addresses, and traffic volumes. 2. Decode with timestamps: Use btmon -t -r > output.txt to produce a text file with wall-clock timestamps for analysis. 3. 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 4. 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. See HCI ERROR AND DISCONNECT REASON CODES for interpretation. 5. Check pairing/security: Search for SMP activity (see SMP PAIRING FLOW): grep -n "Pairing Request\|Pairing Response\|Pairing Failed\|Encryption Change" output.txt 6. Identify LE Audio: Search for ASCS and CIS activity (see LE AUDIO PROTOCOL FLOW): grep -n "ASE Control Point\|CIG Parameters\|Create Connected Isochronous\|CIS Established\|Setup ISO Data Path" output.txt 7. Check for errors: Search across all protocol layers (see PROTOCOL ERROR CODES): # HCI-level errors grep -n "Status:" output.txt | grep -v "Success" # ATT-level errors grep -n "Error Response" output.txt # SMP failures grep -n "Pairing Failed" output.txt # L2CAP rejections grep -n "Connection refused" output.txt 8. Extract GATT discovery: Filter the GATT service/characteristic discovery traffic (see RECONSTRUCTING A GATT DATABASE FROM SNOOP TRACES): # Find all service discovery responses grep -n "Read By Group Type Response\|Attribute group list\|Handle range.*UUID" output.txt # Find all characteristic discovery responses grep -n "Read By Type Response\|Properties:\|Value Handle:\|Value UUID:" output.txt # Find all descriptor discovery responses grep -n "Find Information Response\|Format:\|Handle:.*UUID:" output.txt # Find targeted service searches grep -n "Find By Type Value" output.txt 9. Check L2CAP channels: Identify protocol usage and channel issues (see L2CAP CHANNEL TRACKING): grep -n "PSM:\|Connection Request\|Connection Response\|Parameter Update" output.txt 10. Check advertising: See what devices are visible and what they advertise (see ADVERTISING AND SCANNING): grep -n "Advertising Report\|Name (complete):\|Appearance:" output.txt Key Patterns for Connection Lifecycle A complete connection lifecycle for an LE ACL connection follows this pattern in the trace: 1. LE Enhanced Connection Complete -- connection established, note the Handle and Peer address 2. LE Connection Update Complete -- connection parameters changed (may occur zero or more times) 3. Encryption Change -- link encrypted (may show encryption algorithm). See SMP PAIRING FLOW for the SMP exchange that precedes this. 4. ACL Data with ATT/SMP/L2CAP -- service discovery and data exchange. See RECONSTRUCTING A GATT DATABASE FROM SNOOP TRACES for GATT, L2CAP CHANNEL TRACKING for channel setup, and PROTOCOL ERROR CODES for error interpretation. 5. Disconnect Complete -- connection ended, check Reason field. See HCI ERROR AND DISCONNECT REASON CODES for reason codes. For LE Audio connections, additional steps appear between 3 and 5 (see LE AUDIO PROTOCOL FLOW for full details): o ATT operations on PACS/ASCS characteristics (codec negotiation) o LE Set CIG Parameters command and response o LE Create CIS command o LE CIS Established event (note the CIS handle) o LE Setup ISO Data Path command o ISO Data TX/RX (audio streaming) o Disconnect Complete on CIS handle (stream ended) o LE Remove CIG (group removed) Common Debugging Scenarios Pairing failure diagnosis: 1. Find Pairing Request -- note IO capabilities and auth requirements 2. Find Pairing Response -- compare to determine association model 3. If Pairing Failed appears, the reason code identifies the failure (see SMP PAIRING FLOW) 4. If Encryption Change shows Status: Success, pairing succeeded 5. If no SMP traffic on reconnect but Encryption Change fails, the bond was lost on one side Audio streaming failure diagnosis (see LE AUDIO PROTOCOL FLOW): 1. Check PACS reads -- do both devices support compatible codecs? 2. Check ASE Control Point Config Codec -- was it accepted? 3. Check ASE state notifications -- did the ASE reach Streaming? 4. Check CIS Established -- was Status Success? 5. Check Setup ISO Data Path -- was it configured? 6. Check for ISO Data packets -- is audio actually flowing? GATT operation rejected (see PROTOCOL ERROR CODES): 1. Find Error Response -- note the error code 2. Insufficient Encryption (0x0f) -> expect LE Start Encryption to follow 3. Authentication Insufficient (0x05) -> expect SMP pairing to follow 4. After security is established, the ATT operation should be retried Connection parameter negotiation failure: 1. Find Connection Parameter Update Request (L2CAP level) 2. Check the Response -- rejected means the central denied it 3. Alternatively, find LE Connection Update Complete (HCI level) 4. Check Status -- non-zero means the controller rejected the update 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) Author Marcel Holtmann , Tedd Ho-Jeong An Copyright Free use of this software is granted under the terms of the GNU Lesser General Public Licenses (LGPL). BlueZ April 2021 btmon(1)