Linux bluetooth development
 help / color / mirror / Atom feed
* [RFC PATCH] Bluetooth: fix Set Public Address on controller in HCI_AUTO_OFF grace period
@ 2026-04-30  4:55 Dan Klishch
  2026-04-30  7:49 ` [RFC] " bluez.test.bot
  2026-05-04 18:27 ` [RFC PATCH] " Luiz Augusto von Dentz
  0 siblings, 2 replies; 4+ messages in thread
From: Dan Klishch @ 2026-04-30  4:55 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz; +Cc: linux-bluetooth, linux-kernel

When mgmt's Set Public Address command (and Set External Configuration)
stages a configuration change, set_public_address() sets HCI_CONFIG and
HCI_AUTO_OFF on the device and queues hci_power_on. The intent is for
the queued power_on to run hci_dev_init_sync() -- which detects
HCI_CONFIG and calls hdev->set_bdaddr() to program the new address into
the firmware -- and then re-emit Index Added with the controller back in
the boot-init grace period (HCI_UP=1, HCI_AUTO_OFF=1) so userspace can
re-push pending config commands and drive a fresh Set Powered 1 cycle.

The bug bites when the command is issued while the controller is in
that same grace period itself -- the normal post-boot state, before
bluetoothd has claimed the controller via Set Powered 1. In that state
HCI_UP=1 and HCI_AUTO_OFF=1, so hdev_is_powered() is false (the command
is accepted) but hci_power_on()'s "already up" early-return condition
HCI_UP && HCI_MGMT && HCI_AUTO_OFF is true. The early-return path runs
hci_powered_update_sync() -- which is the wrong thing for this case:
neither hci_dev_init_sync() nor mgmt_index_added() runs. The result:

  - hdev->public_addr is recorded but never reaches the firmware via
    hdev->set_bdaddr(),
  - userspace sees Index Removed (from set_public_address) but no
    Index Added, leaving the controller invisible to mgmt clients;
    it is not in the configured, unconfigured or extended index list
    yet remains registered in the kernel.

The other two starting states are fine: HCI_UP=0 falls through to the
full hci_dev_do_open() path (correct); HCI_UP=1 with HCI_AUTO_OFF=0
makes hdev_is_powered() true, so set_public_address() rejects with
MGMT_STATUS_REJECTED before queueing power_on at all.

Fix: at the top of hci_power_on(), if HCI_CONFIG is pending and we are
in the affected grace-period state (HCI_UP, HCI_MGMT, !HCI_RFKILLED),
close the device first. The early-return condition then fails and we
fall through to hci_dev_do_open() -> hci_dev_init_sync(), which honors
HCI_CONFIG by invoking hdev->set_bdaddr(); the post-open block then
re-emits Index Added via the existing HCI_CONFIG branch.

hci_dev_close_sync() clears HCI_AUTO_OFF as a side effect of going
through the regular power-down path, but set_public_address() had set
it deliberately so the post-reopen state matches the boot-init grace
period that mgmt clients expect ("treat as new one" per the protocol
contract). Several mgmt commands -- Set Privacy, Set Wideband Speech,
Set LE, Set BR/EDR, etc. -- gate on !hdev_is_powered(), and bluetoothd
expects to push them during this window before issuing Set Powered 1
itself. Restore HCI_AUTO_OFF after the close so hdev_is_powered() ==
false again.

This matches the documented behavior for Set Public Address on a
fully-configured controller ("Once the address has been successfully
changed an Index Added event will be sent.")

Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Dan Klishch <danilklishch@gmail.com>
---
 net/bluetooth/hci_core.c | 8 ++++++++
 1 file changed, 8 insertions(+)

--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -948,6 +948,14 @@ static void hci_power_on(struct work_struct *work)

 	BT_DBG("%s", hdev->name);

+	if (hci_dev_test_flag(hdev, HCI_CONFIG) &&
+	    hci_dev_test_flag(hdev, HCI_MGMT) &&
+	    !hci_dev_test_flag(hdev, HCI_RFKILLED) &&
+	    test_bit(HCI_UP, &hdev->flags)) {
+		hci_dev_do_close(hdev);
+		hci_dev_set_flag(hdev, HCI_AUTO_OFF);
+	}
+
 	if (test_bit(HCI_UP, &hdev->flags) &&
 	    hci_dev_test_flag(hdev, HCI_MGMT) &&
 	    hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF)) {

---

Claude was able to fully convince me that the patch and the explanation
are correct. Moreover, this indeed fixed a problem I had with a custom
patched bluetoothd that happened to override public-addr in the 2
second post-boot window. However, both the patch and commit description
are fully AI-generated.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* RE: [RFC] Bluetooth: fix Set Public Address on controller in HCI_AUTO_OFF grace period
  2026-04-30  4:55 [RFC PATCH] Bluetooth: fix Set Public Address on controller in HCI_AUTO_OFF grace period Dan Klishch
@ 2026-04-30  7:49 ` bluez.test.bot
  2026-05-04 18:27 ` [RFC PATCH] " Luiz Augusto von Dentz
  1 sibling, 0 replies; 4+ messages in thread
From: bluez.test.bot @ 2026-04-30  7:49 UTC (permalink / raw)
  To: linux-bluetooth, danilklishch

[-- Attachment #1: Type: text/plain, Size: 5075 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=1087873

---Test result---

Test Summary:
CheckPatch                    FAIL      0.63 seconds
GitLint                       FAIL      0.26 seconds
SubjectPrefix                 PASS      0.09 seconds
BuildKernel                   PASS      25.03 seconds
CheckAllWarning               PASS      27.56 seconds
CheckSparse                   PASS      26.39 seconds
BuildKernel32                 PASS      24.04 seconds
TestRunnerSetup               PASS      523.74 seconds
TestRunner_l2cap-tester       PASS      27.31 seconds
TestRunner_iso-tester         PASS      34.75 seconds
TestRunner_bnep-tester        PASS      6.36 seconds
TestRunner_mgmt-tester        FAIL      109.68 seconds
TestRunner_rfcomm-tester      PASS      9.47 seconds
TestRunner_sco-tester         PASS      14.20 seconds
TestRunner_ioctl-tester       PASS      9.96 seconds
TestRunner_mesh-tester        FAIL      11.22 seconds
TestRunner_smp-tester         PASS      8.64 seconds
TestRunner_userchan-tester    PASS      6.74 seconds
TestRunner_6lowpan-tester     FAIL      8.59 seconds
IncrementalBuild              PASS      23.68 seconds

Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[RFC] Bluetooth: fix Set Public Address on controller in HCI_AUTO_OFF grace period
WARNING: Non-standard signature: Assisted-by:
#148: 
Assisted-by: Claude:claude-opus-4-7

ERROR: Unrecognized email address: 'Claude:claude-opus-4-7'
#148: 
Assisted-by: Claude:claude-opus-4-7

total: 1 errors, 1 warnings, 0 checks, 14 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/patch/14548392.patch has style problems, please review.

NOTE: Ignored message types: UNKNOWN_COMMIT_ID

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.


##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[RFC] Bluetooth: fix Set Public Address on controller in HCI_AUTO_OFF grace period

WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
1: T1 Title exceeds max length (82>80): "[RFC] Bluetooth: fix Set Public Address on controller in HCI_AUTO_OFF grace period"
##############################
Test: TestRunner_mgmt-tester - FAIL
Desc: Run mgmt-tester with test-runner
Output:
Total: 494, Passed: 489 (99.0%), Failed: 1, Not Run: 4

Failed Test Cases
Read Exp Feature - Success                           Failed       0.096 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    1.834 seconds
Mesh - Send cancel - 2                               Timed out    1.995 seconds
##############################
Test: TestRunner_6lowpan-tester - FAIL
Desc: Run 6lowpan-tester with test-runner
Output:
WARNING: possible circular locking dependency detected
7.0.0-rc7-gb8928b8010b2 #1 Not tainted
------------------------------------------------------
kworker/0:1/11 is trying to acquire lock:
ffff888002735940 ((wq_completion)hci0#2){+.+.}-{0:0}, at: touch_wq_lockdep_map+0x75/0x180

but task is already holding lock:
ffffffff9c44faa0 (rtnl_mutex){+.+.}-{4:4}, at: lowpan_unregister_netdev+0xd/0x30

which lock already depends on the new lock.


the existing dependency chain (in reverse order) is:

-> #4 (rtnl_mutex){+.+.}-{4:4}:
       lock_acquire+0xf7/0x2c0
       __mutex_lock+0x16b/0x1fc0
       lowpan_register_netdev+0x11/0x30
       chan_ready_cb+0x836/0xd00
       l2cap_recv_frame+0x61bb/0x88e0
       l2cap_recv_acldata+0x790/0xdf0
       hci_rx_work+0x500/0xd00
       process_scheduled_works+0xba7/0x1a90
       worker_thread+0x514/0xbb0
       kthread+0x368/0x490
       ret_from_fork+0x498/0x7e0
       ret_from_fork_asm+0x19/0x30

-> #3 (&chan->lock#3/1){+.+.}-{4:4}:
       lock_acquire+0xf7/0x2c0
       __mutex_lock+0x16b/0x1fc0
       l2cap_chan_connect+0x74e/0x1980
       lowpan_control_write+0x523/0x660
       full_proxy_write+0x10b/0x190
       vfs_write+0x1c0/0xf60
       ksys_write+0xf1/0x1d0
       do_syscall_64+0xa0/0x570
       entry_SYSCALL_64_after_hwframe+0x74/0x7c

-> #2 (&conn->lock){+.+.}-{4:4}:
...
Total: 8, Passed: 8 (100.0%), Failed: 0, Not Run: 0


https://github.com/bluez/bluetooth-next/pull/135

---
Regards,
Linux Bluetooth


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [RFC PATCH] Bluetooth: fix Set Public Address on controller in HCI_AUTO_OFF grace period
  2026-04-30  4:55 [RFC PATCH] Bluetooth: fix Set Public Address on controller in HCI_AUTO_OFF grace period Dan Klishch
  2026-04-30  7:49 ` [RFC] " bluez.test.bot
@ 2026-05-04 18:27 ` Luiz Augusto von Dentz
  2026-05-04 19:15   ` Dan Klishch
  1 sibling, 1 reply; 4+ messages in thread
From: Luiz Augusto von Dentz @ 2026-05-04 18:27 UTC (permalink / raw)
  To: Dan Klishch; +Cc: Marcel Holtmann, linux-bluetooth, linux-kernel

Hi Dan,

On Thu, Apr 30, 2026 at 12:55 AM Dan Klishch <danilklishch@gmail.com> wrote:
>
> When mgmt's Set Public Address command (and Set External Configuration)
> stages a configuration change, set_public_address() sets HCI_CONFIG and
> HCI_AUTO_OFF on the device and queues hci_power_on. The intent is for
> the queued power_on to run hci_dev_init_sync() -- which detects
> HCI_CONFIG and calls hdev->set_bdaddr() to program the new address into
> the firmware -- and then re-emit Index Added with the controller back in
> the boot-init grace period (HCI_UP=1, HCI_AUTO_OFF=1) so userspace can
> re-push pending config commands and drive a fresh Set Powered 1 cycle.
>
> The bug bites when the command is issued while the controller is in
> that same grace period itself -- the normal post-boot state, before
> bluetoothd has claimed the controller via Set Powered 1. In that state
> HCI_UP=1 and HCI_AUTO_OFF=1, so hdev_is_powered() is false (the command
> is accepted) but hci_power_on()'s "already up" early-return condition
> HCI_UP && HCI_MGMT && HCI_AUTO_OFF is true. The early-return path runs
> hci_powered_update_sync() -- which is the wrong thing for this case:
> neither hci_dev_init_sync() nor mgmt_index_added() runs. The result:
>
>   - hdev->public_addr is recorded but never reaches the firmware via
>     hdev->set_bdaddr(),
>   - userspace sees Index Removed (from set_public_address) but no
>     Index Added, leaving the controller invisible to mgmt clients;
>     it is not in the configured, unconfigured or extended index list
>     yet remains registered in the kernel.
>
> The other two starting states are fine: HCI_UP=0 falls through to the
> full hci_dev_do_open() path (correct); HCI_UP=1 with HCI_AUTO_OFF=0
> makes hdev_is_powered() true, so set_public_address() rejects with
> MGMT_STATUS_REJECTED before queueing power_on at all.
>
> Fix: at the top of hci_power_on(), if HCI_CONFIG is pending and we are
> in the affected grace-period state (HCI_UP, HCI_MGMT, !HCI_RFKILLED),
> close the device first. The early-return condition then fails and we
> fall through to hci_dev_do_open() -> hci_dev_init_sync(), which honors
> HCI_CONFIG by invoking hdev->set_bdaddr(); the post-open block then
> re-emits Index Added via the existing HCI_CONFIG branch.
>
> hci_dev_close_sync() clears HCI_AUTO_OFF as a side effect of going
> through the regular power-down path, but set_public_address() had set
> it deliberately so the post-reopen state matches the boot-init grace
> period that mgmt clients expect ("treat as new one" per the protocol
> contract). Several mgmt commands -- Set Privacy, Set Wideband Speech,
> Set LE, Set BR/EDR, etc. -- gate on !hdev_is_powered(), and bluetoothd
> expects to push them during this window before issuing Set Powered 1
> itself. Restore HCI_AUTO_OFF after the close so hdev_is_powered() ==
> false again.
>
> This matches the documented behavior for Set Public Address on a
> fully-configured controller ("Once the address has been successfully
> changed an Index Added event will be sent.")
>
> Assisted-by: Claude:claude-opus-4-7
> Signed-off-by: Dan Klishch <danilklishch@gmail.com>
> ---
>  net/bluetooth/hci_core.c | 8 ++++++++
>  1 file changed, 8 insertions(+)
>
> --- a/net/bluetooth/hci_core.c
> +++ b/net/bluetooth/hci_core.c
> @@ -948,6 +948,14 @@ static void hci_power_on(struct work_struct *work)
>
>         BT_DBG("%s", hdev->name);
>
> +       if (hci_dev_test_flag(hdev, HCI_CONFIG) &&
> +           hci_dev_test_flag(hdev, HCI_MGMT) &&
> +           !hci_dev_test_flag(hdev, HCI_RFKILLED) &&
> +           test_bit(HCI_UP, &hdev->flags)) {
> +               hci_dev_do_close(hdev);
> +               hci_dev_set_flag(hdev, HCI_AUTO_OFF);
> +       }
> +
>         if (test_bit(HCI_UP, &hdev->flags) &&
>             hci_dev_test_flag(hdev, HCI_MGMT) &&
>             hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF)) {
>
> ---
>
> Claude was able to fully convince me that the patch and the explanation
> are correct. Moreover, this indeed fixed a problem I had with a custom
> patched bluetoothd that happened to override public-addr in the 2
> second post-boot window. However, both the patch and commit description
> are fully AI-generated.

This doesn't inspire much confidence, though. Have you at least tried
it yourself? Perhaps we need to ask Claude to first add a test to
mgmt-tester to ensure it actually fixes something rather than just
hallucinating. Most models are not actually very critical of their
proposals if there is nothing to validate their claims with.

-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [RFC PATCH] Bluetooth: fix Set Public Address on controller in HCI_AUTO_OFF grace period
  2026-05-04 18:27 ` [RFC PATCH] " Luiz Augusto von Dentz
@ 2026-05-04 19:15   ` Dan Klishch
  0 siblings, 0 replies; 4+ messages in thread
From: Dan Klishch @ 2026-05-04 19:15 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: Marcel Holtmann, linux-bluetooth, linux-kernel

Hi Luiz,

On 5/4/26 2:27 PM, Luiz Augusto von Dentz wrote:
> Hi Dan,
> 
> On Thu, Apr 30, 2026 at 12:55 AM Dan Klishch <danilklishch@gmail.com> wrote:
>>
>> When mgmt's Set Public Address command (and Set External Configuration)
>> stages a configuration change, set_public_address() sets HCI_CONFIG and
>> HCI_AUTO_OFF on the device and queues hci_power_on. The intent is for
>> the queued power_on to run hci_dev_init_sync() -- which detects
>> HCI_CONFIG and calls hdev->set_bdaddr() to program the new address into
>> the firmware -- and then re-emit Index Added with the controller back in
>> the boot-init grace period (HCI_UP=1, HCI_AUTO_OFF=1) so userspace can
>> re-push pending config commands and drive a fresh Set Powered 1 cycle.
>>
>> The bug bites when the command is issued while the controller is in
>> that same grace period itself -- the normal post-boot state, before
>> bluetoothd has claimed the controller via Set Powered 1. In that state
>> HCI_UP=1 and HCI_AUTO_OFF=1, so hdev_is_powered() is false (the command
>> is accepted) but hci_power_on()'s "already up" early-return condition
>> HCI_UP && HCI_MGMT && HCI_AUTO_OFF is true. The early-return path runs
>> hci_powered_update_sync() -- which is the wrong thing for this case:
>> neither hci_dev_init_sync() nor mgmt_index_added() runs. The result:
>>
>>    - hdev->public_addr is recorded but never reaches the firmware via
>>      hdev->set_bdaddr(),
>>    - userspace sees Index Removed (from set_public_address) but no
>>      Index Added, leaving the controller invisible to mgmt clients;
>>      it is not in the configured, unconfigured or extended index list
>>      yet remains registered in the kernel.
>>
>> The other two starting states are fine: HCI_UP=0 falls through to the
>> full hci_dev_do_open() path (correct); HCI_UP=1 with HCI_AUTO_OFF=0
>> makes hdev_is_powered() true, so set_public_address() rejects with
>> MGMT_STATUS_REJECTED before queueing power_on at all.
>>
>> Fix: at the top of hci_power_on(), if HCI_CONFIG is pending and we are
>> in the affected grace-period state (HCI_UP, HCI_MGMT, !HCI_RFKILLED),
>> close the device first. The early-return condition then fails and we
>> fall through to hci_dev_do_open() -> hci_dev_init_sync(), which honors
>> HCI_CONFIG by invoking hdev->set_bdaddr(); the post-open block then
>> re-emits Index Added via the existing HCI_CONFIG branch.
>>
>> hci_dev_close_sync() clears HCI_AUTO_OFF as a side effect of going
>> through the regular power-down path, but set_public_address() had set
>> it deliberately so the post-reopen state matches the boot-init grace
>> period that mgmt clients expect ("treat as new one" per the protocol
>> contract). Several mgmt commands -- Set Privacy, Set Wideband Speech,
>> Set LE, Set BR/EDR, etc. -- gate on !hdev_is_powered(), and bluetoothd
>> expects to push them during this window before issuing Set Powered 1
>> itself. Restore HCI_AUTO_OFF after the close so hdev_is_powered() ==
>> false again.
>>
>> This matches the documented behavior for Set Public Address on a
>> fully-configured controller ("Once the address has been successfully
>> changed an Index Added event will be sent.")
>>
>> Assisted-by: Claude:claude-opus-4-7
>> Signed-off-by: Dan Klishch <danilklishch@gmail.com>
>> ---
>>   net/bluetooth/hci_core.c | 8 ++++++++
>>   1 file changed, 8 insertions(+)
>>
>> --- a/net/bluetooth/hci_core.c
>> +++ b/net/bluetooth/hci_core.c
>> @@ -948,6 +948,14 @@ static void hci_power_on(struct work_struct *work)
>>
>>          BT_DBG("%s", hdev->name);
>>
>> +       if (hci_dev_test_flag(hdev, HCI_CONFIG) &&
>> +           hci_dev_test_flag(hdev, HCI_MGMT) &&
>> +           !hci_dev_test_flag(hdev, HCI_RFKILLED) &&
>> +           test_bit(HCI_UP, &hdev->flags)) {
>> +               hci_dev_do_close(hdev);
>> +               hci_dev_set_flag(hdev, HCI_AUTO_OFF);
>> +       }
>> +
>>          if (test_bit(HCI_UP, &hdev->flags) &&
>>              hci_dev_test_flag(hdev, HCI_MGMT) &&
>>              hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF)) {
>>
>> ---
>>
>> Claude was able to fully convince me that the patch and the explanation
>> are correct. Moreover, this indeed fixed a problem I had with a custom
>> patched bluetoothd that happened to override public-addr in the 2
>> second post-boot window. However, both the patch and commit description
>> are fully AI-generated.
> 
> This doesn't inspire much confidence, though. Have you at least tried
> it yourself? Perhaps we need to ask Claude to first add a test to
> mgmt-tester to ensure it actually fixes something rather than just
> hallucinating. Most models are not actually very critical of their
> proposals if there is nothing to validate their claims with.
> 

I did test this indeed. The bluez patch I mentioned:
https://gist.github.com/DanShaders/4d280096a5f0f2f45ce07028cbd36761
(this is yet another AI slop, sorry!; I just wanted something quick for
myself). Without the kernel patch, MGMT_OP_SET_PUBLIC_ADDRESS is just
silently swallowed, adapter is removed, and then the userspace never
sees it again.

Claude says it cannot easily add an in-tree test for the patch without
additional changes in vhci to support setting public address. Should I
tell it to do a 3 commit series (set public addr on vhci; this; a test)
and send as V2?

One more question: seems like CI is angry on me because I included the
`Assisted-by: Claude:claude-opus-4-7` tag as per
https://docs.kernel.org/process/coding-assistants.html . Should I remove
it?

(Resending since I accidentally chose "Reply" instead of "Reply All" the
first time, I'm not very used to mailing lists)

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-05-04 19:15 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-30  4:55 [RFC PATCH] Bluetooth: fix Set Public Address on controller in HCI_AUTO_OFF grace period Dan Klishch
2026-04-30  7:49 ` [RFC] " bluez.test.bot
2026-05-04 18:27 ` [RFC PATCH] " Luiz Augusto von Dentz
2026-05-04 19:15   ` Dan Klishch

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox