Skip to content

[PW_SID:1166333] [v4] Bluetooth: hci_sync: pause advertising for the scan address update - #781

Open
BluezTestBot wants to merge 6 commits into
workflowfrom
1166333
Open

BluezTestBot wants to merge 6 commits into
workflowfrom
1166333

Conversation

@BluezTestBot

Copy link
Copy Markdown

hci_active_scan_sync() programs a non-resolvable private address with LE
Set Random Address on every active scan start.

BLUETOOTH CORE SPECIFICATION Vol 4, Part E, 7.8.4 says the controller
shall return Command Disallowed (0x0C) for that command while legacy
advertising or scanning is enabled. hci_pause_addr_resolution(), called
just above, only stops advertising when LL privacy is in use, so on a
controller without it the command is issued while advertising is still
on:

Bluetooth: hci0: Opcode 0x2005 failed: -16

It does not converge either. hdev->random_addr is only set on a
successful command complete, so it stays BDADDR_ANY, and the deferral
added by commit c2994b0 ("Bluetooth: hci_sync: Fix not setting
Random Address when required") is skipped in exactly that case. Observed
on a BCM43455, which has no LL privacy and no extended advertising, at
the scan restart period of about 10 s, for as long as discovery keeps
restarting:

< LE Set Random Address Address: 02:16:91:90:F1:D4 (Non-Resolvable)

Command Complete LE Set Random Address, Command Disallowed
< LE Set Random Address Address: 26:90:57:96:9A:3E (Non-Resolvable)
Command Complete LE Set Random Address, Command Disallowed
< LE Set Random Address Address: 16:32:01:BC:B5:CE (Non-Resolvable)
Command Complete LE Set Random Address, Command Disallowed

Pause advertising for the address update regardless of privacy, and
resume it on every exit path. The resume was previously guarded by
ll_privacy_capable() and only reached on the error path, which matched
the pause being privacy-only.

With the patch, on the same hardware:

< LE Set Advertising Enable Success
< LE Set Random Address Success
< LE Set Scan Parameters Success
< LE Set Scan Enable Success
< LE Set Advertising Parameters Success
< LE Set Advertising Enable Success

The last two commands are the resume, issued with the scan already
running, and both succeed: on this controller re-enabling legacy
advertising during an active scan does not need a further address write,
so it is not refused.

Over 35425 btmon records and about 4 minutes of continuous active
discovery with advertising enabled there were no Command Disallowed
responses of any opcode, against one per scan restart before, and a
central could still connect.

One caveat this widens, flagged on the previous posting. When
HCI_ADVERTISING is set, hci_pause_advertising_sync() also clears
HCI_DISCOVERABLE and HCI_LIMITED_DISCOVERABLE and zeroes discov_timeout,
and hci_resume_advertising_sync() restores only HCI_ADVERTISING, so the
discoverable state is lost for good. It reproduces today on an LL privacy
controller through hci_pause_addr_resolution(), with no scan patch
involved; this patch makes it reachable on controllers without LL privacy
as well. On a BCM43455 carrying this patch:

btmgmt -i hci0 connectable yes
btmgmt -i hci0 advertising on
btmgmt -i hci0 discov yes
current settings: powered connectable discoverable le advertising ...
btmgmt -i hci0 find -l
current settings: powered connectable le advertising ...

hci_suspend_sync() already calls hci_pause_advertising_sync()
unconditionally, with no privacy guard, so a device that suspends loses
the same state on any controller today. The clear is also reached only
with HCI_ADVERTISING set, i.e. when advertising is mgmt-managed, not for
a device made discoverable without it.

That asymmetry is pre-existing and independent of this patch, so it is
left alone here rather than folded into a scan path fix.

Tooling disclosure (Documentation/process/generated-content.rst): an AI
coding assistant was used to investigate this and to draft the change;
the patch text and code are its output, reviewed by me. Inputs were btmon
captures and kernel logs from the affected device, with the request to
identify what re-issues LE Set Random Address every ~10 s and to fix it.
Three earlier explanations it proposed were discarded after being checked
against the captures: bluetoothd restarting service discovery; RPA
rotation (excluded, Privacy=off); and the static-address branch of
hci_update_random_address_sync() (excluded, both random_address and
static_address read 00:00:00:00:00:00). The cause was only established
after decoding the command payloads, which showed a freshly generated
non-resolvable address per attempt. Testing is as described above, on the
device, using btmon and a second device to confirm connectability.

Fixes: abfeea4 ("Bluetooth: hci_sync: Convert MGMT_OP_START_DISCOVERY")
Assisted-by: Claude:claude-opus-5 btmon
Signed-off-by: Valentin Kindschi valentin.kindschi@fiveco.ch

Changes in v4:

  • Report the HCI_DISCOVERABLE asymmetry raised in review rather than fix
    it: hci_pause_advertising_sync() clears HCI_DISCOVERABLE and
    HCI_LIMITED_DISCOVERABLE and zeroes discov_timeout, and the resume
    restores only HCI_ADVERTISING. It is pre-existing on LL privacy
    controllers, which reach the same pause through
    hci_pause_addr_resolution(); this patch widens it to controllers
    without LL privacy. The commit message now carries a reproducer.
  • Keep the explicit return on the success path, so the resume runs there
    and the function no longer falls through into failed:.
  • Address the review question on whether that resume can itself be
    refused while the scan is running: the capture above shows both resume
    commands succeeding with LE Set Scan Enable already sent.
  • Shorten the added comments to one line each.

Changes in v3:

  • Resend, no code change; v2 had no reply. Rechecked that it still applies
    to bluetooth-next.
  • Added the second capture described above, taken with the two patches from
    the "endless adv params retry" series applied, since in bluetooth-next,
    confirming the fix holds with cancelled outgoing connections in the mix.

Changes in v2:

  • Rebased onto bluetooth-next: mainline renamed use_ll_privacy() to
    ll_privacy_capable(). No functional change.

net/bluetooth/hci_sync.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)

--
2.34.1

tedd-an and others added 6 commits September 15, 2026 20:16
This patch adds workflow files for ci:

[sync.yml]
 - The workflow file for scheduled work
 - Sync the repo with upstream repo and rebase the workflow branch
 - Review the patches in the patchwork and creates the PR if needed

[ci.yml]
 - The workflow file for CI tasks
 - Run CI tests when PR is created

Signed-off-by: Tedd Ho-Jeong An <tedd.an@intel.com>
This replaces the bzcafe action with bluez/action-ci so we can maintain
everything in the github bluez organization

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This attempts to sync every 5 minutes instead of 30.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
bluez/action-ci uses master as default branch for workflow which is
incorrect for kernel

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
The CI action now creates individual GitHub Check Runs per test, which
requires 'checks: write' permission on the GITHUB_TOKEN. Also make the
pull_request trigger types explicit to include 'reopened', allowing CI
to be retriggered by closing and reopening a PR.
hci_active_scan_sync() programs a non-resolvable private address with LE
Set Random Address on every active scan start.

BLUETOOTH CORE SPECIFICATION Vol 4, Part E, 7.8.4 says the controller
shall return Command Disallowed (0x0C) for that command while legacy
advertising or scanning is enabled. hci_pause_addr_resolution(), called
just above, only stops advertising when LL privacy is in use, so on a
controller without it the command is issued while advertising is still
on:

  Bluetooth: hci0: Opcode 0x2005 failed: -16

It does not converge either. hdev->random_addr is only set on a
successful command complete, so it stays BDADDR_ANY, and the deferral
added by commit c2994b0 ("Bluetooth: hci_sync: Fix not setting
Random Address when required") is skipped in exactly that case. Observed
on a BCM43455, which has no LL privacy and no extended advertising, at
the scan restart period of about 10 s, for as long as discovery keeps
restarting:

  < LE Set Random Address  Address: 02:16:91:90:F1:D4 (Non-Resolvable)
  > Command Complete       LE Set Random Address, Command Disallowed
  < LE Set Random Address  Address: 26:90:57:96:9A:3E (Non-Resolvable)
  > Command Complete       LE Set Random Address, Command Disallowed
  < LE Set Random Address  Address: 16:32:01:BC:B5:CE (Non-Resolvable)
  > Command Complete       LE Set Random Address, Command Disallowed

Pause advertising for the address update regardless of privacy, and
resume it on every exit path. The resume was previously guarded by
ll_privacy_capable() and only reached on the error path, which matched
the pause being privacy-only.

With the patch, on the same hardware:

  < LE Set Advertising Enable                            Success
  < LE Set Random Address                                Success
  < LE Set Scan Parameters                               Success
  < LE Set Scan Enable                                   Success
  < LE Set Advertising Parameters                        Success
  < LE Set Advertising Enable                            Success

The last two commands are the resume, issued with the scan already
running, and both succeed: on this controller re-enabling legacy
advertising during an active scan does not need a further address write,
so it is not refused.

Over 35425 btmon records and about 4 minutes of continuous active
discovery with advertising enabled there were no Command Disallowed
responses of any opcode, against one per scan restart before, and a
central could still connect.

One caveat this widens, flagged on the previous posting. When
HCI_ADVERTISING is set, hci_pause_advertising_sync() also clears
HCI_DISCOVERABLE and HCI_LIMITED_DISCOVERABLE and zeroes discov_timeout,
and hci_resume_advertising_sync() restores only HCI_ADVERTISING, so the
discoverable state is lost for good. It reproduces today on an LL privacy
controller through hci_pause_addr_resolution(), with no scan patch
involved; this patch makes it reachable on controllers without LL privacy
as well. On a BCM43455 carrying this patch:

  btmgmt -i hci0 connectable yes
  btmgmt -i hci0 advertising on
  btmgmt -i hci0 discov yes
    current settings: powered connectable discoverable le advertising ...
  btmgmt -i hci0 find -l
    current settings: powered connectable le advertising ...

hci_suspend_sync() already calls hci_pause_advertising_sync()
unconditionally, with no privacy guard, so a device that suspends loses
the same state on any controller today. The clear is also reached only
with HCI_ADVERTISING set, i.e. when advertising is mgmt-managed, not for
a device made discoverable without it.

That asymmetry is pre-existing and independent of this patch, so it is
left alone here rather than folded into a scan path fix.

Tooling disclosure (Documentation/process/generated-content.rst): an AI
coding assistant was used to investigate this and to draft the change;
the patch text and code are its output, reviewed by me. Inputs were btmon
captures and kernel logs from the affected device, with the request to
identify what re-issues LE Set Random Address every ~10 s and to fix it.
Three earlier explanations it proposed were discarded after being checked
against the captures: bluetoothd restarting service discovery; RPA
rotation (excluded, Privacy=off); and the static-address branch of
hci_update_random_address_sync() (excluded, both random_address and
static_address read 00:00:00:00:00:00). The cause was only established
after decoding the command payloads, which showed a freshly generated
non-resolvable address per attempt. Testing is as described above, on the
device, using btmon and a second device to confirm connectability.

Fixes: abfeea4 ("Bluetooth: hci_sync: Convert MGMT_OP_START_DISCOVERY")
Assisted-by: Claude:claude-opus-5 btmon
Signed-off-by: Valentin Kindschi <valentin.kindschi@fiveco.ch>
@github-actions

Copy link
Copy Markdown

CheckPatch
Desc: Run checkpatch.pl script
Duration: 0.75 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

VerifyFixes
Desc: Verify Fixes tag format and validity
Duration: 0.10 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

VerifySignedoff
Desc: Verify Signed-off-by chain
Duration: 0.10 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

GitLint
Desc: Run gitlint
Duration: 0.37 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

SubjectPrefix
Desc: Check subject contains "Bluetooth" prefix
Duration: 0.10 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

BuildKernel
Desc: Build Kernel for Bluetooth
Duration: 27.71 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

CheckAllWarning
Desc: Run linux kernel with all warning enabled
Duration: 31.65 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

CheckSparse
Desc: Run sparse tool with linux kernel
Duration: 34.36 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

BuildKernel32
Desc: Build 32bit Kernel for Bluetooth
Duration: 27.89 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

CheckKernelLLVM
Desc: Build kernel with LLVM + context analysis
Duration: 33.42 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

TestRunnerSetup
Desc: Setup kernel and bluez for test-runner
Duration: 726.62 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

TestRunner_l2cap-tester
Desc: Run l2cap-tester with test-runner
Duration: 16.64 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

TestRunner_iso-tester
Desc: Run iso-tester with test-runner
Duration: 44.72 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

TestRunner_bnep-tester
Desc: Run bnep-tester with test-runner
Duration: 3.09 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

TestRunner_mgmt-tester
Desc: Run mgmt-tester with test-runner
Duration: 60.30 seconds
Result: FAIL
Output:

Total: 501, Passed: 496 (99.0%), Failed: 1, Not Run: 4

Failed Test Cases
Read Exp Feature - Success                           Failed       0.019 seconds

@github-actions

Copy link
Copy Markdown

TestRunner_rfcomm-tester
Desc: Run rfcomm-tester with test-runner
Duration: 4.40 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

TestRunner_sco-tester
Desc: Run sco-tester with test-runner
Duration: 7.56 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

TestRunner_ioctl-tester
Desc: Run ioctl-tester with test-runner
Duration: 4.63 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

TestRunner_mesh-tester
Desc: Run mesh-tester with test-runner
Duration: 7.81 seconds
Result: FAIL
Output:

Total: 10, Passed: 8 (80.0%), Failed: 2, Not Run: 0

Failed Test Cases
Mesh - Send cancel - 1                               Timed out    2.462 seconds
Mesh - Send cancel - 2                               Timed out    1.998 seconds

@github-actions

Copy link
Copy Markdown

TestRunner_smp-tester
Desc: Run smp-tester with test-runner
Duration: 4.30 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

TestRunner_userchan-tester
Desc: Run userchan-tester with test-runner
Duration: 3.14 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

TestRunner_6lowpan-tester
Desc: Run 6lowpan-tester with test-runner
Duration: 4.36 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

IncrementalBuild
Desc: Incremental build with the patches in the series
Duration: 26.44 seconds
Result: PASS

@github-actions
github-actions Bot force-pushed the workflow branch 2 times, most recently from dd2b970 to 940d0d6 Compare September 16, 2026 21:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants