From: Weihong Guan <weihong.guan@gmail.com>
To: linux-bluetooth@vger.kernel.org
Cc: Marcel Holtmann <marcel@holtmann.org>,
Luiz Augusto von Dentz <luiz.dentz@gmail.com>,
Weihong Guan <weihong.guan@gmail.com>
Subject: [PATCH v2 2/3] Bluetooth: hci_sync: Remove an advertising set by its handle
Date: Wed, 11 Nov 2026 01:09:39 +0000 [thread overview]
Message-ID: <20261111010940.728149-3-weihong.guan@gmail.com> (raw)
In-Reply-To: <20261111010940.728149-1-weihong.guan@gmail.com>
When the controller supports a single advertising set,
hci_add_adv_instance() gives instance 1 handle 0x00, but
hci_remove_ext_adv_instance_sync() sends the instance number as the
handle of LE Remove Advertising Set, so removing instance 1 fails:
$ btmgmt rm-adv 1
Remove Advertising failed with status 0x03 (Failed)
< HCI Command: LE Remove Advertising Set Handle: 1
> HCI Event: Command Complete
Status: Unknown Advertising Identifier (0x42)
Send the instance's handle, looked up with hdev->lock held. Two more
things follow from the instance and the handle differing:
- hci_cc_le_remove_adv_set() removes the instance numbered as the
handle it sent, which for handle 0x00 is instance 0, so instance 1
would stay in hdev->adv_instances with its RPA timer running, and no
MGMT_EV_ADVERTISING_REMOVED. The completion can't tell instance 1
from instance 0, which the MGMT Set Advertising path removes on the
same handle, so remove instance 1 in
hci_remove_ext_adv_instance_sync() once the command succeeds.
- While Global Advertising is on, it owns handle 0x00
(adv_overridden_by_global()), and the set may be enabled for it, so
the controller would refuse to remove it, with Command Disallowed.
Remove only the instance then, leaving the set to Global
Advertising.
Fixes: e77f43d531af ("Bluetooth: hci_core: Fix not handling hdev->le_num_of_adv_sets=1")
Assisted-by: Claude:claude-opus-5.5
Signed-off-by: Weihong Guan <weihong.guan@gmail.com>
---
net/bluetooth/hci_sync.c | 55 +++++++++++++++++++++++++++++++++++-----
1 file changed, 49 insertions(+), 6 deletions(-)
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index 320c5ba0d..d4a4f49df 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -2110,6 +2110,9 @@ int hci_enable_advertising(struct hci_dev *hdev)
int hci_remove_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance,
struct sock *sk)
{
+ struct adv_info *adv = NULL;
+ u8 handle = instance;
+ bool global = false;
int err;
if (!ext_adv_capable(hdev))
@@ -2119,13 +2122,53 @@ int hci_remove_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance,
if (err)
return err;
- /* If request specifies an instance that doesn't exist, fail */
- if (instance > 0 && !hci_find_adv_instance(hdev, instance))
- return -EINVAL;
+ if (instance) {
+ hci_dev_lock(hdev);
+
+ adv = hci_find_adv_instance(hdev, instance);
+ if (adv) {
+ handle = adv->handle;
+
+ /* An instance sharing handle 0x00 with Global
+ * Advertising doesn't own the set while Global
+ * Advertising is on, and the set may still be enabled
+ * for it, which the controller would refuse to remove.
+ */
+ global = !handle &&
+ (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
+ hci_dev_test_flag(hdev, HCI_LE_ADV_0));
+ }
+
+ hci_dev_unlock(hdev);
+
+ /* If request specifies an instance that doesn't exist, fail */
+ if (!adv)
+ return -EINVAL;
+ }
+
+ if (!global) {
+ err = __hci_cmd_sync_status_sk(hdev, HCI_OP_LE_REMOVE_ADV_SET,
+ sizeof(handle), &handle, 0,
+ HCI_CMD_TIMEOUT, sk);
+ if (err)
+ return err;
+ }
+
+ /* hci_cc_le_remove_adv_set() removes the instance numbered as the
+ * handle it sent, so remove here an instance using another handle:
+ * instance 1 on handle 0x00, on a controller supporting a single
+ * advertising set. The completion can't tell it from instance 0.
+ */
+ if (handle != instance) {
+ hci_dev_lock(hdev);
+
+ if (!hci_remove_adv_instance(hdev, instance))
+ mgmt_advertising_removed(sk, hdev, instance);
- return __hci_cmd_sync_status_sk(hdev, HCI_OP_LE_REMOVE_ADV_SET,
- sizeof(instance), &instance, 0,
- HCI_CMD_TIMEOUT, sk);
+ hci_dev_unlock(hdev);
+ }
+
+ return 0;
}
int hci_le_terminate_big_sync(struct hci_dev *hdev, u8 handle, u8 reason)
--
2.47.3
next prev parent reply other threads:[~2026-11-11 1:09 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-11 1:09 [PATCH v2 0/3] Bluetooth: Advertising sets on a single-set controller Weihong Guan
2026-11-11 1:09 ` [PATCH v2 1/3] Bluetooth: hci_sync: Set an advertising set's random address on its handle Weihong Guan
2026-11-11 3:38 ` Bluetooth: Advertising sets on a single-set controller bluez.test.bot
2026-11-11 1:09 ` Weihong Guan [this message]
2026-11-11 1:09 ` [PATCH v2 3/3] Bluetooth: hci_event: Find the instance owning a terminated advertising set Weihong Guan
2026-11-11 15:47 ` Luiz Augusto von Dentz
2026-11-11 16:58 ` Weihong Guan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261111010940.728149-3-weihong.guan@gmail.com \
--to=weihong.guan@gmail.com \
--cc=linux-bluetooth@vger.kernel.org \
--cc=luiz.dentz@gmail.com \
--cc=marcel@holtmann.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox