From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH BlueZ v2 9/9] doc/btmon: Add HFP protocol flow documentation
Date: Tue, 24 Mar 2026 15:49:45 -0400 [thread overview]
Message-ID: <20260324194946.109349-9-luiz.dentz@gmail.com> (raw)
In-Reply-To: <20260324194946.109349-1-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Add btmon-hfp.rst documenting the HFP protocol flow as seen in btmon
output. Coverage includes:
- SDP service discovery for Handsfree/AG UUIDs
- RFCOMM channel setup over L2CAP PSM 3 (SABM/UA, Parameter
Negotiation, Modem Status Command)
- AT command exchange for SLC setup (noted as hex dump only -- btmon
does not parse AT commands within RFCOMM UIH data frames)
- Codec negotiation via AT+BAC/AT+BCS
- SCO/eSCO synchronous connection setup (voice setting, coding format)
- Codec summary tables (AT-level vs HCI-level codec IDs)
- Automation-friendly grep patterns
---
doc/btmon-classic-audio.rst | 2 +
doc/btmon-hfp.rst | 476 ++++++++++++++++++++++++++++++++++++
2 files changed, 478 insertions(+)
create mode 100644 doc/btmon-hfp.rst
diff --git a/doc/btmon-classic-audio.rst b/doc/btmon-classic-audio.rst
index 11943c3a54bf..3e7c5384be87 100644
--- a/doc/btmon-classic-audio.rst
+++ b/doc/btmon-classic-audio.rst
@@ -10,3 +10,5 @@ A2DP uses L2CAP-based AVDTP media channels while HFP uses SCO/eSCO
synchronous connections.
.. include:: btmon-a2dp.rst
+
+.. include:: btmon-hfp.rst
diff --git a/doc/btmon-hfp.rst b/doc/btmon-hfp.rst
new file mode 100644
index 000000000000..c81c0df3feb3
--- /dev/null
+++ b/doc/btmon-hfp.rst
@@ -0,0 +1,476 @@
+.. This file is included by btmon-classic-audio.rst.
+
+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:
+
+- **Service Class** -- ``Handsfree (0x111e)`` for HF role,
+ ``Handsfree Audio Gateway (0x111f)`` for AG role
+- **RFCOMM Channel** -- The channel number under ``RFCOMM (0x0003)``
+ in the Protocol Descriptor List (e.g., channel 1)
+- **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=<features>`` / ``+BRSF:<features>`` -- 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``):
+
+.. list-table::
+ :header-rows: 1
+ :widths: 10 25 25
+
+ * - 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 status
+ - Reject call
+ * - 6
+ - Enhanced call control
+ - Enhanced call 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``):
+
+.. list-table::
+ :header-rows: 1
+ :widths: 10 20 30
+
+ * - 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:
+
+.. list-table::
+ :header-rows: 1
+ :widths: 10 20 30
+
+ * - 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:
+
+- **Link type** -- ``SCO (0x00)`` for legacy, ``eSCO (0x02)`` for
+ enhanced (used by mSBC and LC3-SWB)
+- **Air mode** -- ``CVSD (0x02)`` for narrow band,
+ ``Transparent (0x03)`` for mSBC or LC3-SWB
+- **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:
+
+- ``BR-SCO`` -- Legacy SCO connection
+- ``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)**:
+
+- HFP codec ID: 1
+- HCI codec: CVSD (0x02)
+- Voice setting: 0x0060 (Air Coding Format: CVSD)
+- Air mode: CVSD (0x02)
+- Link type: SCO or eSCO
+- Typical packet size: 48 bytes (HV3) or 60 bytes (EV3)
+
+**mSBC (wide band speech)**:
+
+- HFP codec ID: 2
+- HCI codec: mSBC (0x05)
+- Voice setting: 0x0063 (Air Coding Format: Transparent Data)
+- Air mode: Transparent (0x03)
+- Link type: eSCO
+- Typical packet size: 60 bytes (EV3, T2 settings)
+
+**LC3-SWB (super wide band)**:
+
+- HFP codec ID: 3
+- HCI codec: LC3 (0x06)
+- Voice setting: 0x0063 (Air Coding Format: Transparent Data)
+- Air mode: Transparent (0x03)
+- Link type: eSCO
+- 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:
+
+- ``Connection Rejected due to Limited Resources (0x0d)`` -- controller
+ cannot allocate bandwidth
+- ``SCO Offset Rejected (0x2b)`` -- timing parameters rejected
+- ``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
--
2.53.0
next prev parent reply other threads:[~2026-03-24 19:50 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-24 19:49 [PATCH BlueZ v2 1/9] doc/btmon: Split Advertising and Scanning into btmon-advertising.rst Luiz Augusto von Dentz
2026-03-24 19:49 ` [PATCH BlueZ v2 2/9] doc/btmon: Split LE Audio Protocol Flow into btmon-le-audio.rst Luiz Augusto von Dentz
2026-03-24 19:49 ` [PATCH BlueZ v2 3/9] doc/btmon: Split L2CAP Channel Tracking into btmon-l2cap.rst Luiz Augusto von Dentz
2026-03-24 19:49 ` [PATCH BlueZ v2 4/9] doc/btmon: Split SMP Pairing Flow into btmon-smp.rst Luiz Augusto von Dentz
2026-03-24 19:49 ` [PATCH BlueZ v2 5/9] doc/btmon: Split GATT Database Reconstruction into btmon-gatt.rst Luiz Augusto von Dentz
2026-03-24 19:49 ` [PATCH BlueZ v2 6/9] doc/btmon: Split Connection Tracking into btmon-connections.rst Luiz Augusto von Dentz
2026-03-24 19:49 ` [PATCH BlueZ v2 7/9] doc/btmon: Add HCI initialization sequence documentation Luiz Augusto von Dentz
2026-03-24 19:49 ` [PATCH BlueZ v2 8/9] doc/btmon: Add A2DP/AVDTP protocol flow documentation Luiz Augusto von Dentz
2026-03-24 19:49 ` Luiz Augusto von Dentz [this message]
2026-03-26 11:28 ` [PATCH BlueZ v2 9/9] doc/btmon: Add HFP " Frédéric Danis
2026-03-24 20:44 ` [BlueZ,v2,1/9] doc/btmon: Split Advertising and Scanning into btmon-advertising.rst bluez.test.bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260324194946.109349-9-luiz.dentz@gmail.com \
--to=luiz.dentz@gmail.com \
--cc=linux-bluetooth@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox