* [PATCH v3] Bluetooth: MGMT: Fix discovery stuck after a failed Stop Discovery
@ 2026-10-27 21:00 Kevin Dewald
0 siblings, 0 replies; only message in thread
From: Kevin Dewald @ 2026-10-27 21:00 UTC (permalink / raw)
To: linux-bluetooth
Cc: Marcel Holtmann, Luiz Augusto von Dentz, linux-kernel, Kevin Dewald
Stop Discovery moves the discovery to DISCOVERY_STOPPING, and
stop_discovery_complete() only moves it on to DISCOVERY_STOPPED when
stopping succeeded. When it fails, for example because LE Set Scan
Enable times out, nothing moves the discovery out of
DISCOVERY_STOPPING: Stop Discovery is rejected, as the discovery is not
active anymore, and the LE scan timeout was cancelled before the scan
was disabled. Until the controller is powered off, every Start
Discovery then fails with Busy, and hci_update_passive_scan_sync()
skips background scanning, so devices set to auto-connect are not
connected anymore.
Move the discovery back to DISCOVERY_FINDING when stopping it failed
while the inquiry or the LE scan is still running, so that it can be
stopped again, and only cancel the LE scan timeout once the scan is
disabled, so that the discovery still ends on its own. A timed out LE
Set Scan Enable can still complete afterwards, which cancels the
timeout as well, so also stop the discovery when its scan is disabled
while the timeout is pending.
Fixes: 0e05bba6f6f8 ("Bluetooth: Update stop_discovery to use HCI request")
Assisted-by: Claude:claude-opus-5.5
Signed-off-by: Kevin Dewald <kevin@simpleble.org>
---
Changes in v3:
- Go back to DISCOVERY_FINDING instead of DISCOVERY_STOPPED when
stopping failed while the inquiry or the LE scan is still running.
- Keep the LE scan timeout until the scan is disabled, so that the
discovery still ends on its own.
- Stop the discovery when a timed out LE Set Scan Enable completes
afterwards, as that cancels the timeout too.
- v2: https://lore.kernel.org/linux-bluetooth/20261027172730.86568-1-kevin@simpleble.org/
I did not find an error status that shows by itself that the scan
already stopped: the kernel only disables the scan while HCI_LE_SCAN is
set, and hci_cc_inquiry_cancel() already turns Command Disallowed after
the inquiry completed into success. So v3 checks HCI_INQUIRY and
HCI_LE_SCAN instead, which are only cleared once the controller
confirms. Going back to DISCOVERY_FINDING sends Discovering (enabled)
again.
Reproduced in test-runner with a new mgmt-tester case, "Stop Discovery -
Scan Disable Failed 1", in which the emulator answers the first LE Set
Scan Enable (disable) with Unspecified Error: without this patch a
second Stop Discovery is rejected and Start Discovery fails with Busy
(3 of 3 runs); with it the second Stop Discovery succeeds, and so does
Start Discovery (3 of 3). Without the second Stop Discovery, the
discovery now ends at the LE scan timeout. Freezing the emulated
controller while bluetoothd stops discovering makes LE Set Scan Enable
time out and then complete just after: the discovery is stopped when it
completes, and Start Discovery succeeds (3 of 3). The other kernel
testers pass as before. Only tested with the emulator, not with real
controllers. I can send the mgmt-tester case to BlueZ if you want it.
hci_pause_discovery_sync() has the same pattern on suspend, which I have
not reproduced.
net/bluetooth/hci_event.c | 12 +++++++++++-
net/bluetooth/hci_sync.c | 8 ++++++--
net/bluetooth/mgmt.c | 9 ++++++++-
3 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index d05934fef4..80679f1881 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1819,6 +1819,8 @@ static void store_pending_adv_report(struct hci_dev *hdev, bdaddr_t *bdaddr,
static void le_set_scan_enable_complete(struct hci_dev *hdev, u8 enable)
{
+ bool timeout_pending;
+
hci_dev_lock(hdev);
switch (enable) {
@@ -1848,10 +1850,18 @@ static void le_set_scan_enable_complete(struct hci_dev *hdev, u8 enable)
/* Cancel this timer so that we don't try to disable scanning
* when it's already disabled.
*/
- cancel_delayed_work(&hdev->le_scan_disable);
+ timeout_pending = cancel_delayed_work(&hdev->le_scan_disable);
hci_dev_clear_flag(hdev, HCI_LE_SCAN);
+ /* The scan of a discovery was disabled before its timeout,
+ * for example by a Stop Discovery that timed out and still
+ * completed, so nothing else would end the discovery.
+ */
+ if (timeout_pending &&
+ hdev->discovery.state == DISCOVERY_FINDING)
+ hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+
if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
hci_test_quirk(hdev, HCI_QUIRK_SIMULTANEOUS_DISCOVERY) &&
!test_bit(HCI_INQUIRY, &hdev->flags) &&
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index 9d71ce96bd..6465198f13 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -5913,11 +5913,15 @@ int hci_stop_discovery_sync(struct hci_dev *hdev)
}
if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
- cancel_delayed_work(&hdev->le_scan_disable);
-
err = hci_scan_disable_sync(hdev);
if (err)
return err;
+
+ /* Only cancel the LE scan timeout once the scan is
+ * disabled, so that the discovery still ends if
+ * stopping it failed.
+ */
+ cancel_delayed_work(&hdev->le_scan_disable);
}
} else {
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 3cb4f9ece8..2bdc355786 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -6322,7 +6322,14 @@ static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err)
cmd->param, 1);
mgmt_pending_free(cmd);
- if (!err)
+ /* Go back to DISCOVERY_FINDING when stopping failed while the inquiry
+ * or the LE scan is still running, so that the discovery can be
+ * stopped again.
+ */
+ if (err && (test_bit(HCI_INQUIRY, &hdev->flags) ||
+ hci_dev_test_flag(hdev, HCI_LE_SCAN)))
+ hci_discovery_set_state(hdev, DISCOVERY_FINDING);
+ else
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
}
base-commit: 47d4d9f67e92d56ef3965f2727f9c98a5a611368
--
2.53.0
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-27 21:01 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-27 21:00 [PATCH v3] Bluetooth: MGMT: Fix discovery stuck after a failed Stop Discovery Kevin Dewald
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®