* [PATCH v3 0/2] Bluetooth: fix endless adv params retry after a cancelled connection
@ 2026-08-17 15:02 Valentin Kindschi
2026-08-17 15:02 ` [PATCH v3 1/2] Bluetooth: hci_conn: re-enable advertising only for peripheral role Valentin Kindschi
2026-08-17 15:02 ` [PATCH v3 2/2] Bluetooth: hci_event: keep HCI_LE_ADV set if the host cancelled Valentin Kindschi
0 siblings, 2 replies; 7+ messages in thread
From: Valentin Kindschi @ 2026-08-17 15:02 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, johan.hedberg, luiz.dentz, linux-kernel
A gateway device that advertises as a peripheral while also making
outgoing central connections gets stuck logging
Bluetooth: hci0: Opcode 0x2006 failed: -16
every 2 s indefinitely, starting seconds after an outgoing connection
attempt times out and is cancelled. Measured on one unit: 5326
occurrences over 3 hours, ending only when bluetoothd was restarted,
which resets the controller.
The controller is behaving per specification: LE Set Advertising
Parameters is Command Disallowed while advertising is enabled. The host
issues it anyway, and then cannot recover.
Sequence, from btmon (BCM43455, no LE Extended Advertising, so legacy
advertising and the software rotation loop are in use):
LE Create Connection Status Success
... 13.8 s, peer does not answer ...
LE Set Advertising Parameters 0x2006 Success \ done: resume
LE Set Advertising Enable 0x200a Success / HCI_LE_ADV set
LE Create Connection Cancel 0x200e Success
LE Connection Complete Unknown Conn Id
LE Set Advertising Parameters 0x2006 Command Disallowed [+63 ms]
LE Set Advertising Parameters 0x2006 Command Disallowed [+1.954 s]
LE Set Advertising Parameters 0x2006 Command Disallowed [+2.016 s]
... every ~2.016 s, for hours, and no 0x200a is ever sent again
Three connection attempts earlier in the same capture that *succeeded*
show the same 0x2006 + 0x200a pair and do not trigger this. Only an
attempt that times out and is cancelled does.
Why it never recovers: hci_enable_advertising_sync() returns as soon as
LE Set Advertising Parameters fails, before the LE Set Advertising Enable
that would set HCI_LE_ADV. hci_schedule_adv_instance_sync() re-arms
adv_instance_expire every HCI_DEFAULT_ADV_DURATION (2 s) and its
"already advertising" shortcut tests HCI_LE_ADV, which can no longer
become true. hci_disable_advertising_sync() cannot break the tie either -
it returns without sending anything while HCI_LE_ADV is clear, which is
exactly when the flag is wrong.
Patch 1 removes the redundant advertising enable that creates the
mismatch. Patch 2 stops HCI_LE_ADV being cleared for a connection
complete that reports no connection.
Patch 1 has been verified on the affected device. btmon counts:
before, 2.6 min capture: 78 LE Set Advertising Parameters sent,
78 Command Disallowed, 0 LE Set Advertising
Enable sent
after, 2.0 min capture: 3 LE Set Advertising Parameters sent,
0 Command Disallowed, 5 LE Set Advertising
Enable sent, all successful
The enable being sent and accepted again is the point: HCI_LE_ADV gets
set, so the rotation loop's shortcut works and nothing accumulates.
Patch 2 was deployed together with patch 1, so its effect is not
separately attributable on hardware; it is included because the same
mismatch is reachable through le_conn_complete_evt() independently, and
the current unconditional clear is wrong on its own terms.
Both apply to bluetooth-next. A 6.12.y backport needs a small context
adjustment in patch 2 (mainline has hci_store_wake_reason() in
le_conn_complete_evt()); I can send it if wanted.
A third, unrelated Command Disallowed on the same device - LE Set Random
Address refused on every active scan restart because advertising is only
paused for the address update when LL privacy is in use - is sent
separately, as it has a different cause and touches hci_sync.c only.
Tooling disclosure (Documentation/process/generated-content.rst):
the bug was found and the patches drafted with the help of an AI coding
assistant, over a debugging session on the affected hardware. The inputs
were btmon captures and kernel logs from the device; the assistant was
asked to identify what re-issues LE Set Advertising Parameters every 2 s
and to propose a fix. Its first two proposed mechanisms were wrong and
were discarded after being checked against the captures; a third proposed
change (making hci_disable_advertising_sync() always emit the disable)
was built and tested on the device, broke advertising registration
outright, and was dropped. The two patches here are what survived. All
code and reasoning were reviewed by the submitter, and the verification
numbers above were measured on hardware.
Changes in v3:
- Shortened both subject lines to fit the 80-character limit and removed
hard tabs from the changelog bodies (GitLint). No functional change.
- On the CI failures reported for v2, which I believe are unrelated:
The two mesh-tester "Send cancel" timeouts reproduce on an unpatched
kernel. Running bluez master's mesh-tester against stock 6.8.0 gives
Total: 10, Passed: 8, Failed: 2 with the same two cases failing - the
same result CI reports here, on a kernel that never carried these
patches.
mgmt-tester "Read Exp Feature - Success" also fails on that unpatched
kernel, though my local mgmt run is not a clean baseline (424/501 there
versus 496/501 on CI, which looks like tester/kernel version skew in my
environment). Independently, that test exercises the experimental
features read on index 0xffff with no controller involved, which none of
these patches touch.
Of the last 25 pull requests on bluez/bluetooth-next, these two suites
ran on 10 and failed on all 10, including changes that cannot plausibly
affect them (btintel version parsing, eir OOB read, devcoredump
teardown); the other 15 are driver-only series where they are skipped.
Happy to be told otherwise if these are in fact expected to pass.
Changes in v2:
- Rebased onto bluetooth-next. v1 was generated against 6.12.y and the
hci_event.c hunk did not apply to HEAD, because mainline calls
hci_store_wake_reason() in le_conn_complete_evt() and v1's context did
not include it. No functional change; the fix is identical.
Valentin Kindschi (2):
Bluetooth: hci_conn: re-enable advertising only for peripheral role
Bluetooth: hci_event: keep HCI_LE_ADV set if the host cancelled
net/bluetooth/hci_conn.c | 3 ++-
net/bluetooth/hci_event.c | 8 +++++---
2 files changed, 7 insertions(+), 4 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH v3 1/2] Bluetooth: hci_conn: re-enable advertising only for peripheral role
2026-08-17 15:02 [PATCH v3 0/2] Bluetooth: fix endless adv params retry after a cancelled connection Valentin Kindschi
@ 2026-08-17 15:02 ` Valentin Kindschi
2026-08-17 15:49 ` Bluetooth: fix endless adv params retry after a cancelled connection bluez.test.bot
2026-08-17 15:02 ` [PATCH v3 2/2] Bluetooth: hci_event: keep HCI_LE_ADV set if the host cancelled Valentin Kindschi
1 sibling, 1 reply; 7+ messages in thread
From: Valentin Kindschi @ 2026-08-17 15:02 UTC (permalink / raw)
To: linux-bluetooth
Cc: marcel, johan.hedberg, luiz.dentz, linux-kernel,
Valentin Kindschi, stable
hci_le_conn_failed() unconditionally calls hci_enable_advertising(),
although its own comment states advertising should be re-enabled only
when the failed attempt was made as a peripheral.
hci_le_conn_failed() is reached from hci_conn_failed() for every failed
LE connection, including outgoing central connections. For a central
attempt this enable is redundant: hci_le_create_conn_sync() already
restores advertising via hci_resume_advertising_sync() in its done:
block. Because hci_enable_advertising() only queues the work on
cmd_sync_work, it runs *after* that resume has already succeeded and
set HCI_LE_ADV.
The resulting HCI sequence, captured on a BCM43455 (no LE Extended
Advertising, so legacy advertising is used):
LE Create Connection Status Success
... 13.8 s, peer never answers ...
LE Set Advertising Parameters (0x2006) Success <- done: resume,
LE Set Advertising Enable (0x200a) Success HCI_LE_ADV set
LE Create Connection Cancel (0x200e) Success
LE Connection Complete Unknown Conn Id
LE Set Advertising Parameters (0x2006) Command Disallowed (0x0c)
The last command is the queued enable from hci_le_conn_failed() running
as a second hci_enable_advertising_sync() pass. It clears HCI_LE_ADV
(hci_sync.c, "Clear the HCI_LE_ADV bit temporarily"), then sends
LE Set Advertising Parameters while the controller is still advertising,
which the controller correctly rejects with Command Disallowed.
The disable-first call at the top of hci_enable_advertising_sync()
cannot prevent this: hci_disable_advertising_sync() returns early
without sending anything when HCI_LE_ADV is clear, so it is a no-op
exactly when the flag is wrong.
hci_enable_advertising_sync() then returns without sending LE Set
Advertising Enable, so HCI_LE_ADV is never set again. The legacy
software rotation loop re-arms hci_schedule_adv_instance_sync() every
HCI_DEFAULT_ADV_DURATION (2 s), and its "already advertising" shortcut
tests HCI_LE_ADV, which can no longer become true. The command is
therefore retried every 2 s indefinitely:
Bluetooth: hci0: Opcode 0x2006 failed: -16
Observed on a gateway as 5326 occurrences over 3 hours, ending only when
bluetoothd was restarted. Connection attempts that succeed do not call
hci_le_conn_failed() and never trigger this.
Add the role test the comment already describes. Both other
hci_enable_advertising() call sites reached from a failed/closed LE
connection (hci_cs_disconnect() and hci_disconn_complete_evt()) already
guard on conn->role == HCI_ROLE_SLAVE; this one was missed.
Reproducing needs legacy advertising (ext_adv_capable() false, so the
software rotation loop is used), simultaneous peripheral advertising and
outgoing central connects, and a central connect that times out rather
than failing fast.
The Fixes tag points at the commit that introduced the advertising
restart into this path for the directed-advertising (peripheral) case;
the role test that the later commit 0b1db38ca26b ("Bluetooth: Fix check
for direct advertising") added to the sibling paths was never applied
here.
Fixes: 3c857757ef6e ("Bluetooth: Add directed advertising support through connect()")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5 btmon
Signed-off-by: Valentin Kindschi <valentin.kindschi@fiveco.ch>
---
Changes in v2:
- Rebased onto bluetooth-next; no functional change.
net/bluetooth/hci_conn.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -1262,7 +1262,8 @@ static void hci_le_conn_failed(struct hci_conn *conn, u8 status)
/* Enable advertising in case this was a failed connection
* attempt as a peripheral.
*/
- hci_enable_advertising(hdev);
+ if (conn->role == HCI_ROLE_SLAVE)
+ hci_enable_advertising(hdev);
}
/* This function requires the caller holds hdev->lock */
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread* RE: Bluetooth: fix endless adv params retry after a cancelled connection
2026-08-17 15:02 ` [PATCH v3 1/2] Bluetooth: hci_conn: re-enable advertising only for peripheral role Valentin Kindschi
@ 2026-08-17 15:49 ` bluez.test.bot
0 siblings, 0 replies; 7+ messages in thread
From: bluez.test.bot @ 2026-08-17 15:49 UTC (permalink / raw)
To: linux-bluetooth, valentin.kindschi
[-- Attachment #1: Type: text/plain, Size: 2389 bytes --]
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1147269
---Test result---
Test Summary:
CheckPatch PASS 1.65 seconds
VerifyFixes PASS 0.13 seconds
VerifySignedoff PASS 0.14 seconds
GitLint PASS 0.65 seconds
SubjectPrefix PASS 0.25 seconds
BuildKernel PASS 27.32 seconds
CheckAllWarning PASS 29.88 seconds
CheckSparse PASS 28.87 seconds
BuildKernel32 PASS 30.57 seconds
CheckKernelLLVM SKIP 0.00 seconds
TestRunnerSetup PASS 499.72 seconds
TestRunner_l2cap-tester PASS 66.25 seconds
TestRunner_iso-tester PASS 80.03 seconds
TestRunner_bnep-tester PASS 19.40 seconds
TestRunner_mgmt-tester FAIL 222.42 seconds
TestRunner_rfcomm-tester PASS 25.40 seconds
TestRunner_sco-tester PASS 31.73 seconds
TestRunner_ioctl-tester PASS 26.30 seconds
TestRunner_mesh-tester FAIL 25.99 seconds
TestRunner_smp-tester PASS 23.88 seconds
TestRunner_userchan-tester PASS 20.74 seconds
TestRunner_6lowpan-tester PASS 23.54 seconds
IncrementalBuild PASS 34.39 seconds
Details
##############################
Test: CheckKernelLLVM - SKIP
Desc: Build kernel with LLVM + context analysis
Output:
Clang not found
##############################
Test: TestRunner_mgmt-tester - FAIL
Desc: Run mgmt-tester with test-runner
Output:
Total: 501, Passed: 496 (99.0%), Failed: 1, Not Run: 4
Failed Test Cases
Read Exp Feature - Success Failed 0.248 seconds
##############################
Test: TestRunner_mesh-tester - FAIL
Desc: Run mesh-tester with test-runner
Output:
Total: 10, Passed: 8 (80.0%), Failed: 2, Not Run: 0
Failed Test Cases
Mesh - Send cancel - 1 Timed out 2.347 seconds
Mesh - Send cancel - 2 Timed out 1.986 seconds
https://github.com/bluez/bluetooth-next/pull/600
---
Regards,
Linux Bluetooth
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 2/2] Bluetooth: hci_event: keep HCI_LE_ADV set if the host cancelled
2026-08-17 15:02 [PATCH v3 0/2] Bluetooth: fix endless adv params retry after a cancelled connection Valentin Kindschi
2026-08-17 15:02 ` [PATCH v3 1/2] Bluetooth: hci_conn: re-enable advertising only for peripheral role Valentin Kindschi
@ 2026-08-17 15:02 ` Valentin Kindschi
2026-08-17 16:11 ` Luiz Augusto von Dentz
1 sibling, 1 reply; 7+ messages in thread
From: Valentin Kindschi @ 2026-08-17 15:02 UTC (permalink / raw)
To: linux-bluetooth
Cc: marcel, johan.hedberg, luiz.dentz, linux-kernel,
Valentin Kindschi, stable
le_conn_complete_evt() clears HCI_LE_ADV before looking at the event
status, on the premise stated in its comment that all controllers stop
advertising when a connection is created.
That premise fails for Unknown Connection Identifier (0x02), which is
what an HCI_LE_Connection_Complete carries after the host issued
LE Create Connection Cancel: no connection was created and the
controller never stopped advertising. Clearing the flag there makes the
host believe advertising is off while the controller has it on.
Other non-zero statuses must keep clearing it. Advertising Timeout
(0x3c) in particular means the controller gave up advertising on its
own, so the flag has to go; leaving it set would make the
"already advertising" shortcut in hci_schedule_adv_instance_sync() skip
the HCI commands and silently stop advertising altogether.
With legacy advertising the disagreement is self-sustaining. On the next
software rotation tick hci_enable_advertising_sync() runs:
- hci_disable_advertising_sync() returns early without sending
anything, because HCI_LE_ADV is clear;
- LE Set Advertising Parameters is then sent while the controller is
still advertising, and is correctly rejected with Command Disallowed
(0x0c);
- the function returns before LE Set Advertising Enable, so nothing
re-sets HCI_LE_ADV.
hci_schedule_adv_instance_sync() re-arms adv_instance_expire every
HCI_DEFAULT_ADV_DURATION (2 s) and its "already advertising" shortcut
tests HCI_LE_ADV, which can no longer become true, so the command is
retried every 2 s indefinitely:
Bluetooth: hci0: Opcode 0x2006 failed: -16
Captured on a BCM43455 (no LE Extended Advertising) after a central
connection attempt timed out and was cancelled:
LE Set Advertising Parameters (0x2006) Success
LE Set Advertising Enable (0x200a) Success HCI_LE_ADV set
LE Create Connection Cancel (0x200e) Success
LE Connection Complete Unknown Conn Id <- flag cleared
LE Set Advertising Parameters (0x2006) Command Disallowed [+2.033 s]
LE Set Advertising Parameters (0x2006) Command Disallowed [+2.016 s]
...
Keep the flag only for the host-cancelled case.
Fixes: fbd96c151cdc ("Bluetooth: Fix clearing HCI_LE_ADV for LE connections")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5 btmon
Signed-off-by: Valentin Kindschi <valentin.kindschi@fiveco.ch>
---
Changes in v2:
- Rebased onto bluetooth-next; no functional change.
v1's hci_event.c context lacked the hci_store_wake_reason() call
present in mainline, so the hunk did not apply.
net/bluetooth/hci_event.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -5720,10 +5720,12 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
hci_dev_lock(hdev);
hci_store_wake_reason(hdev, bdaddr, bdaddr_type);
- /* All controllers implicitly stop advertising in the event of a
- * connection, so ensure that the state bit is cleared.
+ /* Advertising stops when a connection is created, and when the
+ * controller gives up advertising on its own. It keeps advertising
+ * when the host cancelled an outgoing connection.
*/
- hci_dev_clear_flag(hdev, HCI_LE_ADV);
+ if (status != HCI_ERROR_UNKNOWN_CONN_ID)
+ hci_dev_clear_flag(hdev, HCI_LE_ADV);
/* Check for existing connection:
*
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH v3 2/2] Bluetooth: hci_event: keep HCI_LE_ADV set if the host cancelled
2026-08-17 15:02 ` [PATCH v3 2/2] Bluetooth: hci_event: keep HCI_LE_ADV set if the host cancelled Valentin Kindschi
@ 2026-08-17 16:11 ` Luiz Augusto von Dentz
2026-08-17 16:31 ` Valentin Kindschi
0 siblings, 1 reply; 7+ messages in thread
From: Luiz Augusto von Dentz @ 2026-08-17 16:11 UTC (permalink / raw)
To: Valentin Kindschi
Cc: linux-bluetooth, marcel, johan.hedberg, linux-kernel, stable
Hi Valentin,
On Mon, Aug 17, 2026 at 11:03 AM Valentin Kindschi
<valentin.kindschi@fiveco.ch> wrote:
>
> le_conn_complete_evt() clears HCI_LE_ADV before looking at the event
> status, on the premise stated in its comment that all controllers stop
> advertising when a connection is created.
>
> That premise fails for Unknown Connection Identifier (0x02), which is
> what an HCI_LE_Connection_Complete carries after the host issued
> LE Create Connection Cancel: no connection was created and the
> controller never stopped advertising. Clearing the flag there makes the
> host believe advertising is off while the controller has it on.
>
> Other non-zero statuses must keep clearing it. Advertising Timeout
> (0x3c) in particular means the controller gave up advertising on its
> own, so the flag has to go; leaving it set would make the
> "already advertising" shortcut in hci_schedule_adv_instance_sync() skip
> the HCI commands and silently stop advertising altogether.
>
> With legacy advertising the disagreement is self-sustaining. On the next
> software rotation tick hci_enable_advertising_sync() runs:
>
> - hci_disable_advertising_sync() returns early without sending
> anything, because HCI_LE_ADV is clear;
> - LE Set Advertising Parameters is then sent while the controller is
> still advertising, and is correctly rejected with Command Disallowed
> (0x0c);
> - the function returns before LE Set Advertising Enable, so nothing
> re-sets HCI_LE_ADV.
>
> hci_schedule_adv_instance_sync() re-arms adv_instance_expire every
> HCI_DEFAULT_ADV_DURATION (2 s) and its "already advertising" shortcut
> tests HCI_LE_ADV, which can no longer become true, so the command is
> retried every 2 s indefinitely:
>
> Bluetooth: hci0: Opcode 0x2006 failed: -16
>
> Captured on a BCM43455 (no LE Extended Advertising) after a central
> connection attempt timed out and was cancelled:
>
> LE Set Advertising Parameters (0x2006) Success
> LE Set Advertising Enable (0x200a) Success HCI_LE_ADV set
> LE Create Connection Cancel (0x200e) Success
> LE Connection Complete Unknown Conn Id <- flag cleared
> LE Set Advertising Parameters (0x2006) Command Disallowed [+2.033 s]
> LE Set Advertising Parameters (0x2006) Command Disallowed [+2.016 s]
> ...
>
> Keep the flag only for the host-cancelled case.
>
> Fixes: fbd96c151cdc ("Bluetooth: Fix clearing HCI_LE_ADV for LE connections")
> Cc: stable@vger.kernel.org
> Assisted-by: Claude:claude-opus-5 btmon
> Signed-off-by: Valentin Kindschi <valentin.kindschi@fiveco.ch>
> ---
> Changes in v2:
> - Rebased onto bluetooth-next; no functional change.
> v1's hci_event.c context lacked the hci_store_wake_reason() call
> present in mainline, so the hunk did not apply.
>
> net/bluetooth/hci_event.c | 8 +++++---
> 1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -5720,10 +5720,12 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
> hci_dev_lock(hdev);
> hci_store_wake_reason(hdev, bdaddr, bdaddr_type);
>
> - /* All controllers implicitly stop advertising in the event of a
> - * connection, so ensure that the state bit is cleared.
> + /* Advertising stops when a connection is created, and when the
> + * controller gives up advertising on its own. It keeps advertising
> + * when the host cancelled an outgoing connection.
> */
> - hci_dev_clear_flag(hdev, HCI_LE_ADV);
> + if (status != HCI_ERROR_UNKNOWN_CONN_ID)
> + hci_dev_clear_flag(hdev, HCI_LE_ADV);
Hmm, I wonder if this is not valid for all status != 0 though, for
example if the connection timeout we probably shouldn't clear it
either.
> /* Check for existing connection:
> *
> --
> 2.34.1
--
Luiz Augusto von Dentz
^ permalink raw reply [flat|nested] 7+ messages in thread* RE: [PATCH v3 2/2] Bluetooth: hci_event: keep HCI_LE_ADV set if the host cancelled
2026-08-17 16:11 ` Luiz Augusto von Dentz
@ 2026-08-17 16:31 ` Valentin Kindschi
2026-08-17 16:42 ` Luiz Augusto von Dentz
0 siblings, 1 reply; 7+ messages in thread
From: Valentin Kindschi @ 2026-08-17 16:31 UTC (permalink / raw)
To: Luiz Augusto von Dentz
Cc: linux-bluetooth@vger.kernel.org, marcel@holtmann.org,
johan.hedberg@gmail.com, linux-kernel@vger.kernel.org,
stable@vger.kernel.org
Oh, you're right. The test is too narrow - a connection timeout on the central path should not clear it either.
The clear exists because advertising stops when a peripheral connection is created, so the role seems more relevant than the status - but ev->role is not dependable on a failed event, and the conn lookup that would give a trustworthy role happens after this point.
We could move the clear below the lookup and gate it on conn->role, or simply !status ?
Valentin Kindschi
-----Message d'origine-----
De : Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Envoyé : lundi, 17 août 2026 18:12
À : Valentin Kindschi <valentin.kindschi@fiveco.ch>
Cc : linux-bluetooth@vger.kernel.org; marcel@holtmann.org; johan.hedberg@gmail.com; linux-kernel@vger.kernel.org; stable@vger.kernel.org
Objet : Re: [PATCH v3 2/2] Bluetooth: hci_event: keep HCI_LE_ADV set if the host cancelled
Hi Valentin,
On Mon, Aug 17, 2026 at 11:03 AM Valentin Kindschi <valentin.kindschi@fiveco.ch> wrote:
>
> le_conn_complete_evt() clears HCI_LE_ADV before looking at the event
> status, on the premise stated in its comment that all controllers stop
> advertising when a connection is created.
>
> That premise fails for Unknown Connection Identifier (0x02), which is
> what an HCI_LE_Connection_Complete carries after the host issued LE
> Create Connection Cancel: no connection was created and the controller
> never stopped advertising. Clearing the flag there makes the host
> believe advertising is off while the controller has it on.
>
> Other non-zero statuses must keep clearing it. Advertising Timeout
> (0x3c) in particular means the controller gave up advertising on its
> own, so the flag has to go; leaving it set would make the "already
> advertising" shortcut in hci_schedule_adv_instance_sync() skip the HCI
> commands and silently stop advertising altogether.
>
> With legacy advertising the disagreement is self-sustaining. On the
> next software rotation tick hci_enable_advertising_sync() runs:
>
> - hci_disable_advertising_sync() returns early without sending
> anything, because HCI_LE_ADV is clear;
> - LE Set Advertising Parameters is then sent while the controller is
> still advertising, and is correctly rejected with Command Disallowed
> (0x0c);
> - the function returns before LE Set Advertising Enable, so nothing
> re-sets HCI_LE_ADV.
>
> hci_schedule_adv_instance_sync() re-arms adv_instance_expire every
> HCI_DEFAULT_ADV_DURATION (2 s) and its "already advertising" shortcut
> tests HCI_LE_ADV, which can no longer become true, so the command is
> retried every 2 s indefinitely:
>
> Bluetooth: hci0: Opcode 0x2006 failed: -16
>
> Captured on a BCM43455 (no LE Extended Advertising) after a central
> connection attempt timed out and was cancelled:
>
> LE Set Advertising Parameters (0x2006) Success
> LE Set Advertising Enable (0x200a) Success HCI_LE_ADV set
> LE Create Connection Cancel (0x200e) Success
> LE Connection Complete Unknown Conn Id <- flag cleared
> LE Set Advertising Parameters (0x2006) Command Disallowed [+2.033 s]
> LE Set Advertising Parameters (0x2006) Command Disallowed [+2.016 s]
> ...
>
> Keep the flag only for the host-cancelled case.
>
> Fixes: fbd96c151cdc ("Bluetooth: Fix clearing HCI_LE_ADV for LE
> connections")
> Cc: stable@vger.kernel.org
> Assisted-by: Claude:claude-opus-5 btmon
> Signed-off-by: Valentin Kindschi <valentin.kindschi@fiveco.ch>
> ---
> Changes in v2:
> - Rebased onto bluetooth-next; no functional change.
> v1's hci_event.c context lacked the hci_store_wake_reason() call
> present in mainline, so the hunk did not apply.
>
> net/bluetooth/hci_event.c | 8 +++++---
> 1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -5720,10 +5720,12 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
> hci_dev_lock(hdev);
> hci_store_wake_reason(hdev, bdaddr, bdaddr_type);
>
> - /* All controllers implicitly stop advertising in the event of a
> - * connection, so ensure that the state bit is cleared.
> + /* Advertising stops when a connection is created, and when the
> + * controller gives up advertising on its own. It keeps advertising
> + * when the host cancelled an outgoing connection.
> */
> - hci_dev_clear_flag(hdev, HCI_LE_ADV);
> + if (status != HCI_ERROR_UNKNOWN_CONN_ID)
> + hci_dev_clear_flag(hdev, HCI_LE_ADV);
Hmm, I wonder if this is not valid for all status != 0 though, for example if the connection timeout we probably shouldn't clear it either.
> /* Check for existing connection:
> *
> --
> 2.34.1
--
Luiz Augusto von Dentz
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH v3 2/2] Bluetooth: hci_event: keep HCI_LE_ADV set if the host cancelled
2026-08-17 16:31 ` Valentin Kindschi
@ 2026-08-17 16:42 ` Luiz Augusto von Dentz
0 siblings, 0 replies; 7+ messages in thread
From: Luiz Augusto von Dentz @ 2026-08-17 16:42 UTC (permalink / raw)
To: Valentin Kindschi
Cc: linux-bluetooth@vger.kernel.org, marcel@holtmann.org,
johan.hedberg@gmail.com, linux-kernel@vger.kernel.org,
stable@vger.kernel.org
Hi Valentin,
On Mon, Aug 17, 2026 at 12:31 PM Valentin Kindschi
<valentin.kindschi@fiveco.ch> wrote:
>
> Oh, you're right. The test is too narrow - a connection timeout on the central path should not clear it either.
>
> The clear exists because advertising stops when a peripheral connection is created, so the role seems more relevant than the status - but ev->role is not dependable on a failed event, and the conn lookup that would give a trustworthy role happens after this point.
>
> We could move the clear below the lookup and gate it on conn->role, or simply !status ?
Try with !status, we need to confirm that doesn't break any CI test
either. That said, it does look like it would clear it also for
extended advertising where there could be multiple instances
advertising, so I'm not sure if it's correct to assume that if one
instance connects all others shall also be considered connected.
> Valentin Kindschi
>
> -----Message d'origine-----
> De : Luiz Augusto von Dentz <luiz.dentz@gmail.com>
> Envoyé : lundi, 17 août 2026 18:12
> À : Valentin Kindschi <valentin.kindschi@fiveco.ch>
> Cc : linux-bluetooth@vger.kernel.org; marcel@holtmann.org; johan.hedberg@gmail.com; linux-kernel@vger.kernel.org; stable@vger.kernel.org
> Objet : Re: [PATCH v3 2/2] Bluetooth: hci_event: keep HCI_LE_ADV set if the host cancelled
>
> Hi Valentin,
>
> On Mon, Aug 17, 2026 at 11:03 AM Valentin Kindschi <valentin.kindschi@fiveco.ch> wrote:
> >
> > le_conn_complete_evt() clears HCI_LE_ADV before looking at the event
> > status, on the premise stated in its comment that all controllers stop
> > advertising when a connection is created.
> >
> > That premise fails for Unknown Connection Identifier (0x02), which is
> > what an HCI_LE_Connection_Complete carries after the host issued LE
> > Create Connection Cancel: no connection was created and the controller
> > never stopped advertising. Clearing the flag there makes the host
> > believe advertising is off while the controller has it on.
> >
> > Other non-zero statuses must keep clearing it. Advertising Timeout
> > (0x3c) in particular means the controller gave up advertising on its
> > own, so the flag has to go; leaving it set would make the "already
> > advertising" shortcut in hci_schedule_adv_instance_sync() skip the HCI
> > commands and silently stop advertising altogether.
> >
> > With legacy advertising the disagreement is self-sustaining. On the
> > next software rotation tick hci_enable_advertising_sync() runs:
> >
> > - hci_disable_advertising_sync() returns early without sending
> > anything, because HCI_LE_ADV is clear;
> > - LE Set Advertising Parameters is then sent while the controller is
> > still advertising, and is correctly rejected with Command Disallowed
> > (0x0c);
> > - the function returns before LE Set Advertising Enable, so nothing
> > re-sets HCI_LE_ADV.
> >
> > hci_schedule_adv_instance_sync() re-arms adv_instance_expire every
> > HCI_DEFAULT_ADV_DURATION (2 s) and its "already advertising" shortcut
> > tests HCI_LE_ADV, which can no longer become true, so the command is
> > retried every 2 s indefinitely:
> >
> > Bluetooth: hci0: Opcode 0x2006 failed: -16
> >
> > Captured on a BCM43455 (no LE Extended Advertising) after a central
> > connection attempt timed out and was cancelled:
> >
> > LE Set Advertising Parameters (0x2006) Success
> > LE Set Advertising Enable (0x200a) Success HCI_LE_ADV set
> > LE Create Connection Cancel (0x200e) Success
> > LE Connection Complete Unknown Conn Id <- flag cleared
> > LE Set Advertising Parameters (0x2006) Command Disallowed [+2.033 s]
> > LE Set Advertising Parameters (0x2006) Command Disallowed [+2.016 s]
> > ...
> >
> > Keep the flag only for the host-cancelled case.
> >
> > Fixes: fbd96c151cdc ("Bluetooth: Fix clearing HCI_LE_ADV for LE
> > connections")
> > Cc: stable@vger.kernel.org
> > Assisted-by: Claude:claude-opus-5 btmon
> > Signed-off-by: Valentin Kindschi <valentin.kindschi@fiveco.ch>
> > ---
> > Changes in v2:
> > - Rebased onto bluetooth-next; no functional change.
> > v1's hci_event.c context lacked the hci_store_wake_reason() call
> > present in mainline, so the hunk did not apply.
> >
> > net/bluetooth/hci_event.c | 8 +++++---
> > 1 file changed, 5 insertions(+), 3 deletions(-)
> >
> > diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> > --- a/net/bluetooth/hci_event.c
> > +++ b/net/bluetooth/hci_event.c
> > @@ -5720,10 +5720,12 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
> > hci_dev_lock(hdev);
> > hci_store_wake_reason(hdev, bdaddr, bdaddr_type);
> >
> > - /* All controllers implicitly stop advertising in the event of a
> > - * connection, so ensure that the state bit is cleared.
> > + /* Advertising stops when a connection is created, and when the
> > + * controller gives up advertising on its own. It keeps advertising
> > + * when the host cancelled an outgoing connection.
> > */
> > - hci_dev_clear_flag(hdev, HCI_LE_ADV);
> > + if (status != HCI_ERROR_UNKNOWN_CONN_ID)
> > + hci_dev_clear_flag(hdev, HCI_LE_ADV);
>
> Hmm, I wonder if this is not valid for all status != 0 though, for example if the connection timeout we probably shouldn't clear it either.
>
> > /* Check for existing connection:
> > *
> > --
> > 2.34.1
>
>
>
> --
> Luiz Augusto von Dentz
--
Luiz Augusto von Dentz
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-08-17 16:42 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-17 15:02 [PATCH v3 0/2] Bluetooth: fix endless adv params retry after a cancelled connection Valentin Kindschi
2026-08-17 15:02 ` [PATCH v3 1/2] Bluetooth: hci_conn: re-enable advertising only for peripheral role Valentin Kindschi
2026-08-17 15:49 ` Bluetooth: fix endless adv params retry after a cancelled connection bluez.test.bot
2026-08-17 15:02 ` [PATCH v3 2/2] Bluetooth: hci_event: keep HCI_LE_ADV set if the host cancelled Valentin Kindschi
2026-08-17 16:11 ` Luiz Augusto von Dentz
2026-08-17 16:31 ` Valentin Kindschi
2026-08-17 16:42 ` Luiz Augusto von Dentz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox