Bluetooth: hci_event: Fix LE link drop on remote features command status

When the local controller supports peripheral-initiated features
exchange, the LE Read Remote Features procedure also runs for incoming
connections, and it fails with Unsupported Remote Feature (0x1a) if the
central does not support that feature. hci_le_remote_feat_complete_evt()
and hci_le_read_all_remote_features_evt() handle this and let the
connection transition into connected state.

A controller can also return that error in the Command Status event
instead. An Intel controller does so for a central that does not
support peripheral-initiated features exchange, presumably because it
already has the features of the central. hci_cs_le_read_remote_features()
and hci_cs_le_read_all_remote_features() then confirm the connection as
failed while it is still in BT_CONFIG, and the hci_conn_drop() in
le_read_features_complete() disconnects it right away:

  > HCI Event: LE Meta Event (0x3e) plen 31
      LE Enhanced Connection Complete (0x0a)
        Status: Success (0x00)
        Role: Peripheral (0x01)
  < HCI Command: LE Read Remote Used Features (0x08|0x0016) plen 2
  > HCI Event: Command Status (0x0f) plen 4
      LE Read Remote Used Features (0x08|0x0016) ncmd 1
        Status: Unsupported Remote Feature / Unsupported LMP Feature (0x1a)
  < HCI Command: Disconnect (0x01|0x0006) plen 3
        Reason: Remote User Terminated Connection (0x13)

Data the central sends afterwards is reported as:

  Bluetooth: hci0: ACL packet for unknown connection handle 3585

Handle Unsupported Remote Feature in the command status the same way as
in the complete events.

Fixes: 0fe29fd1cd ("Bluetooth: Read LE remote features during connection establishment")
Fixes: a106e50be7 ("Bluetooth: HCI: Add support for LL Extended Feature Set")
Assisted-by: Claude:claude-opus-5.5
Signed-off-by: Kevin Dewald <kevin@simpleble.org>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
Kevin Dewald 2026-10-13 00:16:15 -07:00 committed by Luiz Augusto von Dentz
parent 5ba2dc0439
commit 91638f53ff

View File

@ -3015,8 +3015,25 @@ static void hci_cs_le_read_remote_features(struct hci_dev *hdev, u8 status)
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
if (conn && conn->state == BT_CONFIG)
if (conn && conn->state == BT_CONFIG) {
/* If the local controller supports peripheral-initiated
* features exchange, but the remote controller does not,
* then the controller may already return the error code
* 0x1a for unsupported remote feature in the command
* status.
*
* Handle it as hci_le_remote_feat_complete_evt() does and
* allow the connection to transition into connected state.
*/
if (!conn->out &&
status == HCI_ERROR_UNSUPPORTED_REMOTE_FEATURE &&
(hdev->le_features[0] & HCI_LE_PERIPHERAL_FEATURES)) {
conn->state = BT_CONNECTED;
status = 0x00;
}
hci_connect_cfm(conn, status);
}
hci_dev_unlock(hdev);
}
@ -4113,8 +4130,17 @@ static void hci_cs_le_read_all_remote_features(struct hci_dev *hdev, u8 status)
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
if (conn && conn->state == BT_CONFIG)
if (conn && conn->state == BT_CONFIG) {
/* See hci_cs_le_read_remote_features() */
if (!conn->out &&
status == HCI_ERROR_UNSUPPORTED_REMOTE_FEATURE &&
(hdev->le_features[0] & HCI_LE_PERIPHERAL_FEATURES)) {
conn->state = BT_CONNECTED;
status = 0x00;
}
hci_connect_cfm(conn, status);
}
hci_dev_unlock(hdev);
}