From fb1baa000d7a0b597ab9eb29b179b03e70e5f6ee Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Thu, 15 Oct 2026 11:37:52 -0400 Subject: [PATCH 01/30] Bluetooth: hci_sync: Fix invalid Supervision_Timeout in LE Set Default Rate The LE Set Default Rate Parameters command is rejected with Invalid HCI Command Parameters (0x12) because the Supervision_Timeout of 120 ms is exactly the minimum recommended by HOGP v1.2: Greater than or equal to (1 + Peripheral Latency) x Subrate max x Connection Interval max x 2 But the Core spec treats the equality as invalid: BLUETOOTH CORE SPECIFICATION Version 6.3 | Vol 4, Part E 7.8.158. LE Set Default Rate Parameters command If Connection_Interval_Max x Subrate_Max x (Max_Latency + 1) is greater than or equal to Supervision_Timeout x 40, the Controller shall return the error code Invalid HCI Command Parameters (0x12). With the current values 0x78 x 4 x 1 = 480 >= 0x0c x 40 = 480. Fix this by using 2 s as the default Supervision_Timeout, which is 10x lower than the 20 s used for non-SCI connections while still well above the minimum required, and make sure it remains above the minimum in case interval_max is raised to match the controller's minimum supported connection interval. Fixes: 2f8784cfe8a9 ("Bluetooth: Add support for Shorter Connection Interval (SCI) feature") Assisted-by: OpenCode:claude-opus-5.5 Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_sync.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 03f706c1f815..7ac26daba966 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -4828,6 +4828,9 @@ static int hci_le_set_def_rate_sync(struct hci_dev *hdev) struct hci_cp_le_set_def_rate cp; u16 interval_min = 0x000a; /* 1.25 ms */ u16 interval_max = 0x0078; /* 15 ms */ + u16 subrate_max = 0x0004; + u16 max_latency = 0x0000; + u32 supv_timeout; if (!le_sci_capable(hdev)) return 0; @@ -4852,10 +4855,31 @@ static int hci_le_set_def_rate_sync(struct hci_dev *hdev) cp.interval_min = cpu_to_le16(interval_min); cp.interval_max = cpu_to_le16(interval_max); cp.subrate_min = cpu_to_le16(0x0001); - cp.subrate_max = cpu_to_le16(0x0004); - cp.max_latency = cpu_to_le16(0x0000); + cp.subrate_max = cpu_to_le16(subrate_max); + cp.max_latency = cpu_to_le16(max_latency); cp.cont_num = cpu_to_le16(0x0001); - cp.supv_timeout = cpu_to_le16(0x000c); /* 120 ms */ + + /* HOGP v1.2 recommends a Supervision_Timeout greater than or equal to + * (1 + Max_Latency) x Subrate_Max x Connection_Interval_Max x 2, but + * the Core spec treats the equality as invalid: + * + * BLUETOOTH CORE SPECIFICATION Version 6.3 | Vol 4, Part E + * 7.8.158. LE Set Default Rate Parameters command + * + * If Connection_Interval_Max x Subrate_Max x (Max_Latency + 1) is + * greater than or equal to Supervision_Timeout x 40, the Controller + * shall return the error code Invalid HCI Command Parameters (0x12). + * + * So default to 2 s, 10x lower than the 20 s used for non-SCI + * connections while still well above the minimum required, but make + * sure it stays strictly above the minimum in case interval_max has + * been raised. + */ + supv_timeout = (u32)interval_max * subrate_max * (max_latency + 1); + supv_timeout = supv_timeout / 40 + 1; + supv_timeout = clamp_t(u32, max_t(u32, supv_timeout, 0x00c8), + 0x000a, 0x0c80); + cp.supv_timeout = cpu_to_le16(supv_timeout); /* The connection event length recommended in requests by a Peripheral * uses units of 125 us with a valid range of 0x0001 to 0x7CFF From f0cf5a24cefeb629876bd15d668ff062c8655e28 Mon Sep 17 00:00:00 2001 From: Binbin Deng <18983559317@163.com> Date: Mon, 19 Oct 2026 19:16:11 +0800 Subject: [PATCH 02/30] Bluetooth: hci_core: Initialize IRK before publication hci_add_irk() initializes the identity address and address type of a newly allocated IRK, publishes it on hdev->identity_resolving_keys, and only then initializes its value and RPA. RCU readers such as hci_find_irk_by_rpa() and the debugfs identity_resolving_keys_show() can traverse the new entry during that window and see a zero or partially initialized IRK. The race is reachable by racing an IRK addition with another CPU resolving or dumping IRKs. In particular, userspace can issue MGMT_OP_LOAD_IRKS while another process reads the corresponding debugfs file or triggers RPA resolution. Initialize the IRK value and RPA before publishing a newly allocated IRK. Existing IRKs remain published and continue to be updated in place. Found during a static-analysis-assisted audit: candidate sites were surfaced by a Coccinelle rule, and the reader/writer paths were confirmed by LLM-assisted (GLM-5.3) code inspection. The issue was not observed at runtime; it is identified by code inspection only. Fixes: adae20cb2d20 ("Bluetooth: Convert IRK list to RCU") Assisted-by: GLM-5.3 coccinelle Signed-off-by: Binbin Deng <18983559317@163.com> Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_core.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 209244fd9391..65373e4aea94 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1315,9 +1315,10 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, struct smp_irk *hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 val[16], bdaddr_t *rpa) { - struct smp_irk *irk; + struct smp_irk *irk, *old_irk; - irk = hci_find_irk_by_addr(hdev, bdaddr, addr_type); + old_irk = hci_find_irk_by_addr(hdev, bdaddr, addr_type); + irk = old_irk; if (!irk) { irk = kzalloc_obj(*irk); if (!irk) @@ -1326,12 +1327,14 @@ struct smp_irk *hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, bacpy(&irk->bdaddr, bdaddr); irk->addr_type = addr_type; - list_add_rcu(&irk->list, &hdev->identity_resolving_keys); } memcpy(irk->val, val, 16); bacpy(&irk->rpa, rpa); + if (!old_irk) + list_add_rcu(&irk->list, &hdev->identity_resolving_keys); + return irk; } From ae9c8df1ffb84560ac01cbdc26cfb19027f4d25f Mon Sep 17 00:00:00 2001 From: Binbin Deng <18983559317@163.com> Date: Mon, 19 Oct 2026 16:17:11 +0800 Subject: [PATCH 03/30] Bluetooth: hci_core: Initialize link key before publication hci_add_link_key() allocates a new link key with kzalloc(), inserts it into hdev->link_keys with list_add_rcu(), and only then initializes its address, value, type, and PIN length. RCU readers such as hci_find_link_key() and the debugfs link_keys_show() do not take hci_dev_lock, so they can traverse the new entry during that initialization window and observe a zero or partially initialized key. This can be triggered by racing a link-key update with another CPU looking up or dumping keys. In particular, userspace can issue MGMT_OP_LOAD_LINK_KEYS while another process reads the corresponding debugfs file. Complete all fields of a newly allocated key before publishing it with list_add_rcu(). Existing keys remain visible and keep their current in-place update behavior. Found during a static-analysis-assisted audit: candidate sites were surfaced by a Coccinelle rule, and the reader/writer paths were confirmed by LLM-assisted (GLM-5.3) code inspection. The issue was not observed at runtime; it is identified by code inspection only. Fixes: 0378b5977013 ("Bluetooth: Convert link keys list to use RCU") Signed-off-by: Binbin Deng <18983559317@163.com> Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 65373e4aea94..ec5ef5811df9 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1252,7 +1252,6 @@ struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, key = kzalloc_obj(*key); if (!key) return NULL; - list_add_rcu(&key->list, &hdev->link_keys); } BT_DBG("%s key for %pMR type %u", hdev->name, bdaddr, type); @@ -1276,6 +1275,9 @@ struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, else key->type = type; + if (!old_key) + list_add_rcu(&key->list, &hdev->link_keys); + if (persistent) *persistent = hci_persistent_key(hdev, conn, type, old_key_type); From 4335849380aa1081ee9a1c2b934cbdda0961fa57 Mon Sep 17 00:00:00 2001 From: Binbin Deng <18983559317@163.com> Date: Mon, 19 Oct 2026 18:56:24 +0800 Subject: [PATCH 04/30] Bluetooth: hci_core: Initialize LTK before publication hci_add_ltk() publishes a newly allocated LTK on hdev->long_term_keys before initializing its address, type, value, authentication state, encryption size, EDIV, and random value. hci_find_ltk() and the debugfs long_term_keys_show() traverse this list under RCU and can therefore see a zero or partially initialized key before those stores complete. The race is reachable by racing an LTK addition with another CPU looking up or dumping long-term keys. For example, userspace can issue MGMT_OP_LOAD_LONG_TERM_KEYS while another process reads the corresponding debugfs file. Initialize all fields of a new LTK before list_add_rcu() makes it visible to RCU readers. Existing LTKs remain published and continue to be updated in place. Found during a static-analysis-assisted audit: candidate sites were surfaced by a Coccinelle rule, and the reader/writer paths were confirmed by LLM-assisted (GLM-5.3) code inspection. The issue was not observed at runtime; it is identified by code inspection only. Fixes: 970d0f1b2803 ("Bluetooth: Convert LTK list to RCU") Assisted-by: GLM-5.3 coccinelle Signed-off-by: Binbin Deng <18983559317@163.com> Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index ec5ef5811df9..e53cbaef819c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1299,7 +1299,6 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, key = kzalloc_obj(*key); if (!key) return NULL; - list_add_rcu(&key->list, &hdev->long_term_keys); } bacpy(&key->bdaddr, bdaddr); @@ -1311,6 +1310,9 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, key->enc_size = enc_size; key->type = type; + if (!old_key) + list_add_rcu(&key->list, &hdev->long_term_keys); + return key; } From 737139f4157d302292a6b937d96922879ecabfa3 Mon Sep 17 00:00:00 2001 From: Valentin Kindschi Date: Tue, 20 Oct 2026 12:51:49 +0200 Subject: [PATCH 05/30] Bluetooth: hci_sync: re-enable legacy advertising on resume hci_resume_advertising_sync() never re-enables advertising on a controller without extended advertising. It restores HCI_ADVERTISING from advertising_old_state, then calls hci_schedule_adv_instance_sync(), which starts with: if (hci_dev_test_flag(hdev, HCI_ADVERTISING) && !ext_adv_capable(hdev)) return -EPERM; The flag it tests was set a few lines earlier by the resume itself, so the call returns -EPERM without sending anything. The return value is discarded by every caller, so the failure is silent: advertising_paused is cleared, HCI_ADVERTISING is set, and the controller is not advertising. Observed on a BCM43455 (no extended advertising) after an active scan: btmon shows the pause disabling advertising and no re-enable in the ten seconds that follow, the device does not appear in another controller's scan, and btmgmt info still reports "advertising" in current settings. Enable instance 0x00 directly in that case, the way reenable_adv_sync() already does for the same situation. Instances continue to go through hci_schedule_adv_instance_sync() so the software rotation loop is rearmed. This affects every caller of hci_resume_advertising_sync(), not only the scan path: address resolution changes, accept list updates, discovery stop, suspend/resume and the end of an LE connection attempt all leave advertising disabled on such a controller today. The resume does nothing when the controller is already advertising, as it is after directed advertising was started for a peripheral connection, so it does not replace that advertising. err is initialised because the extended branch leaves it unset when adv_instances is empty and HCI_LE_ADV_0 is clear. Fixes: ad383c2c65a5 ("Bluetooth: hci_sync: Enable advertising when LL privacy is enabled") Cc: stable@vger.kernel.org Assisted-by: Claude:claude-opus-5.5 btmon Signed-off-by: Valentin Kindschi Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_sync.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 7ac26daba966..c2f2a0c0e73d 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -2733,7 +2733,7 @@ static int hci_pause_advertising_sync(struct hci_dev *hdev) static int hci_resume_advertising_sync(struct hci_dev *hdev) { struct adv_info *adv, *tmp; - int err; + int err = 0; /* If advertising has not been paused there is nothing to do. */ if (!hdev->advertising_paused) @@ -2766,13 +2766,19 @@ static int hci_resume_advertising_sync(struct hci_dev *hdev) */ if (hci_dev_test_and_clear_flag(hdev, HCI_LE_ADV_0)) err = hci_enable_ext_advertising_sync(hdev, 0x00); - } else { + } else if (hdev->cur_adv_instance) { /* Schedule for most recent instance to be restarted and begin * the software rotation loop */ err = hci_schedule_adv_instance_sync(hdev, hdev->cur_adv_instance, true); + } else if (hci_dev_test_flag(hdev, HCI_ADVERTISING) && + !hci_dev_test_flag(hdev, HCI_LE_ADV)) { + /* hci_schedule_adv_instance_sync() rejects instance 0x00 while + * HCI_ADVERTISING is set, so enable it directly. + */ + err = hci_start_adv_sync(hdev, 0x00); } hdev->advertising_paused = false; From 56ed6b127a27c418dc2daa3fd076539d8fe69c4c Mon Sep 17 00:00:00 2001 From: Valentin Kindschi Date: Tue, 20 Oct 2026 12:51:50 +0200 Subject: [PATCH 06/30] Bluetooth: hci_sync: pause advertising for the scan address update 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 c2994b008492 ("Bluetooth: hci_sync: Fix not setting Random Address when required") requires it to be set. Unlike the resolvable address a few lines above, which is reused while rpa_valid(), the non-resolvable one is regenerated and rewritten on every call, so a controller that refuses the write is asked again at the scan restart period of about 10 s, for as long as discovery keeps restarting. Observed on a BCM43455, which has no LL privacy and no extended advertising, 190 rejections in one capture, every one retrying the same address: < 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 Pause advertising for the address update, and resume it once the update is done and before the scan is started. The pause does not outlive the function: it is taken only when nothing else holds it, and every exit resumes advertising, which also releases the pause taken by hci_pause_addr_resolution(). A failed pause returns before marking anything paused, so the error path is a no-op. The resume in the error path is no longer guarded by ll_privacy_capable(). That guard matched a pause taken only under LL privacy; the pause added here is unconditional, and hci_resume_advertising_sync() returns early when nothing was paused. One caveat this widens, raised 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. It reproduces today on an LL privacy controller through hci_pause_addr_resolution(); the unconditional pause makes it reachable without LL privacy as well. hci_suspend_sync() also pauses unconditionally, so a device that suspends loses the same state on any controller today. That asymmetry is pre-existing and is left alone here rather than folded into a scan path fix. Legacy controllers have one random address register, shared by the scanner and the advertiser. Restoring the advertiser here can reprogram it when the advertiser is non-connectable, so the scan then uses that address rather than the one generated for it. Both are non-resolvable and neither is linkable to the identity address. With privacy enabled both roles already share one resolvable address the same way. With the patch, on the same hardware: < LE Set Advertising Enable Enable: 0x00 Success < LE Set Random Address Success < LE Set Advertising Parameters Success < LE Set Advertising Enable Enable: 0x01 Success < LE Set Scan Parameters Success < LE Set Scan Enable Enable: 0x01 Success The address write is accepted, and advertising is restored before the scan is started. Over 119369 btmon records and about 12 minutes of the normal workload of that device, alternating active and passive scanning with ten outgoing connection attempts, every LE Set Random Address succeeded and there were no Command Disallowed responses of any opcode, against one per scan restart before. Patch 1 is required: without it the resume added here returns -EPERM on the controllers this fixes and leaves advertising disabled. Fixes: 3c44a431d62b ("Bluetooth: hci_sync: Resume adv with no RPA when active scan") Cc: stable@vger.kernel.org Assisted-by: Claude:claude-opus-5.5 btmon Signed-off-by: Valentin Kindschi Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_sync.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index c2f2a0c0e73d..c9e80b957455 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -6340,6 +6340,7 @@ static int hci_active_scan_sync(struct hci_dev *hdev, uint16_t interval) u8 filter_policy = 0x00; /* Default is to enable duplicates filter */ u8 filter_dup = LE_SCAN_FILTER_DUP_ENABLE; + bool paused; int err; bt_dev_dbg(hdev, ""); @@ -6363,6 +6364,12 @@ static int hci_active_scan_sync(struct hci_dev *hdev, uint16_t interval) if (err) goto failed; + /* LE Set Random Address is disallowed while advertising is enabled. */ + paused = !hdev->advertising_paused; + err = hci_pause_advertising_sync(hdev); + if (err) + goto failed; + /* All active scans will be done with either a resolvable private * address (when privacy feature has been enabled) or non-resolvable * private address. @@ -6372,6 +6379,9 @@ static int hci_active_scan_sync(struct hci_dev *hdev, uint16_t interval) if (err < 0) own_addr_type = ADDR_LE_DEV_PUBLIC; + if (paused) + hci_resume_advertising_sync(hdev); + if (hci_is_adv_monitoring(hdev) || (hci_test_quirk(hdev, HCI_QUIRK_STRICT_DUPLICATE_FILTER) && hdev->discovery.result_filtering)) { @@ -6395,9 +6405,8 @@ static int hci_active_scan_sync(struct hci_dev *hdev, uint16_t interval) return err; failed: - /* Resume advertising if it was paused */ - if (ll_privacy_capable(hdev)) - hci_resume_advertising_sync(hdev); + /* No-op when advertising was not paused. */ + hci_resume_advertising_sync(hdev); /* Resume passive scanning */ hci_update_passive_scan_sync(hdev); From 19b4e5701712f74d005cc66a36374559e8dfd281 Mon Sep 17 00:00:00 2001 From: Akhil Arul Date: Fri, 23 Oct 2026 21:46:09 +0530 Subject: [PATCH 07/30] Bluetooth: hci_core: Fix queuing rx_work while workqueue is drained hci_recv_frame() drops a frame unless HCI_UP or HCI_INIT is set, but the check is not synchronized with hci_dev_close_sync(). A driver can pass the check, then close clears HCI_UP, flushes rx_work and starts drain_workqueue(), and the late queue_work() of rx_work hits the draining workqueue: workqueue: cannot queue hci_rx_work on wq hci0 WARNING: kernel/workqueue.c:2352 at __queue_work+0x2c0/0x780 Call Trace: queue_work_on+0xb2/0xc0 hci_recv_frame+0x18f/0x330 vhci_write+0x174/0x240 vfs_write+0x271/0x680 ksys_write+0x7c/0x110 Skipping the queue_work() while HCI_CMD_DRAIN_WORKQUEUE is set, as done for tx_work, does not work for rx_work: the flag covers the whole close, and events still have to be received in that window, for the commands sent by hdev->shutdown() and for the reset done with HCI_QUIRK_RESET_ON_CLOSE. Run hci_recv_frame() under rcu_read_lock() and wait with synchronize_rcu() once HCI_UP has been cleared, so that every caller which still saw HCI_UP has queued its work before the workqueue is drained, and later callers drop the frame. HCI_INIT does not reopen that window. Apart from the HCI_QUIRK_RESET_ON_CLOSE reset, which runs after drain_workqueue() has returned, it is only set by hci_dev_init_sync() during open, and open and close are serialized by hci_req_sync_lock. So once the grace period has ended, nothing can pass the check and queue rx_work until the drain is over. Tested in qemu with the syzbot C reproducer, one run per boot: the warning showed up on 12 of 30 boots before and on none of 42 boots after. Bringing a vhci controller up and down 50 times behaves the same with and without this change. Fixes: 76727c02c1e1 ("Bluetooth: Call drain_workqueue() before resetting state") Reported-by: syzbot+2344fb8002f3ef5b1712@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=2344fb8002f3ef5b1712 Signed-off-by: Akhil Arul Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_core.c | 9 +++++++++ net/bluetooth/hci_sync.c | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e53cbaef819c..55fc64db495a 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2904,8 +2904,14 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb) { u8 dev_pkt_type; + /* Pairs with synchronize_rcu() in hci_dev_close_sync(), so rx_work is + * not queued once the workqueue is being drained. + */ + rcu_read_lock(); + if (!hdev || (!test_bit(HCI_UP, &hdev->flags) && !test_bit(HCI_INIT, &hdev->flags))) { + rcu_read_unlock(); kfree_skb(skb); return -ENXIO; } @@ -2941,6 +2947,7 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb) case HCI_DRV_PKT: break; default: + rcu_read_unlock(); kfree_skb(skb); return -EINVAL; } @@ -2954,6 +2961,8 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb) skb_queue_tail(&hdev->rx_q, skb); queue_work(hdev->workqueue, &hdev->rx_work); + rcu_read_unlock(); + return 0; } EXPORT_SYMBOL(hci_recv_frame); diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index c9e80b957455..93dfe2e9bb0e 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -5667,6 +5667,11 @@ int hci_dev_close_sync(struct hci_dev *hdev) return err; } + /* Wait for hci_recv_frame() callers that still saw HCI_UP, so that + * none of them queues rx_work while the workqueue is drained below. + */ + synchronize_rcu(); + hci_leds_update_powered(hdev, false); /* Flush RX and TX works */ From f92b7bca985205082c86140d0bd7c86c5be00efc Mon Sep 17 00:00:00 2001 From: Catherine L Date: Fri, 23 Oct 2026 11:30:26 +0530 Subject: [PATCH 08/30] Bluetooth: btintel: fix buffer over-read in fw payload The firmware decoder cast fw_ptr + frag_len to struct hci_command_hdr and read cmd->plen before confirming the header and payload still fit in the remaining firmware buffer. Add explicit bounds checks before each dereference: 1. Reject if the command header is not fully contained in remain. 2. Reject if the full command including payload exceeds remain. 3. Log the offending fragment length and remaining size before returning -EINVAL. Fixes: fbbe83c52bc0d ("Bluetooth: btintel: Create common function for firmware download") Signed-off-by: Catherine L Tested-by: Kiran K Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btintel.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 0709fb3212f9..929018428c19 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -1201,7 +1201,29 @@ static int btintel_download_firmware_payload(struct hci_dev *hdev, err = -EINVAL; while (fw_ptr - fw->data < fw->size) { - struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len); + struct hci_command_hdr *cmd; + size_t remain = fw->size - (fw_ptr - fw->data); + + /* Ensure the header fits before dereferencing */ + if (frag_len + sizeof(*cmd) > remain) { + bt_dev_err(hdev, + "Firmware buffer overrun at header (frag_len %u, need %zu, remain %zu)", + frag_len, frag_len + sizeof(*cmd), remain); + err = -EINVAL; + goto done; + } + + cmd = (void *)(fw_ptr + frag_len); + + /* Ensure the full command (header + payload) fits before use */ + if (frag_len + sizeof(*cmd) + cmd->plen > remain) { + bt_dev_err(hdev, + "Firmware buffer overrun at payload (frag_len %u, plen %u, need %zu, remain %zu)", + frag_len, cmd->plen, + frag_len + sizeof(*cmd) + cmd->plen, remain); + err = -EINVAL; + goto done; + } frag_len += sizeof(*cmd) + cmd->plen; From f5cd268af1c6f87fb3847e98274e22b8c6324aa4 Mon Sep 17 00:00:00 2001 From: Kevin Dewald Date: Fri, 23 Oct 2026 12:14:37 -0700 Subject: [PATCH 09/30] Bluetooth: hci_event: Clear explicit connect state on LE connection Since commit 6cd29ec6ae5e ("Bluetooth: hci_sync: Wait for proper events when connecting LE"), create_le_conn_complete() only runs once the LE Connection Complete event has been handled, and le_conn_complete_evt() has already removed the connection parameters from pend_le_conns by then. hci_connect_le_scan_cleanup() looks the parameters up in pend_le_conns, so after a successful connection it no longer clears explicit_connect, nor deletes the parameters that were only created for the explicit connect. The parameters of every device connected through an explicit connect, such as an L2CAP or ATT connect or MGMT Pair Device, are thus left with explicit_connect set. MGMT Remove Device for all devices then keeps them as HCI_AUTO_CONN_EXPLICIT instead of freeing them, and if the device was set to auto-connect and is disconnected, they also stay on pend_le_conns: the kernel keeps scanning for the device and connects to it as soon as it advertises, although no one asked for it any more. Do the cleanup in le_conn_complete_evt() instead, where the explicit connect request is fulfilled: clear explicit_connect, delete the parameters if they only existed for it, and put report parameters back on pend_le_reports. Auto-connect parameters are added back to pend_le_conns on disconnection, as before. Update the comment in hci_explicit_conn_params_set() that names hci_connect_le_scan_cleanup() as the only place deleting them. Fixes: 6cd29ec6ae5e ("Bluetooth: hci_sync: Wait for proper events when connecting LE") Assisted-by: Claude:claude-opus-5.5 Signed-off-by: Kevin Dewald Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_conn.c | 5 +++-- net/bluetooth/hci_event.c | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 29da3fe2b953..5de95408e6e3 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -1614,8 +1614,9 @@ static int hci_explicit_conn_params_set(struct hci_dev *hdev, if (!params) return -ENOMEM; - /* If we created new params, mark them to be deleted in - * hci_connect_le_scan_cleanup. It's different case than + /* If we created new params, mark them to be deleted once the + * explicit connect is done, see le_conn_complete_evt() and + * hci_connect_le_scan_cleanup(). It's different case than * existing disabled params, those will stay after cleanup. */ params->auto_connect = HCI_AUTO_CONN_EXPLICIT; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 1f80f2cf6b2c..dede0b686c13 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -6041,6 +6041,28 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, hci_conn_put(params->conn); params->conn = NULL; } + + /* An explicit connect request is complete once connected, so + * clean it up here: hci_connect_le_scan_cleanup() no longer + * finds the params since they have just been removed from + * pend_le_conns. + */ + if (params->explicit_connect) { + params->explicit_connect = false; + + switch (params->auto_connect) { + case HCI_AUTO_CONN_EXPLICIT: + hci_conn_params_del(hdev, &conn->dst, + conn->dst_type); + break; + case HCI_AUTO_CONN_REPORT: + hci_pend_le_list_add(params, + &hdev->pend_le_reports); + break; + default: + break; + } + } } /* If we are central and have subrate parameters stored, queue a From 1eebde8ecede18e351ccf438f17b53d3b62a75a9 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Fri, 23 Oct 2026 17:19:10 -0400 Subject: [PATCH 10/30] Bluetooth: hci_core: Convert hci_conn flags to a bitmap struct hci_conn stores its flags in a single unsigned long, but the HCI_CONN_* enum already has 33 entries (up to HCI_CONN_PA_SYNC_FAILED = 32), so on 32-bit architectures set_bit()/test_bit() on the highest flags access memory past the flags field, aliasing the adjacent conn_reason field. Fix this by declaring flags with DECLARE_BITMAP() sized by a new __HCI_CONN_NUM_FLAGS terminator so it can accommodate any number of flags. Assisted-by: OpenCode:claude-opus-5.5 Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci_core.h | 101 ++++++++++---------- net/bluetooth/hci_conn.c | 87 +++++++++--------- net/bluetooth/hci_event.c | 152 +++++++++++++++---------------- net/bluetooth/hci_sync.c | 36 ++++---- net/bluetooth/iso.c | 20 ++-- net/bluetooth/l2cap_core.c | 2 +- net/bluetooth/mgmt.c | 20 ++-- net/bluetooth/smp.c | 24 ++--- 8 files changed, 221 insertions(+), 221 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index aa04dec45153..1991de9eafca 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -680,6 +680,44 @@ enum conn_reasons { CONN_REASON_ISO_CONNECT, }; +enum { + HCI_CONN_AUTH_PEND, + HCI_CONN_ENCRYPT_PEND, + HCI_CONN_RSWITCH_PEND, + HCI_CONN_MODE_CHANGE_PEND, + HCI_CONN_SCO_SETUP_PEND, + HCI_CONN_MGMT_CONNECTED, + HCI_CONN_SSP_ENABLED, + HCI_CONN_SC_ENABLED, + HCI_CONN_AES_CCM, + HCI_CONN_POWER_SAVE, + HCI_CONN_FLUSH_KEY, + HCI_CONN_ENCRYPT, + HCI_CONN_AUTH, + HCI_CONN_SECURE, + HCI_CONN_FIPS, + HCI_CONN_STK_ENCRYPT, + HCI_CONN_AUTH_INITIATOR, + HCI_CONN_DROP, + HCI_CONN_CANCEL, + HCI_CONN_PARAM_REMOVAL_PEND, + HCI_CONN_NEW_LINK_KEY, + HCI_CONN_SCANNING, + HCI_CONN_AUTH_FAILURE, + HCI_CONN_PER_ADV, + HCI_CONN_BIG_CREATED, + HCI_CONN_CREATE, + HCI_CONN_CREATE_CIS, + HCI_CONN_CREATE_BIG_SYNC, + HCI_CONN_BIG_SYNC, + HCI_CONN_BIG_SYNC_FAILED, + HCI_CONN_CREATE_PA_SYNC, + HCI_CONN_PA_SYNC, + HCI_CONN_PA_SYNC_FAILED, + + __HCI_CONN_NUM_FLAGS, +}; + struct hci_conn { struct list_head list; @@ -750,7 +788,7 @@ struct hci_conn { __u8 num_bis; __u8 bis[HCI_MAX_ISO_BIS]; - unsigned long flags; + DECLARE_BITMAP(flags, __HCI_CONN_NUM_FLAGS); enum conn_reasons conn_reason; __u8 abort_reason; @@ -980,55 +1018,18 @@ u32 hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, bool name_known); void hci_inquiry_cache_flush(struct hci_dev *hdev); -/* ----- HCI Connections ----- */ -enum { - HCI_CONN_AUTH_PEND, - HCI_CONN_ENCRYPT_PEND, - HCI_CONN_RSWITCH_PEND, - HCI_CONN_MODE_CHANGE_PEND, - HCI_CONN_SCO_SETUP_PEND, - HCI_CONN_MGMT_CONNECTED, - HCI_CONN_SSP_ENABLED, - HCI_CONN_SC_ENABLED, - HCI_CONN_AES_CCM, - HCI_CONN_POWER_SAVE, - HCI_CONN_FLUSH_KEY, - HCI_CONN_ENCRYPT, - HCI_CONN_AUTH, - HCI_CONN_SECURE, - HCI_CONN_FIPS, - HCI_CONN_STK_ENCRYPT, - HCI_CONN_AUTH_INITIATOR, - HCI_CONN_DROP, - HCI_CONN_CANCEL, - HCI_CONN_PARAM_REMOVAL_PEND, - HCI_CONN_NEW_LINK_KEY, - HCI_CONN_SCANNING, - HCI_CONN_AUTH_FAILURE, - HCI_CONN_PER_ADV, - HCI_CONN_BIG_CREATED, - HCI_CONN_CREATE, - HCI_CONN_CREATE_CIS, - HCI_CONN_CREATE_BIG_SYNC, - HCI_CONN_BIG_SYNC, - HCI_CONN_BIG_SYNC_FAILED, - HCI_CONN_CREATE_PA_SYNC, - HCI_CONN_PA_SYNC, - HCI_CONN_PA_SYNC_FAILED, -}; - static inline bool hci_conn_ssp_enabled(struct hci_conn *conn) { struct hci_dev *hdev = conn->hdev; return hci_dev_test_flag(hdev, HCI_SSP_ENABLED) && - test_bit(HCI_CONN_SSP_ENABLED, &conn->flags); + test_bit(HCI_CONN_SSP_ENABLED, conn->flags); } static inline bool hci_conn_sc_enabled(struct hci_conn *conn) { struct hci_dev *hdev = conn->hdev; return hci_dev_test_flag(hdev, HCI_SC_ENABLED) && - test_bit(HCI_CONN_SC_ENABLED, &conn->flags); + test_bit(HCI_CONN_SC_ENABLED, conn->flags); } static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) @@ -1219,7 +1220,7 @@ hci_conn_hash_lookup_create_pa_sync(struct hci_dev *hdev) if (c->type != PA_LINK) continue; - if (!test_bit(HCI_CONN_CREATE_PA_SYNC, &c->flags)) + if (!test_bit(HCI_CONN_CREATE_PA_SYNC, c->flags)) continue; rcu_read_unlock(); @@ -1245,7 +1246,7 @@ hci_conn_hash_lookup_per_adv_bis(struct hci_dev *hdev, list_for_each_entry_rcu(c, &h->list, list) { if (bacmp(&c->dst, ba) || c->type != BIS_LINK || - !test_bit(HCI_CONN_PER_ADV, &c->flags)) + !test_bit(HCI_CONN_PER_ADV, c->flags)) continue; if (c->iso_qos.bcast.big == big && @@ -1502,7 +1503,7 @@ hci_conn_hash_lookup_pa_sync_big_handle(struct hci_dev *hdev, __u8 big) list_for_each_entry_rcu(c, &h->list, list) { if (c->type != BIS_LINK || - !test_bit(HCI_CONN_PA_SYNC, &c->flags)) + !test_bit(HCI_CONN_PA_SYNC, c->flags)) continue; if (c->iso_qos.bcast.big == big) { @@ -1580,7 +1581,7 @@ static inline void hci_conn_hash_list_flag(struct hci_dev *hdev, rcu_read_lock(); list_for_each_entry_rcu(c, &h->list, list) { - if (c->type == type && test_bit(flag, &c->flags)) + if (c->type == type && test_bit(flag, c->flags)) func(c, data); } @@ -1598,7 +1599,7 @@ static inline struct hci_conn *hci_lookup_le_connect(struct hci_dev *hdev) list_for_each_entry_rcu(c, &h->list, list) { if (c->type == LE_LINK && c->state == BT_CONNECT && - !test_bit(HCI_CONN_SCANNING, &c->flags)) { + !test_bit(HCI_CONN_SCANNING, c->flags)) { rcu_read_unlock(); return c; } @@ -1619,7 +1620,7 @@ static inline bool hci_is_le_conn_scanning(struct hci_dev *hdev) list_for_each_entry_rcu(c, &h->list, list) { if (c->type == LE_LINK && c->state == BT_CONNECT && - test_bit(HCI_CONN_SCANNING, &c->flags)) { + test_bit(HCI_CONN_SCANNING, c->flags)) { rcu_read_unlock(); return true; } @@ -2239,10 +2240,10 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status) struct hci_cb *cb; __u8 encrypt; - if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) + if (test_bit(HCI_CONN_ENCRYPT_PEND, conn->flags)) return; - encrypt = test_bit(HCI_CONN_ENCRYPT, &conn->flags) ? 0x01 : 0x00; + encrypt = test_bit(HCI_CONN_ENCRYPT, conn->flags) ? 0x01 : 0x00; mutex_lock(&hci_cb_list_lock); list_for_each_entry(cb, &hci_cb_list, list) { @@ -2271,9 +2272,9 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status) return; } - if (!test_bit(HCI_CONN_ENCRYPT, &conn->flags)) + if (!test_bit(HCI_CONN_ENCRYPT, conn->flags)) encrypt = 0x00; - else if (test_bit(HCI_CONN_AES_CCM, &conn->flags)) + else if (test_bit(HCI_CONN_AES_CCM, conn->flags)) encrypt = 0x02; else encrypt = 0x01; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 5de95408e6e3..b007f623b2ec 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -138,10 +138,10 @@ static void hci_conn_cleanup(struct hci_conn *conn) { struct hci_dev *hdev = conn->hdev; - if (test_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags)) + if (test_bit(HCI_CONN_PARAM_REMOVAL_PEND, conn->flags)) hci_conn_params_del(conn->hdev, &conn->dst, conn->dst_type); - if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags)) + if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, conn->flags)) hci_remove_link_key(hdev, &conn->dst); hci_chan_list_flush(conn); @@ -685,7 +685,7 @@ static void hci_conn_idle(struct work_struct *work) hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp); } - if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) { + if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, conn->flags)) { struct hci_cp_sniff_mode cp; cp.handle = cpu_to_le16(conn->handle); cp.max_interval = cpu_to_le16(hdev->sniff_max_interval); @@ -814,7 +814,7 @@ static int hci_le_terminate_big(struct hci_dev *hdev, struct hci_conn *conn) d->big = conn->iso_qos.bcast.big; d->bis = conn->iso_qos.bcast.bis; - d->big_term = test_and_clear_bit(HCI_CONN_BIG_CREATED, &conn->flags); + d->big_term = test_and_clear_bit(HCI_CONN_BIG_CREATED, conn->flags); ret = hci_cmd_sync_queue(hdev, terminate_big_sync, d, terminate_big_destroy); @@ -867,7 +867,7 @@ static int hci_le_big_terminate(struct hci_dev *hdev, struct hci_conn *conn) d->sync_handle = conn->sync_handle; if (conn->type == PA_LINK && - test_and_clear_bit(HCI_CONN_PA_SYNC, &conn->flags)) { + test_and_clear_bit(HCI_CONN_PA_SYNC, conn->flags)) { hci_conn_hash_list_flag(hdev, find_bis, PA_LINK, HCI_CONN_PA_SYNC, d); @@ -877,7 +877,7 @@ static int hci_le_big_terminate(struct hci_dev *hdev, struct hci_conn *conn) d->count = 0; } - if (test_and_clear_bit(HCI_CONN_BIG_SYNC, &conn->flags)) { + if (test_and_clear_bit(HCI_CONN_BIG_SYNC, conn->flags)) { hci_conn_hash_list_flag(hdev, find_bis, BIS_LINK, HCI_CONN_BIG_SYNC, d); @@ -912,7 +912,7 @@ static void bis_cleanup(struct hci_conn *conn) bt_dev_dbg(hdev, "conn %p", conn); if (conn->role == HCI_ROLE_MASTER) { - if (!test_and_clear_bit(HCI_CONN_PER_ADV, &conn->flags)) + if (!test_and_clear_bit(HCI_CONN_PER_ADV, conn->flags)) return; /* Check if ISO connection is a BIS and terminate advertising @@ -1087,7 +1087,7 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, conn->sync_handle = HCI_SYNC_HANDLE_INVALID; conn->sid = HCI_SID_INVALID; - set_bit(HCI_CONN_POWER_SAVE, &conn->flags); + set_bit(HCI_CONN_POWER_SAVE, conn->flags); conn->disc_timeout = HCI_DISCONN_TIMEOUT; /* Set Default Authenticated payload timeout to 30s */ @@ -1217,8 +1217,8 @@ static void hci_conn_cleanup_child(struct hci_conn *conn, u8 reason) case BIS_LINK: case PA_LINK: if ((conn->state != BT_CONNECTED && - !test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) || - test_bit(HCI_CONN_BIG_CREATED, &conn->flags)) + !test_bit(HCI_CONN_CREATE_CIS, conn->flags)) || + test_bit(HCI_CONN_BIG_CREATED, conn->flags)) hci_conn_failed(conn, reason); break; } @@ -1234,8 +1234,8 @@ static void hci_conn_unlink(struct hci_conn *conn) struct hci_link *link, *t; conn->sec_level = BT_SECURITY_SDP; - clear_bit(HCI_CONN_ENCRYPT, &conn->flags); - clear_bit(HCI_CONN_AES_CCM, &conn->flags); + clear_bit(HCI_CONN_ENCRYPT, conn->flags); + clear_bit(HCI_CONN_AES_CCM, conn->flags); /* mgmt_security_level_changed() reports the reset only if * this connection was actually reported to userspace as * connected (it checks HCI_CONN_MGMT_CONNECTED itself), so it @@ -1254,7 +1254,7 @@ static void hci_conn_unlink(struct hci_conn *conn) */ if (test_bit(HCI_UP, &hdev->flags)) mgmt_security_level_changed(conn); - clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags); + clear_bit(HCI_CONN_MGMT_CONNECTED, conn->flags); list_for_each_entry_safe(link, t, &conn->link_list, list) { struct hci_conn *child = link->conn; @@ -1458,8 +1458,8 @@ void hci_conn_failed(struct hci_conn *conn, u8 status) /* In case of BIG/PA sync failed, clear conn flags so that * the conns will be correctly cleaned up by ISO layer */ - test_and_clear_bit(HCI_CONN_BIG_SYNC_FAILED, &conn->flags); - test_and_clear_bit(HCI_CONN_PA_SYNC_FAILED, &conn->flags); + test_and_clear_bit(HCI_CONN_BIG_SYNC_FAILED, conn->flags); + test_and_clear_bit(HCI_CONN_PA_SYNC_FAILED, conn->flags); conn->state = BT_CLOSED; hci_connect_cfm(conn, status); @@ -1524,9 +1524,8 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, * to connect. */ conn = hci_conn_hash_lookup_le(hdev, dst, dst_type); - if (conn && !test_bit(HCI_CONN_SCANNING, &conn->flags)) { + if (conn && !test_bit(HCI_CONN_SCANNING, conn->flags)) return ERR_PTR(-EBUSY); - } /* Check if the destination address has been resolved by the controller * since if it did then the identity address shall be used. @@ -1798,7 +1797,7 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst, } conn->state = BT_CONNECT; - set_bit(HCI_CONN_SCANNING, &conn->flags); + set_bit(HCI_CONN_SCANNING, conn->flags); conn->sec_level = BT_SECURITY_LOW; conn->pending_sec_level = sec_level; conn->conn_timeout = conn_timeout; @@ -1924,12 +1923,12 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, if (acl->state == BT_CONNECTED && (sco->state == BT_OPEN || sco->state == BT_CLOSED)) { - set_bit(HCI_CONN_POWER_SAVE, &acl->flags); + set_bit(HCI_CONN_POWER_SAVE, acl->flags); hci_conn_enter_active_mode(acl, BT_POWER_FORCE_ACTIVE_ON); - if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->flags)) { + if (test_bit(HCI_CONN_MODE_CHANGE_PEND, acl->flags)) { /* defer SCO setup until mode change completed */ - set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->flags); + set_bit(HCI_CONN_SCO_SETUP_PEND, acl->flags); return sco; } @@ -2221,7 +2220,7 @@ int hci_le_create_cis_pending(struct hci_dev *hdev) rcu_read_lock(); list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) { - if (test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) { + if (test_bit(HCI_CONN_CREATE_CIS, conn->flags)) { rcu_read_unlock(); return -EBUSY; } @@ -2449,7 +2448,7 @@ static void bis_mark_per_adv(struct hci_conn *conn, void *data) d->bis != conn->iso_qos.bcast.bis) return; - set_bit(HCI_CONN_PER_ADV, &conn->flags); + set_bit(HCI_CONN_PER_ADV, conn->flags); } struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, @@ -2569,7 +2568,7 @@ int hci_conn_check_link_mode(struct hci_conn *conn) */ if (hci_dev_test_flag(conn->hdev, HCI_SC_ONLY)) { if (!hci_conn_sc_enabled(conn) || - !test_bit(HCI_CONN_AES_CCM, &conn->flags) || + !test_bit(HCI_CONN_AES_CCM, conn->flags) || conn->key_type != HCI_LK_AUTH_COMBINATION_P256) return 0; } @@ -2585,14 +2584,14 @@ int hci_conn_check_link_mode(struct hci_conn *conn) * not shortened) */ if (conn->sec_level == BT_SECURITY_FIPS && - !test_bit(HCI_CONN_AES_CCM, &conn->flags)) { + !test_bit(HCI_CONN_AES_CCM, conn->flags)) { bt_dev_err(conn->hdev, "Invalid security: Missing AES-CCM usage"); return 0; } if (hci_conn_ssp_enabled(conn) && - !test_bit(HCI_CONN_ENCRYPT, &conn->flags)) + !test_bit(HCI_CONN_ENCRYPT, conn->flags)) return 0; return 1; @@ -2608,7 +2607,7 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) if (sec_level > conn->sec_level) conn->pending_sec_level = sec_level; - else if (test_bit(HCI_CONN_AUTH, &conn->flags)) + else if (test_bit(HCI_CONN_AUTH, conn->flags)) return 1; /* Make sure we preserve an existing MITM requirement*/ @@ -2616,7 +2615,7 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) conn->auth_type = auth_type; - if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, conn->flags)) { struct hci_cp_auth_requested cp; cp.handle = cpu_to_le16(conn->handle); @@ -2626,8 +2625,8 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) /* Set the ENCRYPT_PEND to trigger encryption after * authentication. */ - if (!test_bit(HCI_CONN_ENCRYPT, &conn->flags)) - set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); + if (!test_bit(HCI_CONN_ENCRYPT, conn->flags)) + set_bit(HCI_CONN_ENCRYPT_PEND, conn->flags); } return 0; @@ -2638,7 +2637,7 @@ static void hci_conn_encrypt(struct hci_conn *conn) { BT_DBG("hcon %p", conn); - if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) { + if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, conn->flags)) { struct hci_cp_set_conn_encrypt cp; cp.handle = cpu_to_le16(conn->handle); cp.encrypt = 0x01; @@ -2666,7 +2665,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type, return 1; /* For other security levels we need the link key. */ - if (!test_bit(HCI_CONN_AUTH, &conn->flags)) + if (!test_bit(HCI_CONN_AUTH, conn->flags)) goto auth; switch (conn->key_type) { @@ -2706,17 +2705,17 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type, } auth: - if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) + if (test_bit(HCI_CONN_ENCRYPT_PEND, conn->flags)) return 0; if (initiator) - set_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags); + set_bit(HCI_CONN_AUTH_INITIATOR, conn->flags); if (!hci_conn_auth(conn, sec_level, auth_type)) return 0; encrypt: - if (test_bit(HCI_CONN_ENCRYPT, &conn->flags)) { + if (test_bit(HCI_CONN_ENCRYPT, conn->flags)) { /* Ensure that the encryption key size has been read, * otherwise stall the upper layer responses. */ @@ -2759,7 +2758,7 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role) if (role == conn->role) return 1; - if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->flags)) { + if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, conn->flags)) { struct hci_cp_switch_role cp; bacpy(&cp.bdaddr, &conn->dst); cp.role = role; @@ -2780,10 +2779,10 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active) if (conn->mode != HCI_CM_SNIFF) goto timer; - if (!test_bit(HCI_CONN_POWER_SAVE, &conn->flags) && !force_active) + if (!test_bit(HCI_CONN_POWER_SAVE, conn->flags) && !force_active) goto timer; - if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) { + if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, conn->flags)) { struct hci_cp_exit_sniff_mode cp; cp.handle = cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_EXIT_SNIFF_MODE, sizeof(cp), &cp); @@ -2823,16 +2822,16 @@ static u32 get_link_mode(struct hci_conn *conn) if (conn->role == HCI_ROLE_MASTER) link_mode |= HCI_LM_MASTER; - if (test_bit(HCI_CONN_ENCRYPT, &conn->flags)) + if (test_bit(HCI_CONN_ENCRYPT, conn->flags)) link_mode |= HCI_LM_ENCRYPT; - if (test_bit(HCI_CONN_AUTH, &conn->flags)) + if (test_bit(HCI_CONN_AUTH, conn->flags)) link_mode |= HCI_LM_AUTH; - if (test_bit(HCI_CONN_SECURE, &conn->flags)) + if (test_bit(HCI_CONN_SECURE, conn->flags)) link_mode |= HCI_LM_SECURE; - if (test_bit(HCI_CONN_FIPS, &conn->flags)) + if (test_bit(HCI_CONN_FIPS, conn->flags)) link_mode |= HCI_LM_FIPS; return link_mode; @@ -2946,7 +2945,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn) BT_DBG("%s hcon %p", hdev->name, conn); - if (test_bit(HCI_CONN_DROP, &conn->flags)) { + if (test_bit(HCI_CONN_DROP, conn->flags)) { BT_DBG("Refusing to create new hci_chan"); return NULL; } @@ -2976,7 +2975,7 @@ void hci_chan_del(struct hci_chan *chan) synchronize_rcu(); /* Prevent new hci_chan's to be created for this hci_conn */ - set_bit(HCI_CONN_DROP, &conn->flags); + set_bit(HCI_CONN_DROP, conn->flags); hci_conn_put(conn); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index dede0b686c13..ab8a0b1ab9a8 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -732,8 +732,8 @@ static u8 hci_cc_read_enc_key_size(struct hci_dev *hdev, void *data, bt_dev_err(hdev, "failed to read key size for handle %u", handle); conn->enc_key_size = 0; - clear_bit(HCI_CONN_ENCRYPT, &conn->flags); - clear_bit(HCI_CONN_AES_CCM, &conn->flags); + clear_bit(HCI_CONN_ENCRYPT, conn->flags); + clear_bit(HCI_CONN_AES_CCM, conn->flags); /* Downgrade to reflect the connection no longer being * encrypted, instead of advertising a stale elevated * security level alongside MGMT_CONN_SEC_ENCRYPT_NONE. @@ -761,8 +761,8 @@ static u8 hci_cc_read_enc_key_size(struct hci_dev *hdev, void *data, * state at a later time. */ status = HCI_ERROR_AUTH_FAILURE; - clear_bit(HCI_CONN_ENCRYPT, &conn->flags); - clear_bit(HCI_CONN_AES_CCM, &conn->flags); + clear_bit(HCI_CONN_ENCRYPT, conn->flags); + clear_bit(HCI_CONN_AES_CCM, conn->flags); /* Downgrade to reflect the connection no longer being * encrypted, instead of advertising a stale elevated * security level alongside MGMT_CONN_SEC_ENCRYPT_NONE. @@ -2595,10 +2595,10 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) if (!hci_outgoing_auth_needed(hdev, conn)) goto unlock; - if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, conn->flags)) { struct hci_cp_auth_requested auth_cp; - set_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags); + set_bit(HCI_CONN_AUTH_INITIATOR, conn->flags); auth_cp.handle = __cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, @@ -2738,9 +2738,9 @@ static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status) conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); if (conn) { - clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags); + clear_bit(HCI_CONN_MODE_CHANGE_PEND, conn->flags); - if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags)) + if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, conn->flags)) hci_sco_setup(conn, status); } @@ -2765,9 +2765,9 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status) conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); if (conn) { - clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags); + clear_bit(HCI_CONN_MODE_CHANGE_PEND, conn->flags); - if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags)) + if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, conn->flags)) hci_sco_setup(conn, status); } @@ -2824,10 +2824,10 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status) * still needs it set to know whether to report the security level * reset, so it is consumed there instead of here. */ - mgmt_conn = test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags); + mgmt_conn = test_bit(HCI_CONN_MGMT_CONNECTED, conn->flags); if (conn->type == ACL_LINK) { - if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags)) + if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, conn->flags)) hci_remove_link_key(hdev, &conn->dst); } @@ -3078,7 +3078,7 @@ static void hci_cs_switch_role(struct hci_dev *hdev, u8 status) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); if (conn) - clear_bit(HCI_CONN_RSWITCH_PEND, &conn->flags); + clear_bit(HCI_CONN_RSWITCH_PEND, conn->flags); hci_dev_unlock(hdev); } @@ -3309,19 +3309,19 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data, hci_conn_add_sysfs(conn); if (test_bit(HCI_AUTH, &hdev->flags)) - set_bit(HCI_CONN_AUTH, &conn->flags); + set_bit(HCI_CONN_AUTH, conn->flags); if (test_bit(HCI_ENCRYPT, &hdev->flags)) - set_bit(HCI_CONN_ENCRYPT, &conn->flags); + set_bit(HCI_CONN_ENCRYPT, conn->flags); /* "Link key request" completed ahead of "connect request" completes */ - if (ev->encr_mode == 1 && !test_bit(HCI_CONN_ENCRYPT, &conn->flags) && + if (ev->encr_mode == 1 && !test_bit(HCI_CONN_ENCRYPT, conn->flags) && ev->link_type == ACL_LINK) { struct link_key *key; key = hci_find_link_key(hdev, &ev->bdaddr); if (key) { - set_bit(HCI_CONN_ENCRYPT, &conn->flags); + set_bit(HCI_CONN_ENCRYPT, conn->flags); hci_read_enc_key_size(hdev, conn); hci_encrypt_cfm(conn, ev->status); } @@ -3525,9 +3525,9 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, void *data, * still needs it set to know whether to report the security level * reset, so it is consumed there instead of here. */ - mgmt_connected = test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags); + mgmt_connected = test_bit(HCI_CONN_MGMT_CONNECTED, conn->flags); - if (test_bit(HCI_CONN_AUTH_FAILURE, &conn->flags)) + if (test_bit(HCI_CONN_AUTH_FAILURE, conn->flags)) reason = MGMT_DEV_DISCONN_AUTH_FAILURE; else reason = hci_to_mgmt_reason(ev->reason); @@ -3536,7 +3536,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, void *data, reason, mgmt_connected); if (conn->type == ACL_LINK) { - if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags)) + if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, conn->flags)) hci_remove_link_key(hdev, &conn->dst); hci_update_scan(hdev); @@ -3607,8 +3607,8 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, void *data, goto unlock; if (!ev->status) { - clear_bit(HCI_CONN_AUTH_FAILURE, &conn->flags); - set_bit(HCI_CONN_AUTH, &conn->flags); + clear_bit(HCI_CONN_AUTH_FAILURE, conn->flags); + set_bit(HCI_CONN_AUTH, conn->flags); /* Authentication alone does not imply encryption: for SSP * capable devices, encryption is only requested below, and * for legacy devices it is requested by a separate @@ -3621,12 +3621,12 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, void *data, conn->sec_level = conn->pending_sec_level; } else { if (ev->status == HCI_ERROR_PIN_OR_KEY_MISSING) - set_bit(HCI_CONN_AUTH_FAILURE, &conn->flags); + set_bit(HCI_CONN_AUTH_FAILURE, conn->flags); mgmt_auth_failed(conn, ev->status); } - clear_bit(HCI_CONN_AUTH_PEND, &conn->flags); + clear_bit(HCI_CONN_AUTH_PEND, conn->flags); if (conn->state == BT_CONFIG) { if (!ev->status && hci_conn_ssp_enabled(conn)) { @@ -3648,7 +3648,7 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, void *data, hci_conn_drop(conn); } - if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) { + if (test_bit(HCI_CONN_ENCRYPT_PEND, conn->flags)) { if (!ev->status) { struct hci_cp_set_conn_encrypt cp; cp.handle = ev->handle; @@ -3656,7 +3656,7 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, void *data, hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp); } else { - clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); + clear_bit(HCI_CONN_ENCRYPT_PEND, conn->flags); hci_encrypt_cfm(conn, ev->status); } } @@ -3693,10 +3693,10 @@ static void hci_remote_name_evt(struct hci_dev *hdev, void *data, if (!hci_outgoing_auth_needed(hdev, conn)) goto unlock; - if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, conn->flags)) { struct hci_cp_auth_requested cp; - set_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags); + set_bit(HCI_CONN_AUTH_INITIATOR, conn->flags); cp.handle = __cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); @@ -3723,17 +3723,17 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data, if (!ev->status) { if (ev->encrypt) { /* Encryption implies authentication */ - set_bit(HCI_CONN_AUTH, &conn->flags); - set_bit(HCI_CONN_ENCRYPT, &conn->flags); + set_bit(HCI_CONN_AUTH, conn->flags); + set_bit(HCI_CONN_ENCRYPT, conn->flags); conn->sec_level = conn->pending_sec_level; /* P-256 authentication key implies FIPS */ if (conn->key_type == HCI_LK_AUTH_COMBINATION_P256) - set_bit(HCI_CONN_FIPS, &conn->flags); + set_bit(HCI_CONN_FIPS, conn->flags); if ((conn->type == ACL_LINK && ev->encrypt == 0x02) || conn->type == LE_LINK) - set_bit(HCI_CONN_AES_CCM, &conn->flags); + set_bit(HCI_CONN_AES_CCM, conn->flags); /* For ACL links the encryption key size is still * validated below via hci_read_enc_key_size(). Its @@ -3745,8 +3745,8 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data, if (conn->type != ACL_LINK) mgmt_security_level_changed(conn); } else { - clear_bit(HCI_CONN_ENCRYPT, &conn->flags); - clear_bit(HCI_CONN_AES_CCM, &conn->flags); + clear_bit(HCI_CONN_ENCRYPT, conn->flags); + clear_bit(HCI_CONN_AES_CCM, conn->flags); /* Elevated security levels (MEDIUM and above) require * encryption, so downgrade to reflect the connection * no longer being encrypted before reporting, instead @@ -3767,7 +3767,7 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data, hci_adv_instances_set_rpa_expired(hdev, true); } - clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); + clear_bit(HCI_CONN_ENCRYPT_PEND, conn->flags); /* Check link security requirements are met */ if (!hci_conn_check_link_mode(conn)) @@ -3775,7 +3775,7 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data, if (ev->status && conn->state == BT_CONNECTED) { if (ev->status == HCI_ERROR_PIN_OR_KEY_MISSING) - set_bit(HCI_CONN_AUTH_FAILURE, &conn->flags); + set_bit(HCI_CONN_AUTH_FAILURE, conn->flags); /* Notify upper layers so they can cleanup before * disconnecting. @@ -3813,8 +3813,8 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data, * type can be either LE or ACL and controller must support LMP Ping. * Ensure for AES-CCM encryption as well. */ - if (test_bit(HCI_CONN_ENCRYPT, &conn->flags) && - test_bit(HCI_CONN_AES_CCM, &conn->flags) && + if (test_bit(HCI_CONN_ENCRYPT, conn->flags) && + test_bit(HCI_CONN_AES_CCM, conn->flags) && ((conn->type == ACL_LINK && lmp_ping_capable(hdev)) || (conn->type == LE_LINK && (hdev->le_features[0] & HCI_LE_PING)))) { struct hci_cp_write_auth_payload_to cp; @@ -3846,9 +3846,9 @@ static void hci_change_link_key_complete_evt(struct hci_dev *hdev, void *data, conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); if (conn) { if (!ev->status) - set_bit(HCI_CONN_SECURE, &conn->flags); + set_bit(HCI_CONN_SECURE, conn->flags); - clear_bit(HCI_CONN_AUTH_PEND, &conn->flags); + clear_bit(HCI_CONN_AUTH_PEND, conn->flags); hci_key_change_cfm(conn, ev->status); } @@ -4074,7 +4074,7 @@ static u8 hci_cc_le_setup_iso_path(struct hci_dev *hdev, void *data, hci_connect_cfm(conn, rp->status); /* Notify device connected in case it is a BIG Sync */ - if (!rp->status && test_bit(HCI_CONN_BIG_SYNC, &conn->flags)) + if (!rp->status && test_bit(HCI_CONN_BIG_SYNC, conn->flags)) mgmt_device_connected(hdev, conn, NULL, 0); break; @@ -4504,7 +4504,7 @@ static void hci_cs_le_create_cis(struct hci_dev *hdev, u8 status) conn = hci_conn_hash_lookup_handle(hdev, handle); if (conn) { if (test_and_clear_bit(HCI_CONN_CREATE_CIS, - &conn->flags)) + conn->flags)) pending = true; conn->state = BT_CLOSED; hci_connect_cfm(conn, status); @@ -4625,7 +4625,7 @@ static void hci_role_change_evt(struct hci_dev *hdev, void *data, if (!ev->status) conn->role = ev->role; - clear_bit(HCI_CONN_RSWITCH_PEND, &conn->flags); + clear_bit(HCI_CONN_RSWITCH_PEND, conn->flags); hci_role_switch_cfm(conn, ev->status, ev->role); } @@ -4737,12 +4737,12 @@ static void hci_mode_change_evt(struct hci_dev *hdev, void *data, conn->mode = ev->mode; if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, - &conn->flags)) { - assign_bit(HCI_CONN_POWER_SAVE, &conn->flags, + conn->flags)) { + assign_bit(HCI_CONN_POWER_SAVE, conn->flags, conn->mode == HCI_CM_ACTIVE); } - if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags)) + if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, conn->flags)) hci_sco_setup(conn, ev->status); } @@ -4770,7 +4770,7 @@ static void hci_pin_code_request_evt(struct hci_dev *hdev, void *data, } if (!hci_dev_test_flag(hdev, HCI_BONDABLE) && - !test_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags)) { + !test_bit(HCI_CONN_AUTH_INITIATOR, conn->flags)) { hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(ev->bdaddr), &ev->bdaddr); } else if (hci_dev_test_flag(hdev, HCI_MGMT)) { @@ -4845,7 +4845,7 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, void *data, conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); if (conn) { - clear_bit(HCI_CONN_NEW_LINK_KEY, &conn->flags); + clear_bit(HCI_CONN_NEW_LINK_KEY, conn->flags); if ((key->type == HCI_LK_UNAUTH_COMBINATION_P192 || key->type == HCI_LK_UNAUTH_COMBINATION_P256) && @@ -4908,7 +4908,7 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, void *data, conn->disc_timeout = HCI_DISCONN_TIMEOUT; hci_conn_drop(conn); - set_bit(HCI_CONN_NEW_LINK_KEY, &conn->flags); + set_bit(HCI_CONN_NEW_LINK_KEY, conn->flags); conn_set_key(conn, ev->key_type, conn->pin_length); if (!hci_dev_test_flag(hdev, HCI_MGMT)) @@ -4939,7 +4939,7 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, void *data, goto unlock; } - assign_bit(HCI_CONN_FLUSH_KEY, &conn->flags, !persistent); + assign_bit(HCI_CONN_FLUSH_KEY, conn->flags, !persistent); unlock: hci_dev_unlock(hdev); @@ -5117,7 +5117,7 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev, void *data, ie->data.ssp_mode = (ev->features[0] & LMP_HOST_SSP); if (ev->features[0] & LMP_HOST_SSP) { - set_bit(HCI_CONN_SSP_ENABLED, &conn->flags); + set_bit(HCI_CONN_SSP_ENABLED, conn->flags); } else { /* It is mandatory by the Bluetooth specification that * Extended Inquiry Results are only used when Secure @@ -5127,17 +5127,17 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev, void *data, * To make these devices work, the internal SSP * enabled flag needs to be cleared if the remote host * features do not indicate SSP support */ - clear_bit(HCI_CONN_SSP_ENABLED, &conn->flags); + clear_bit(HCI_CONN_SSP_ENABLED, conn->flags); } if (ev->features[0] & LMP_HOST_SC) - set_bit(HCI_CONN_SC_ENABLED, &conn->flags); + set_bit(HCI_CONN_SC_ENABLED, conn->flags); } if (conn->state != BT_CONFIG) goto unlock; - if (!ev->status && !test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) { + if (!ev->status && !test_bit(HCI_CONN_MGMT_CONNECTED, conn->flags)) { struct hci_cp_remote_name_req cp; memset(&cp, 0, sizeof(cp)); bacpy(&cp.bdaddr, &conn->dst); @@ -5373,7 +5373,7 @@ static void hci_key_refresh_complete_evt(struct hci_dev *hdev, void *data, mgmt_security_level_changed(conn); } - clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); + clear_bit(HCI_CONN_ENCRYPT_PEND, conn->flags); if (ev->status && conn->state == BT_CONNECTED) { hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE); @@ -5474,7 +5474,7 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, void *data, goto unlock; /* Assume remote supports SSP since it has triggered this event */ - set_bit(HCI_CONN_SSP_ENABLED, &conn->flags); + set_bit(HCI_CONN_SSP_ENABLED, conn->flags); hci_conn_hold(conn); @@ -5485,7 +5485,7 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, void *data, * pairing or if the remote is not requesting bonding. */ if (hci_dev_test_flag(hdev, HCI_BONDABLE) || - test_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags) || + test_bit(HCI_CONN_AUTH_INITIATOR, conn->flags) || (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) { struct hci_cp_io_capability_reply cp; @@ -5595,7 +5595,7 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev, void *data, * local IO capability is not NoInputNoOutput, use JUST_WORKS * method (mgmt_user_confirm with confirm_hint set to 1). */ - if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && + if (!test_bit(HCI_CONN_AUTH_PEND, conn->flags) && conn->io_capability != HCI_IO_NO_INPUT_OUTPUT) { bt_dev_dbg(hdev, "Confirming auto-accept as acceptor"); confirm_hint = 1; @@ -5738,7 +5738,7 @@ static void hci_simple_pair_complete_evt(struct hci_dev *hdev, void *data, * initiated the authentication. A traditional auth_complete * event gets always produced as initiator and is also mapped to * the mgmt_auth_failed event */ - if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status) + if (!test_bit(HCI_CONN_AUTH_PEND, conn->flags) && ev->status) mgmt_auth_failed(conn, ev->status); hci_conn_drop(conn); @@ -5984,7 +5984,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, goto unlock; /* Drop the connection if it has been aborted */ - if (test_bit(HCI_CONN_CANCEL, &conn->flags)) { + if (test_bit(HCI_CONN_CANCEL, conn->flags)) { hci_conn_drop(conn); goto unlock; } @@ -6123,8 +6123,8 @@ static void hci_le_pa_sync_lost_evt(struct hci_dev *hdev, void *data, /* Delete the pa sync connection */ conn = hci_conn_hash_lookup_pa_sync_handle(hdev, handle); if (conn) { - clear_bit(HCI_CONN_BIG_SYNC, &conn->flags); - clear_bit(HCI_CONN_PA_SYNC, &conn->flags); + clear_bit(HCI_CONN_BIG_SYNC, conn->flags); + clear_bit(HCI_CONN_PA_SYNC, conn->flags); hci_disconn_cfm(conn, HCI_ERROR_REMOTE_USER_TERM); hci_conn_del(conn); } @@ -6258,7 +6258,7 @@ static void hci_le_past_received_evt(struct hci_dev *hdev, void *data, pa_sync->sync_handle = le16_to_cpu(ev->sync_handle); if (ev->status) { - set_bit(HCI_CONN_PA_SYNC_FAILED, &pa_sync->flags); + set_bit(HCI_CONN_PA_SYNC_FAILED, pa_sync->flags); /* Notify iso layer */ hci_connect_cfm(pa_sync, ev->status); @@ -6780,7 +6780,7 @@ static void hci_le_pa_sync_established_evt(struct hci_dev *hdev, void *data, goto unlock; } - clear_bit(HCI_CONN_CREATE_PA_SYNC, &conn->flags); + clear_bit(HCI_CONN_CREATE_PA_SYNC, conn->flags); conn->sync_handle = le16_to_cpu(ev->handle); conn->sid = HCI_SID_INVALID; @@ -6805,7 +6805,7 @@ static void hci_le_pa_sync_established_evt(struct hci_dev *hdev, void *data, pa_sync->sync_handle = le16_to_cpu(ev->handle); if (ev->status) { - set_bit(HCI_CONN_PA_SYNC_FAILED, &pa_sync->flags); + set_bit(HCI_CONN_PA_SYNC_FAILED, pa_sync->flags); /* Notify iso layer */ hci_connect_cfm(pa_sync, ev->status); @@ -6849,7 +6849,7 @@ static void hci_le_per_adv_report_evt(struct hci_dev *hdev, void *data, goto unlock; if (ev->data_status == LE_PA_DATA_COMPLETE && - !test_and_set_bit(HCI_CONN_PA_SYNC, &pa_sync->flags)) { + !test_and_set_bit(HCI_CONN_PA_SYNC, pa_sync->flags)) { /* Notify iso layer */ hci_connect_cfm(pa_sync, 0); @@ -6962,11 +6962,11 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, void *data, * using a distributed LTK. */ if (ltk->type == SMP_STK) { - set_bit(HCI_CONN_STK_ENCRYPT, &conn->flags); + set_bit(HCI_CONN_STK_ENCRYPT, conn->flags); list_del_rcu(<k->list); kfree_rcu(ltk, rcu); } else { - clear_bit(HCI_CONN_STK_ENCRYPT, &conn->flags); + clear_bit(HCI_CONN_STK_ENCRYPT, conn->flags); } hci_dev_unlock(hdev); @@ -7162,7 +7162,7 @@ static void hci_le_cis_established_evt(struct hci_dev *hdev, void *data, qos = &conn->iso_qos; - pending = test_and_clear_bit(HCI_CONN_CREATE_CIS, &conn->flags); + pending = test_and_clear_bit(HCI_CONN_CREATE_CIS, conn->flags); /* BLUETOOTH CORE SPECIFICATION Version 5.4 | Vol 6, Part G * page 3075: @@ -7359,7 +7359,7 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data, } conn->state = BT_CONNECTED; - set_bit(HCI_CONN_BIG_CREATED, &conn->flags); + set_bit(HCI_CONN_BIG_CREATED, conn->flags); hci_debugfs_create_conn(conn); hci_conn_add_sysfs(conn); hci_iso_setup_path(conn); @@ -7404,7 +7404,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data, goto unlock; } - clear_bit(HCI_CONN_CREATE_BIG_SYNC, &conn->flags); + clear_bit(HCI_CONN_CREATE_BIG_SYNC, conn->flags); conn->num_bis = 0; memset(conn->bis, 0, sizeof(conn->bis)); @@ -7427,7 +7427,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data, if (ev->status != 0x42) /* Mark PA sync as established */ - set_bit(HCI_CONN_PA_SYNC, &bis->flags); + set_bit(HCI_CONN_PA_SYNC, bis->flags); bis->sync_handle = conn->sync_handle; bis->iso_qos.bcast.big = ev->handle; @@ -7440,7 +7440,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data, if (!ev->status) { bis->state = BT_CONNECTED; - set_bit(HCI_CONN_BIG_SYNC, &bis->flags); + set_bit(HCI_CONN_BIG_SYNC, bis->flags); hci_debugfs_create_conn(bis); hci_conn_add_sysfs(bis); hci_iso_setup_path(bis); @@ -7458,7 +7458,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data, if (!bis) continue; - set_bit(HCI_CONN_BIG_SYNC_FAILED, &bis->flags); + set_bit(HCI_CONN_BIG_SYNC_FAILED, bis->flags); hci_connect_cfm(bis, ev->status); } @@ -7488,13 +7488,13 @@ static void hci_le_big_sync_lost_evt(struct hci_dev *hdev, void *data, * it is consumed there instead of here. */ mgmt_conn = test_bit(HCI_CONN_MGMT_CONNECTED, - &bis->flags); + bis->flags); mgmt_device_disconnected(hdev, &bis->dst, bis->type, bis->dst_type, ev->reason, mgmt_conn); } - clear_bit(HCI_CONN_BIG_SYNC, &bis->flags); + clear_bit(HCI_CONN_BIG_SYNC, bis->flags); hci_disconn_cfm(bis, ev->reason); hci_conn_del(bis); } diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 93dfe2e9bb0e..431c28bd29d8 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -5948,11 +5948,11 @@ static int hci_le_connect_cancel_sync(struct hci_dev *hdev, /* Return reason if scanning since the connection shall probably be * cleanup directly. */ - if (test_bit(HCI_CONN_SCANNING, &conn->flags)) + if (test_bit(HCI_CONN_SCANNING, conn->flags)) return reason; if (conn->role == HCI_ROLE_SLAVE || - test_and_set_bit(HCI_CONN_CANCEL, &conn->flags)) + test_and_set_bit(HCI_CONN_CANCEL, conn->flags)) return 0; return __hci_cmd_sync_status(hdev, HCI_OP_LE_CREATE_CONN_CANCEL, @@ -5974,7 +5974,7 @@ static int hci_connect_cancel_sync(struct hci_dev *hdev, struct hci_conn *conn, * then an HCI_LE_CIS_Established event shall also be sent for * this CIS with the Status Operation Cancelled by Host (0x44). */ - if (test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) + if (test_bit(HCI_CONN_CREATE_CIS, conn->flags)) return hci_disconnect_sync(hdev, conn, reason); /* CIS with no Create CIS sent have nothing to cancel */ @@ -6972,7 +6972,7 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data) bt_dev_dbg(hdev, "conn %p", conn); - clear_bit(HCI_CONN_SCANNING, &conn->flags); + clear_bit(HCI_CONN_SCANNING, conn->flags); conn->state = BT_CONNECT; /* If requested to connect as peripheral use directed advertising */ @@ -7039,7 +7039,7 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data) /* Mark create connection in flight so hci_cancel_connect_sync() can * cancel it while blocking on the connection complete event. */ - set_bit(HCI_CONN_CREATE, &conn->flags); + set_bit(HCI_CONN_CREATE, conn->flags); /* Send command LE Extended Create Connection if supported */ if (use_ext_conn(hdev)) { @@ -7076,7 +7076,7 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data) conn->conn_timeout, NULL); done: - clear_bit(HCI_CONN_CREATE, &conn->flags); + clear_bit(HCI_CONN_CREATE, conn->flags); if (err == -ETIMEDOUT) hci_le_connect_cancel_sync(hdev, conn, 0x00); @@ -7123,7 +7123,7 @@ int hci_le_create_cis_sync(struct hci_dev *hdev) /* Wait until previous Create CIS has completed */ list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) { - if (test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) + if (test_bit(HCI_CONN_CREATE_CIS, conn->flags)) goto done; } @@ -7159,7 +7159,7 @@ int hci_le_create_cis_sync(struct hci_dev *hdev) conn->iso_qos.ucast.cig != cig) continue; - set_bit(HCI_CONN_CREATE_CIS, &conn->flags); + set_bit(HCI_CONN_CREATE_CIS, conn->flags); cis->acl_handle = cpu_to_le16(conn->parent->handle); cis->cis_handle = cpu_to_le16(conn->handle); timeout = conn->conn_timeout; @@ -7362,14 +7362,14 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data) /* Mark create connection in flight so hci_cancel_connect_sync() can * cancel it while blocking on the connection complete event. */ - set_bit(HCI_CONN_CREATE, &conn->flags); + set_bit(HCI_CONN_CREATE, conn->flags); err = __hci_cmd_sync_status_sk(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp, HCI_EV_CONN_COMPLETE, conn->conn_timeout, NULL); - clear_bit(HCI_CONN_CREATE, &conn->flags); + clear_bit(HCI_CONN_CREATE, conn->flags); return err; } @@ -7458,7 +7458,7 @@ static int hci_acl_cancel_create_conn_sync(struct hci_dev *hdev, mutex_lock(&hdev->cmd_sync_work_lock); /* In flight: this connection owns the pending request, cancel it. */ - if (test_bit(HCI_CONN_CREATE, &conn->flags)) { + if (test_bit(HCI_CONN_CREATE, conn->flags)) { hci_cmd_sync_cancel(hdev, ECANCELED); goto unlock; } @@ -7489,7 +7489,7 @@ static int hci_le_cancel_create_conn_sync(struct hci_dev *hdev, */ mutex_lock(&hdev->cmd_sync_work_lock); - if (test_bit(HCI_CONN_CREATE, &conn->flags)) { + if (test_bit(HCI_CONN_CREATE, conn->flags)) { hci_cmd_sync_cancel(hdev, ECANCELED); goto unlock; } @@ -7516,7 +7516,7 @@ static int hci_cis_cancel_create_conn_sync(struct hci_dev *hdev, */ mutex_lock(&hdev->cmd_sync_work_lock); - if (test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) + if (test_bit(HCI_CONN_CREATE_CIS, conn->flags)) hci_cmd_sync_cancel(hdev, ECANCELED); mutex_unlock(&hdev->cmd_sync_work_lock); @@ -7653,7 +7653,7 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err) hci_dev_lock(hdev); if (hci_conn_valid(hdev, conn)) - clear_bit(HCI_CONN_CREATE_PA_SYNC, &conn->flags); + clear_bit(HCI_CONN_CREATE_PA_SYNC, conn->flags); if (!err) goto unlock; @@ -7665,7 +7665,7 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err) if (IS_ERR(pa_sync)) goto unlock; - set_bit(HCI_CONN_PA_SYNC_FAILED, &pa_sync->flags); + set_bit(HCI_CONN_PA_SYNC_FAILED, pa_sync->flags); /* Notify iso layer */ hci_connect_cfm(pa_sync, bt_status(err)); @@ -7738,7 +7738,7 @@ static int hci_le_pa_create_sync(struct hci_dev *hdev, void *data) * program the address in the allow list so PA advertisements can be * received. */ - set_bit(HCI_CONN_CREATE_PA_SYNC, &conn->flags); + set_bit(HCI_CONN_CREATE_PA_SYNC, conn->flags); hci_update_passive_scan_sync(hdev); @@ -7841,7 +7841,7 @@ static void create_big_complete(struct hci_dev *hdev, void *data, int err) if (err == -ECANCELED) goto done; - clear_bit(HCI_CONN_CREATE_BIG_SYNC, &conn->flags); + clear_bit(HCI_CONN_CREATE_BIG_SYNC, conn->flags); done: hci_conn_put(conn); @@ -7858,7 +7858,7 @@ static int hci_le_big_create_sync(struct hci_dev *hdev, void *data) if (!hci_conn_valid(hdev, conn)) return -ECANCELED; - set_bit(HCI_CONN_CREATE_BIG_SYNC, &conn->flags); + set_bit(HCI_CONN_CREATE_BIG_SYNC, conn->flags); memset(cp, 0, sizeof(*cp)); cp->handle = qos->bcast.big; diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index c1fdd9846eeb..06f1e7ba2cb1 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -912,7 +912,7 @@ static void iso_sock_disconn(struct sock *sk) struct sock *bis_sk; struct hci_conn *hcon = iso_pi(sk)->conn->hcon; - if (test_bit(HCI_CONN_BIG_CREATED, &hcon->flags)) { + if (test_bit(HCI_CONN_BIG_CREATED, hcon->flags)) { bis_sk = iso_get_sock_big(sk, &iso_pi(sk)->src, &iso_pi(sk)->dst, iso_pi(sk)->qos.bcast.big); @@ -957,8 +957,8 @@ static void __iso_sock_close(struct sock *sk) case BT_CONNECT2: if (iso_pi(sk)->conn->hcon && - (test_bit(HCI_CONN_PA_SYNC, &iso_pi(sk)->conn->hcon->flags) || - test_bit(HCI_CONN_PA_SYNC_FAILED, &iso_pi(sk)->conn->hcon->flags))) + (test_bit(HCI_CONN_PA_SYNC, iso_pi(sk)->conn->hcon->flags) || + test_bit(HCI_CONN_PA_SYNC_FAILED, iso_pi(sk)->conn->hcon->flags))) iso_sock_disconn(sk); else iso_chan_del(sk, ECONNRESET); @@ -2289,7 +2289,7 @@ static void iso_conn_ready(struct iso_conn *conn) hdev = hcon->hdev; - if (test_bit(HCI_CONN_BIG_SYNC, &hcon->flags)) { + if (test_bit(HCI_CONN_BIG_SYNC, hcon->flags)) { /* A BIS slave hcon is notified to the ISO layer * after the Command Complete for the LE Setup * ISO Data Path command is received. Get the @@ -2298,7 +2298,7 @@ static void iso_conn_ready(struct iso_conn *conn) parent = iso_get_sock(hdev, &hcon->src, &hcon->dst, BT_LISTEN, iso_match_big_hcon, hcon); - } else if (test_bit(HCI_CONN_BIG_SYNC_FAILED, &hcon->flags)) { + } else if (test_bit(HCI_CONN_BIG_SYNC_FAILED, hcon->flags)) { ev = hci_recv_event_data(hcon->hdev, HCI_EVT_LE_BIG_SYNC_ESTABLISHED); @@ -2312,7 +2312,7 @@ static void iso_conn_ready(struct iso_conn *conn) &hcon->dst, BT_LISTEN, iso_match_big, ev); - } else if (test_bit(HCI_CONN_PA_SYNC_FAILED, &hcon->flags)) { + } else if (test_bit(HCI_CONN_PA_SYNC_FAILED, hcon->flags)) { ev2 = hci_recv_event_data(hcon->hdev, HCI_EV_LE_PA_SYNC_ESTABLISHED); if (ev2) @@ -2320,7 +2320,7 @@ static void iso_conn_ready(struct iso_conn *conn) &hcon->dst, BT_LISTEN, iso_match_sid, ev2); - } else if (test_bit(HCI_CONN_PA_SYNC, &hcon->flags)) { + } else if (test_bit(HCI_CONN_PA_SYNC, hcon->flags)) { ev3 = hci_recv_event_data(hcon->hdev, HCI_EV_LE_PER_ADV_REPORT); if (ev3) @@ -2376,7 +2376,7 @@ static void iso_conn_ready(struct iso_conn *conn) hcon->dst_type = le_addr_type(iso_pi(parent)->dst_type); } - if (test_bit(HCI_CONN_PA_SYNC, &hcon->flags)) { + if (test_bit(HCI_CONN_PA_SYNC, hcon->flags)) { iso_pi(sk)->qos = iso_pi(parent)->qos; hcon->iso_qos = iso_pi(sk)->qos; iso_pi(sk)->bc_sid = iso_pi(parent)->bc_sid; @@ -2676,8 +2676,8 @@ static void iso_connect_cfm(struct hci_conn *hcon, __u8 status) * into the accept queue of the listening socket and wake up * userspace, to inform the user about the event. */ - if (!status || test_bit(HCI_CONN_BIG_SYNC_FAILED, &hcon->flags) || - test_bit(HCI_CONN_PA_SYNC_FAILED, &hcon->flags)) { + if (!status || test_bit(HCI_CONN_BIG_SYNC_FAILED, hcon->flags) || + test_bit(HCI_CONN_PA_SYNC_FAILED, hcon->flags)) { struct iso_conn *conn; conn = iso_conn_add(hcon); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 4dd56e0074fd..f4e93100e5d5 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1575,7 +1575,7 @@ static bool l2cap_check_enc_key_size(struct hci_conn *hcon, if (chan->sec_level == BT_SECURITY_FIPS) min_key_size = 16; - return (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags) || + return (!test_bit(HCI_CONN_ENCRYPT, hcon->flags) || hcon->enc_key_size >= min_key_size); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3b9c82bd2f02..188c719c50ad 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3241,7 +3241,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, /* Defer clearing up the connection parameters until closing to * give a chance of keeping them if a repairing happens. */ - set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags); + set_bit(HCI_CONN_PARAM_REMOVAL_PEND, conn->flags); /* Disable auto-connection parameters if present */ params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type); @@ -3416,7 +3416,7 @@ static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data, i = 0; list_for_each_entry(c, &hdev->conn_hash.list, list) { - if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags)) + if (test_bit(HCI_CONN_MGMT_CONNECTED, c->flags)) i++; } @@ -3428,7 +3428,7 @@ static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data, i = 0; list_for_each_entry(c, &hdev->conn_hash.list, list) { - if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags)) + if (!test_bit(HCI_CONN_MGMT_CONNECTED, c->flags)) continue; bacpy(&rp->addr[i].bdaddr, &c->dst); rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type); @@ -3628,7 +3628,7 @@ static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status) /* The device is paired so there is no need to remove * its connection parameters anymore. */ - clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags); + clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, conn->flags); hci_conn_put(conn); @@ -10128,7 +10128,7 @@ void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn, u16 eir_len = 0; u32 flags = 0; - if (test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) + if (test_and_set_bit(HCI_CONN_MGMT_CONNECTED, conn->flags)) return; /* allocate buff for LE or BR/EDR adv */ @@ -10177,7 +10177,7 @@ void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn, * since userspace did not know about them yet, so report it now. * Unencrypted connections have no change to report. */ - if (test_bit(HCI_CONN_ENCRYPT, &conn->flags)) + if (test_bit(HCI_CONN_ENCRYPT, conn->flags)) mgmt_security_level_changed(conn); } @@ -10289,7 +10289,7 @@ void mgmt_connect_failed(struct hci_dev *hdev, struct hci_conn *conn, u8 status) * still needs it set to know whether to report the security level * reset, so it is consumed there instead of here. */ - if (test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) { + if (test_bit(HCI_CONN_MGMT_CONNECTED, conn->flags)) { mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type, hci_to_mgmt_reason(status), true); @@ -10930,7 +10930,7 @@ void mgmt_security_level_changed(struct hci_conn *conn) u8 *tlv_data; u8 tlv_len; - if (!test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) + if (!test_bit(HCI_CONN_MGMT_CONNECTED, conn->flags)) return; /* Only ACL, LE and BIS links are tracked as mgmt connections, so @@ -10961,9 +10961,9 @@ void mgmt_security_level_changed(struct hci_conn *conn) tlv = (void *)tlv_data; tlv->type = cpu_to_le16(MGMT_SEC_LEVEL_CHANGED_PARAM_ENC_TYPE); tlv->length = sizeof(__u8); - if (!test_bit(HCI_CONN_ENCRYPT, &conn->flags)) + if (!test_bit(HCI_CONN_ENCRYPT, conn->flags)) tlv->value[0] = MGMT_CONN_SEC_ENCRYPT_NONE; - else if (test_bit(HCI_CONN_AES_CCM, &conn->flags)) + else if (test_bit(HCI_CONN_AES_CCM, conn->flags)) tlv->value[0] = MGMT_CONN_SEC_ENCRYPT_AES_CCM; else tlv->value[0] = MGMT_CONN_SEC_ENCRYPT_E0; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 5dac8b2eae42..984b2d0b5e3e 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -984,12 +984,12 @@ static u8 smp_random(struct smp_chan *smp) smp_s1(smp->tk, smp->rrnd, smp->prnd, stk); - if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) + if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, hcon->flags)) return SMP_UNSPECIFIED; hci_le_start_enc(hcon, ediv, rand, stk, smp->enc_key_size); hcon->enc_key_size = smp->enc_key_size; - set_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags); + set_bit(HCI_CONN_STK_ENCRYPT, hcon->flags); } else { u8 stk[16], auth; __le64 rand = 0; @@ -1028,7 +1028,7 @@ static void smp_notify_keys(struct l2cap_conn *conn) persistent = false; else persistent = !test_bit(HCI_CONN_FLUSH_KEY, - &hcon->flags); + hcon->flags); } else { /* The LTKs, IRKs and CSRKs should be persistent only if * both sides had the bonding bit set in their @@ -1753,7 +1753,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) /* SMP over BR/EDR requires special treatment */ if (conn->hcon->type == ACL_LINK) { /* We must have a BR/EDR SC link */ - if (!test_bit(HCI_CONN_AES_CCM, &conn->hcon->flags) && + if (!test_bit(HCI_CONN_AES_CCM, conn->hcon->flags) && !hci_dev_test_flag(hdev, HCI_FORCE_BREDR_SMP)) return SMP_CROSS_TRANSP_NOT_ALLOWED; @@ -2210,14 +2210,14 @@ static bool smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level) if (smp_ltk_sec_level(key) < sec_level) return false; - if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) + if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, hcon->flags)) return true; hci_le_start_enc(hcon, key->ediv, key->rand, key->val, key->enc_size); hcon->enc_key_size = key->enc_size; /* We never store STKs for initiator role, so clear this flag */ - clear_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags); + clear_bit(HCI_CONN_STK_ENCRYPT, hcon->flags); return true; } @@ -2235,7 +2235,7 @@ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level, * don't have an LTK (e.g. because of key distribution bits). */ if (key_pref == SMP_USE_LTK && - test_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags) && + test_bit(HCI_CONN_STK_ENCRYPT, hcon->flags) && hci_find_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, hcon->role)) return false; @@ -3084,11 +3084,11 @@ static void bredr_pairing(struct l2cap_chan *chan) bt_dev_dbg(hdev, "chan %p", chan); /* Only new pairings are interesting */ - if (!test_bit(HCI_CONN_NEW_LINK_KEY, &hcon->flags)) + if (!test_bit(HCI_CONN_NEW_LINK_KEY, hcon->flags)) return; /* Don't bother if we're not encrypted */ - if (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags)) + if (!test_bit(HCI_CONN_ENCRYPT, hcon->flags)) return; /* Only initiator may initiate SMP over BR/EDR */ @@ -3100,7 +3100,7 @@ static void bredr_pairing(struct l2cap_chan *chan) return; /* BR/EDR must use Secure Connections for SMP */ - if (!test_bit(HCI_CONN_AES_CCM, &hcon->flags) && + if (!test_bit(HCI_CONN_AES_CCM, hcon->flags) && !hci_dev_test_flag(hdev, HCI_FORCE_BREDR_SMP)) return; @@ -3149,7 +3149,7 @@ static void smp_resume_cb(struct l2cap_chan *chan) if (!smp) return; - if (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags)) + if (!test_bit(HCI_CONN_ENCRYPT, hcon->flags)) return; cancel_delayed_work(&smp->security_timer); @@ -3172,7 +3172,7 @@ static void smp_ready_cb(struct l2cap_chan *chan) */ conn->smp = chan; - if (hcon->type == ACL_LINK && test_bit(HCI_CONN_ENCRYPT, &hcon->flags)) + if (hcon->type == ACL_LINK && test_bit(HCI_CONN_ENCRYPT, hcon->flags)) bredr_pairing(chan); } From 5d005ded2cb14531c4d4ab5d02383407c75dbee6 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 21 Oct 2026 13:49:35 -0400 Subject: [PATCH 11/30] Bluetooth: L2CAP: Hold incoming data until encryption key size is known Once encryption is enabled on an ACL link, the encryption key size is read from the controller, using hdev->min_enc_key_size in the meantime. Data received before the reply is processed with that key size, so a peer starting SMP over BR/EDR right after encryption, which it may do, gets its Pairing Request rejected with "Encryption Key Size" whenever the pending security level is FIPS, as that requires a 16 octet key: > HCI Event: Encryption Change (0x08) plen 4 > ACL Data RX: Handle 1 flags 0x02 dlen 11 BR/EDR SMP: Pairing Request (0x01) len 6 @ MGMT Event: Authentication Failed (0x0011) plen 8 Status: Authentication Failed (0x05) < HCI Command: Read Encryption Key Size (0x05|0x0008) plen 2 > HCI Event: Command Complete (0x0e) plen 7 Key size: 16 < ACL Data TX: Handle 1 flags 0x00 dlen 6 BR/EDR SMP: Pairing Failed (0x05) len 1 Reason: Encryption key size (0x06) Mark the connection with HCI_CONN_ENC_KEY_SIZE_PEND while the key size is read and hold incoming L2CAP data back in pending_rx meanwhile, processing it once the reply is handled. Found with mgmt-tester "Pairing Acceptor - SMP over BR/EDR 2" under User Mode Linux time travel, where the emulated peer always replies before the key size is read. Fixes: e3f6a257a73d ("Bluetooth: Use actual encryption key size for SMP over BR/EDR") Assisted-by: OpenCode:claude-opus-5.5 Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_event.c | 12 +++++++++++- net/bluetooth/l2cap_core.c | 16 ++++++++++++++-- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 1991de9eafca..3381abdcc28b 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -714,6 +714,7 @@ enum { HCI_CONN_CREATE_PA_SYNC, HCI_CONN_PA_SYNC, HCI_CONN_PA_SYNC_FAILED, + HCI_CONN_ENC_KEY_SIZE_PEND, __HCI_CONN_NUM_FLAGS, }; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index ab8a0b1ab9a8..975c63df23c1 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -724,6 +724,8 @@ static u8 hci_cc_read_enc_key_size(struct hci_dev *hdev, void *data, goto done; } + clear_bit(HCI_CONN_ENC_KEY_SIZE_PEND, conn->flags); + /* While unexpected, the read_enc_key_size command may fail. The most * secure approach is to then assume the key size is 0 to force a * disconnection. @@ -3190,6 +3192,7 @@ static int hci_read_enc_key_size(struct hci_dev *hdev, struct hci_conn *conn) { struct hci_cp_read_enc_key_size cp; u8 *key_enc_size = hci_conn_key_enc_size(conn); + int err; if (!read_key_size_capable(hdev)) { conn->enc_key_size = HCI_LINK_KEY_SIZE; @@ -3211,7 +3214,14 @@ static int hci_read_enc_key_size(struct hci_dev *hdev, struct hci_conn *conn) else conn->enc_key_size = hdev->min_enc_key_size; - return hci_send_cmd(hdev, HCI_OP_READ_ENC_KEY_SIZE, sizeof(cp), &cp); + /* L2CAP holds incoming data back until the key size is known */ + set_bit(HCI_CONN_ENC_KEY_SIZE_PEND, conn->flags); + + err = hci_send_cmd(hdev, HCI_OP_READ_ENC_KEY_SIZE, sizeof(cp), &cp); + if (err) + clear_bit(HCI_CONN_ENC_KEY_SIZE_PEND, conn->flags); + + return err; } static void hci_conn_complete_evt(struct hci_dev *hdev, void *data, diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index f4e93100e5d5..83b622a42811 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7389,7 +7389,11 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) u16 cid, len; __le16 psm; - if (hcon->state != BT_CONNECTED) { + /* Also hold data back while the encryption key size is read, as + * the security of the link, e.g. for SMP over BR/EDR, depends on it. + */ + if (hcon->state != BT_CONNECTED || + test_bit(HCI_CONN_ENC_KEY_SIZE_PEND, hcon->flags)) { BT_DBG("queueing pending rx skb"); skb_queue_tail(&conn->pending_rx, skb); return; @@ -7452,7 +7456,11 @@ static void process_pending_rx(struct work_struct *work) mutex_lock(&conn->lock); - while ((skb = skb_dequeue(&conn->pending_rx))) + /* l2cap_recv_frame() would queue it all again while the encryption + * key size is read, l2cap_security_cfm() schedules this once known. + */ + while (!test_bit(HCI_CONN_ENC_KEY_SIZE_PEND, conn->hcon->flags) && + (skb = skb_dequeue(&conn->pending_rx))) l2cap_recv_frame(conn, skb); mutex_unlock(&conn->lock); @@ -8041,6 +8049,10 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) } mutex_unlock(&conn->lock); + + /* Process data held back while the encryption key size was read */ + if (!skb_queue_empty(&conn->pending_rx)) + queue_work(hcon->hdev->workqueue, &conn->pending_rx_work); } /* Append fragment into frame respecting the maximum len of rx_skb */ From e24bfbc5e20711dafa0cdc2b3325c69de1cff068 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Thu, 22 Oct 2026 17:03:37 -0400 Subject: [PATCH 12/30] Bluetooth: hci_sync: Update the CIS host feature when enabling LE The Connected Isochronous Stream (Host Support) feature bit is only set during init, based on LE being enabled at that time. If LE is enabled afterwards without the init being repeated, as happens when the controller is still auto powered on after registration, the bit stays cleared and controllers enforcing it reject LE Create CIS with Command Disallowed. Update the bit whenever LE Host Supported is written, so it follows the LE state. Fixes: 709788b154ca ("Bluetooth: hci_core: Fix using {cis,bis}_capable for current settings") Assisted-by: OpenCode:claude-opus-5.5 Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_sync.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 431c28bd29d8..cb84a4288031 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -3511,9 +3511,13 @@ int hci_write_ssp_mode_sync(struct hci_dev *hdev, u8 mode) return hci_write_sc_support_sync(hdev, 0x01); } +static int hci_le_set_host_feature_sync(struct hci_dev *hdev, u16 bit, + u8 value); + int hci_write_le_host_supported_sync(struct hci_dev *hdev, u8 le, u8 simul) { struct hci_cp_write_le_host_supported cp; + int err; if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) || !lmp_bredr_capable(hdev)) @@ -3531,8 +3535,16 @@ int hci_write_le_host_supported_sync(struct hci_dev *hdev, u8 le, u8 simul) cp.le = le; cp.simul = simul; - return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, - sizeof(cp), &cp, HCI_CMD_TIMEOUT); + err = __hci_cmd_sync_status(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, + sizeof(cp), &cp, HCI_CMD_TIMEOUT); + if (err || !cis_capable(hdev)) + return err; + + /* The CIS host feature is set during init based on LE being enabled, + * which is not repeated when LE is enabled afterwards, e.g. while the + * controller is still auto powered on, so update it here. + */ + return hci_le_set_host_feature_sync(hdev, 32, iso_enabled(hdev)); } static int hci_powered_update_adv_sync(struct hci_dev *hdev) From 8524c3588fbb9d5c1b876e6f908c42926845650d Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Thu, 22 Oct 2026 11:21:48 +0800 Subject: [PATCH 13/30] Bluetooth: btmtk: drop zero-length ISO packets from endpoint padding The ISO interrupt IN endpoint delivers a fixed-size transfer that holds one HCI ISO packet and zero-fills the remainder. That padding belongs to the transfer rather than to the stream, so it has to be dropped instead of reported to the host. btmtk_recv_isopkt() keeps parsing it: the zero bytes read as an ISO header with handle 0 and a Data_Total_Length of zero, and each one is passed to hci_recv_frame() as a complete frame. A single transfer yields a long run of them, which is what fills the HCI log with malformed ISO packets, and iso_recv() drops the SDU it is reassembling whenever handle 0 belongs to a live CIS/BIS. A zero Data_Total_Length carries no ISO Data Load, so such a packet is never part of the stream. Check for the zero-filled remainder before starting to parse the next frame, rather than after assembling a 4-byte header: a remainder shorter than HCI_ISO_HDR_SIZE would otherwise be held across calls as a partial header, corrupting the next transfer's framing. This also means a fully zero-filled remainder no longer costs an skb allocation that gets immediately freed. Reaching a zero Data_Total_Length any other way is then a genuine error, not padding. This was observed on MT7925, but btmtk_recv_isopkt() is shared by every MediaTek USB controller that supports ISO data. Fixes: ceac1cb0259d ("Bluetooth: btusb: mediatek: add ISO data transmission functions") Co-developed-by: Hao Qin Signed-off-by: Hao Qin Co-developed-by: Wenlong Tian Signed-off-by: Wenlong Tian Signed-off-by: Chris Lu Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btmtk.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c index 75483d8230e1..01d5ad2479f4 100644 --- a/drivers/bluetooth/btmtk.c +++ b/drivers/bluetooth/btmtk.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -1565,6 +1566,14 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count) int len; if (!skb) { + /* Drop the endpoint's zero-filled padding before + * allocating an skb for it; a zero Data_Total_Length + * check below would miss a padding remainder + * shorter than an ISO header. + */ + if (mem_is_zero(buffer, count)) + break; + skb = bt_skb_alloc(HCI_MAX_ISO_SIZE, GFP_ATOMIC); if (!skb) { err = -ENOMEM; @@ -1588,6 +1597,17 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count) /* Complete ISO header */ hci_skb_expect(skb) = __le16_to_cpu(dlen); + if (!hci_skb_expect(skb)) { + /* Zero padding was ruled out above, so a + * zero Data_Total_Length here is invalid. + */ + kfree_skb(skb); + skb = NULL; + + err = -EILSEQ; + break; + } + if (skb_tailroom(skb) < hci_skb_expect(skb)) { kfree_skb(skb); skb = NULL; From d015faf684129a276f2137ad2e11c6c985294648 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Thu, 22 Oct 2026 11:21:49 +0800 Subject: [PATCH 14/30] Bluetooth: btmtk: bound the ISO payload length by the controller's MTU btmtk_recv_isopkt() bounds the Data_Total_Length reported by the controller with skb_tailroom(skb) < hci_skb_expect(skb). That keeps the reassembly inside the skb, but it enforces no protocol limit: the head allocation is rounded up to the next kmalloc bucket and skb_tailroom() reports what the bucket can hold rather than what was requested, which is several hundred bytes more. An oversized length therefore passes, and the parser keeps pulling bytes out of the following transfers to fill it, swallowing the real ISO packets they carry until the frame is handed to hci_recv_frame(). The controller reports the largest ISO_Data_Packet_Length it will send in LE Read Buffer Size [v2], which hci_cc_le_read_buffer_size_v2() keeps in hdev->iso_mtu. Once that is available, bound the length by it and size the receive skb to hold that much plus the 4-byte header. HCI_MAX_ISO_SIZE is kept only as a fallback for the window before the command completes. Keep the skb_tailroom() test as well, because a fragment started before hdev->iso_mtu was populated sits in an skb sized for the fallback. Fixes: ceac1cb0259d ("Bluetooth: btusb: mediatek: add ISO data transmission functions") Co-developed-by: Hao Qin Signed-off-by: Hao Qin Co-developed-by: Wenlong Tian Signed-off-by: Wenlong Tian Signed-off-by: Chris Lu Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btmtk.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c index 01d5ad2479f4..f2224eb0bf6b 100644 --- a/drivers/bluetooth/btmtk.c +++ b/drivers/bluetooth/btmtk.c @@ -1557,8 +1557,15 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count) struct btmtk_data *btmtk_data = hci_get_priv(hdev); struct sk_buff *skb; unsigned long flags; + unsigned int iso_mtu; int err = 0; + /* The controller reports the largest Data_Total_Length it will send in + * LE Read Buffer Size [v2]. Fall back to HCI_MAX_ISO_SIZE while that + * command has not completed yet. + */ + iso_mtu = hdev->iso_mtu ? hdev->iso_mtu : HCI_MAX_ISO_SIZE; + spin_lock_irqsave(&btmtk_data->isorxlock, flags); skb = btmtk_data->isopkt_skb; @@ -1574,7 +1581,8 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count) if (mem_is_zero(buffer, count)) break; - skb = bt_skb_alloc(HCI_MAX_ISO_SIZE, GFP_ATOMIC); + skb = bt_skb_alloc(HCI_ISO_HDR_SIZE + iso_mtu, + GFP_ATOMIC); if (!skb) { err = -ENOMEM; break; @@ -1608,7 +1616,13 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count) break; } - if (skb_tailroom(skb) < hci_skb_expect(skb)) { + /* Reject a length the controller said it would never + * send. The skb_tailroom() test is kept because a + * fragment started before hdev->iso_mtu was populated + * sits in a smaller skb than iso_mtu now allows. + */ + if (hci_skb_expect(skb) > iso_mtu || + skb_tailroom(skb) < hci_skb_expect(skb)) { kfree_skb(skb); skb = NULL; From 855c9a54608f1e94f4c52afe3790def30534155a Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Thu, 22 Oct 2026 11:21:50 +0800 Subject: [PATCH 15/30] Bluetooth: btmtk: derive the firmware ISO setting from MTK_ISO_THRESHOLD The ISO data transfer size is spelled out twice: as a raw byte pair in the vendor command sent by btmtk_usb_isointf_init(), and as MTK_ISO_THRESHOLD for the padding in btmtk_isopkt_pad(). Build the command payload from the macro so the size is stated once, and update the setting for current MediaTek controllers. Fixes: ceac1cb0259d ("Bluetooth: btusb: mediatek: add ISO data transmission functions") Signed-off-by: Chris Lu Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btmtk.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c index f2224eb0bf6b..bf9bfed3da23 100644 --- a/drivers/bluetooth/btmtk.c +++ b/drivers/bluetooth/btmtk.c @@ -31,7 +31,7 @@ #define BTMTK_CBMCU_FLAG_ENABLE_PATCH 0xF1 /* It is for mt79xx iso data transmission setting */ -#define MTK_ISO_THRESHOLD 264 +#define MTK_ISO_THRESHOLD 342 struct btmtk_patch_header { u8 datetime[16]; @@ -1741,7 +1741,7 @@ static int btmtk_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags) static int btmtk_usb_isointf_init(struct hci_dev *hdev) { struct btmtk_data *btmtk_data = hci_get_priv(hdev); - u8 iso_param[2] = { 0x08, 0x01 }; + __le16 iso_param = cpu_to_le16(MTK_ISO_THRESHOLD); struct sk_buff *skb; int err; @@ -1756,7 +1756,7 @@ static int btmtk_usb_isointf_init(struct hci_dev *hdev) return err; } - skb = __hci_cmd_sync(hdev, 0xfd98, sizeof(iso_param), iso_param, + skb = __hci_cmd_sync(hdev, 0xfd98, sizeof(iso_param), &iso_param, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { bt_dev_err(hdev, "Failed to apply iso setting (%ld)", PTR_ERR(skb)); From 674006912777747170ad70d7727804ad4f2d047f Mon Sep 17 00:00:00 2001 From: Cen Zhang Date: Thu, 22 Oct 2026 20:16:36 +0800 Subject: [PATCH 16/30] Bluetooth: hci_sync: Copy the LE accept list under hdev->lock The LE accept-list mirror consists of bdaddr_list entries that are added, removed and freed under hdev->lock. The ordinary branch of hci_update_accept_list_sync() traverses this list without that lock. The request worker's req_lock does not serialize raw HCI completions, and the RCU sections protect connection and pending-action lookups, not the accept-list nodes. Changing connectability can reach this iterator through set_connectable_sync(), hci_update_connectable_sync(), hci_update_passive_scan_sync() and hci_passive_scan_sync(). With a populated mirror, a privileged raw HCI sender can issue HCI_OP_LE_CLEAR_ACCEPT_LIST while request work is reconciling it: Request work HCI event work select b and successor t hci_cc_le_clear_accept_list() hci_dev_lock(hdev) hci_bdaddr_list_clear() unlink nodes and kfree(b) hci_dev_unlock(hdev) read b->bdaddr_type The clear completion can therefore free the selected node before its field read, or the saved successor before the iterator advances. KASAN reported a one-byte read of bdaddr_type from the freed node. Copy each entry's address and type under hdev->lock and reconcile the private array instead. Release the mutex before issuing synchronous commands, since their completion handlers also acquire it. Free the copy after iteration and use the existing error path to disable accept-list filtering if allocation fails. This change has not been runtime-tested. KASAN report as below: ================================================================== BUG: KASAN: slab-use-after-free in hci_passive_scan_sync+0x1cc4/0x1f80 Read of size 1 at addr ffff888105ee6c56 by task kworker/u17:1/499 Workqueue: hci0 hci_cmd_sync_work Call Trace: dump_stack_lvl+0x93/0xd0 print_report+0xce/0x630 ? hci_passive_scan_sync+0x1cc4/0x1f80 ? srso_alias_return_thunk+0x5/0xfbef5 ? __virt_addr_valid+0x20d/0x410 ? hci_passive_scan_sync+0x1cc4/0x1f80 kasan_report+0xe0/0x110 ? hci_passive_scan_sync+0x1cc4/0x1f80 hci_passive_scan_sync+0x1cc4/0x1f80 ? pmbd_gate_site_armed+0x31/0x1c0 ? __pfx_hci_passive_scan_sync+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? pmbd_probe_hit_cookie+0x10/0x1c0 ? __pfx_pmbd_probe_hit_cookie+0x10/0x10 ? hci_update_passive_scan_sync+0x43f/0x9e0 ? srso_alias_return_thunk+0x5/0xfbef5 ? lock_release+0xc8/0x280 hci_update_passive_scan_sync+0x473/0x9e0 hci_update_connectable_sync+0x13c/0x250 set_connectable_sync+0x39/0xb0 hci_cmd_sync_work+0x1b3/0x450 ? srso_alias_return_thunk+0x5/0xfbef5 process_one_work+0x908/0x19c0 ? __pfx_process_one_work+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? lock_is_held_type+0x8f/0x100 ? srso_alias_return_thunk+0x5/0xfbef5 worker_thread+0x65c/0xe40 ? __pfx_worker_thread+0x10/0x10 kthread+0x34f/0x460 ? srso_alias_return_thunk+0x5/0xfbef5 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x659/0x940 ? __pfx_ret_from_fork+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? __switch_to+0x74f/0xf80 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 Allocated by task 511: kasan_save_stack+0x33/0x60 kasan_save_track+0x14/0x30 __kasan_kmalloc+0xaa/0xb0 __kmalloc_cache_noprof+0x251/0x610 hci_bdaddr_list_add+0x179/0x390 hci_cc_le_add_to_accept_list+0x189/0x2d0 hci_cmd_complete_evt+0x373/0xab0 hci_event_packet+0x4e8/0xc70 hci_rx_work+0x367/0xf00 process_one_work+0x908/0x19c0 worker_thread+0x65c/0xe40 kthread+0x34f/0x460 ret_from_fork+0x659/0x940 ret_from_fork_asm+0x1a/0x30 Freed by task 511: kasan_save_stack+0x33/0x60 kasan_save_track+0x14/0x30 kasan_save_free_info+0x3b/0x60 __kasan_slab_free+0x5f/0x80 kfree+0x307/0x580 hci_bdaddr_list_clear+0x134/0x230 hci_cc_le_clear_accept_list+0x80/0x1f0 hci_cmd_complete_evt+0x373/0xab0 hci_event_packet+0x4e8/0xc70 hci_rx_work+0x367/0xf00 process_one_work+0x908/0x19c0 worker_thread+0x65c/0xe40 kthread+0x34f/0x460 ret_from_fork+0x659/0x940 ret_from_fork_asm+0x1a/0x30 The buggy address belongs to the object at ffff888105ee6c40 which belongs to the cache kmalloc-32 of size 32 The buggy address is located 22 bytes inside of freed 32-byte region [ffff888105ee6c40, ffff888105ee6c60) The buggy address belongs to the physical page: page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff888105ee69c0 pfn:0x105ee6 flags: 0x200000000000200(workingset|node=0|zone=2) page_type: f5(slab) raw: 0200000000000200 ffff888100042780 ffffea0004187150 ffffea00042534d0 raw: ffff888105ee69c0 000000000040003f 00000000f5000000 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff888105ee6b00: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc ffff888105ee6b80: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc >ffff888105ee6c00: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc ^ ffff888105ee6c80: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc ffff888105ee6d00: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc ================================================================== Fixes: e8907f76544f ("Bluetooth: hci_sync: Make use of hci_cmd_sync_queue set 3") Assisted-by: LLM Signed-off-by: Cen Zhang Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_sync.c | 53 ++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index cb84a4288031..4c090d2a6eed 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -2885,6 +2885,31 @@ static struct conn_params *conn_params_copy(struct list_head *list, size_t *n) return p; } +static struct conn_params *le_accept_list_copy(struct hci_dev *hdev, + size_t *n) +{ + struct bdaddr_list *entry; + struct conn_params *params; + size_t i = 0; + + hci_dev_lock(hdev); + + *n = list_count_nodes(&hdev->le_accept_list); + params = kvzalloc_objs(struct conn_params, *n); + if (!params) + goto unlock; + + list_for_each_entry(entry, &hdev->le_accept_list, list) { + bacpy(¶ms[i].addr, &entry->bdaddr); + params[i].addr_type = entry->bdaddr_type; + i++; + } + +unlock: + hci_dev_unlock(hdev); + return params; +} + /* Clear LE Accept List */ static int hci_le_clear_accept_list_sync(struct hci_dev *hdev) { @@ -2915,7 +2940,6 @@ static int hci_le_clear_accept_list_sync(struct hci_dev *hdev) static u8 hci_update_accept_list_sync(struct hci_dev *hdev) { struct conn_params *params; - struct bdaddr_list *b, *t; u8 num_entries = 0; bool pend_conn, pend_report; u8 filter_policy; @@ -2980,20 +3004,27 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev) * report. If not present in either list, then remove it from * the controller. */ - list_for_each_entry_safe(b, t, &hdev->le_accept_list, list) { + params = le_accept_list_copy(hdev, &n); + if (!params) { + err = -ENOMEM; + goto done; + } + + for (i = 0; i < n; i++) { rcu_read_lock(); - if (hci_conn_hash_lookup_le(hdev, &b->bdaddr, b->bdaddr_type)) { + if (hci_conn_hash_lookup_le(hdev, ¶ms[i].addr, + params[i].addr_type)) { rcu_read_unlock(); continue; } pend_conn = hci_pend_le_action_lookup(&hdev->pend_le_conns, - &b->bdaddr, - b->bdaddr_type); - pend_report = hci_pend_le_action_lookup(&hdev->pend_le_reports, - &b->bdaddr, - b->bdaddr_type); + ¶ms[i].addr, + params[i].addr_type); + pend_report = hci_pend_le_action_lookup( + &hdev->pend_le_reports, ¶ms[i].addr, + params[i].addr_type); rcu_read_unlock(); @@ -3001,14 +3032,16 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev) * remove it from the acceptlist. */ if (!pend_conn && !pend_report) { - hci_le_del_accept_list_sync(hdev, &b->bdaddr, - b->bdaddr_type); + hci_le_del_accept_list_sync(hdev, ¶ms[i].addr, + params[i].addr_type); continue; } num_entries++; } + kvfree(params); + /* Since all no longer valid accept list entries have been * removed, walk through the list of pending connections * and ensure that any new device gets programmed into From f05bd61a3213613de7848c8df2865492d5225023 Mon Sep 17 00:00:00 2001 From: Cen Zhang Date: Thu, 22 Oct 2026 20:05:56 +0800 Subject: [PATCH 17/30] Bluetooth: hci_sync: Protect resolving-list lookups The host resolving list is updated under hdev->lock, and each bdaddr_list_with_irk entry must remain alive throughout a lookup. hci_le_del_resolve_list_sync() and hci_le_add_resolve_list_sync() traverse that list without taking the lock. On an LE privacy-capable controller with a programmed entry, passive scan reconciliation can reach hci_le_del_resolve_list_sync() while a privileged HCI_RAW client sends LE Clear Resolving List. The raw command does not take req_lock, and its successful completion runs on the controller workqueue independently of request work: Request work Raw HCI / event work hci_le_del_resolve_list_sync() lookup loads a list node hci_sock_sendmsg() queue LE Clear Resolving List hci_cc_le_clear_resolv_list() take hdev->lock unlink and free the node release hdev->lock read the node's address/type The clear can free the node after the lookup loads it and before its address/type read, causing a use-after-free. The report below shows this access with the delete helper on the faulting stack. The add helper uses the same unprotected lookup. Take hdev->lock around each resolving-list membership lookup and retain only a boolean result. This serializes traversal with clear completion and keeps entry pointers inside the protected section. Release the lock before issuing a synchronous HCI command, whose completion also needs the lock. KASAN report as below: ================================================================== BUG: KASAN: slab-use-after-free in hci_bdaddr_list_lookup_with_irk+0x106/0x120 Read of size 1 at addr ffff88810b036e16 by task kworker/u17:0/495 CPU: 2 UID: 0 PID: 495 Comm: kworker/u17:0 Not tainted 7.2.0-rc6-pmb-bt-functional-v1+ #3 PREEMPT(lazy) Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 Workqueue: hci0 hci_cmd_sync_work Call Trace: dump_stack_lvl+0x93/0xd0 print_report+0xce/0x630 ? hci_bdaddr_list_lookup_with_irk+0x106/0x120 ? srso_alias_return_thunk+0x5/0xfbef5 ? __virt_addr_valid+0x20d/0x410 ? hci_bdaddr_list_lookup_with_irk+0x106/0x120 kasan_report+0xe0/0x110 ? hci_bdaddr_list_lookup_with_irk+0x106/0x120 hci_bdaddr_list_lookup_with_irk+0x106/0x120 hci_le_del_resolve_list_sync.isra.0+0xd6/0x3f0 ? __pfx_hci_le_del_resolve_list_sync.isra.0+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 hci_le_del_accept_list_sync.isra.0+0x11c/0x290 ? __pfx_hci_le_del_accept_list_sync.isra.0+0x10/0x10 ? hci_passive_scan_sync+0x551/0x1e80 ? srso_alias_return_thunk+0x5/0xfbef5 ? lock_release+0xc8/0x280 hci_passive_scan_sync+0x71c/0x1e80 ? __pfx_hci_passive_scan_sync+0x10/0x10 ? find_held_lock+0x2b/0x80 ? hci_lookup_le_connect+0xe1/0x3c0 ? srso_alias_return_thunk+0x5/0xfbef5 ? find_held_lock+0x2b/0x80 ? hci_update_passive_scan_sync+0x437/0x950 ? srso_alias_return_thunk+0x5/0xfbef5 ? lock_release+0xc8/0x280 hci_update_passive_scan_sync+0x461/0x950 hci_cmd_sync_work+0x1b3/0x450 ? srso_alias_return_thunk+0x5/0xfbef5 process_one_work+0x908/0x19c0 ? __pfx_process_one_work+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? lock_is_held_type+0x8f/0x100 ? srso_alias_return_thunk+0x5/0xfbef5 worker_thread+0x65c/0xe40 ? __pfx_worker_thread+0x10/0x10 kthread+0x34f/0x460 ? srso_alias_return_thunk+0x5/0xfbef5 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x659/0x940 ? __pfx_ret_from_fork+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? __switch_to+0x74f/0xf80 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 Allocated by task 495: kasan_save_stack+0x33/0x60 kasan_save_track+0x14/0x30 __kasan_kmalloc+0xaa/0xb0 __kmalloc_cache_noprof+0x251/0x610 hci_bdaddr_list_add_with_irk+0x183/0x3e0 hci_cc_le_add_to_resolv_list+0x18c/0x240 hci_cmd_complete_evt+0x373/0xab0 hci_event_packet+0x4e8/0xc70 hci_rx_work+0x367/0xf00 process_one_work+0x908/0x19c0 worker_thread+0x65c/0xe40 kthread+0x34f/0x460 ret_from_fork+0x659/0x940 ret_from_fork_asm+0x1a/0x30 Freed by task 497: kasan_save_stack+0x33/0x60 kasan_save_track+0x14/0x30 kasan_save_free_info+0x3b/0x60 __kasan_slab_free+0x5f/0x80 kfree+0x307/0x580 hci_bdaddr_list_clear+0x134/0x230 hci_cc_le_clear_resolv_list+0x13d/0x240 hci_cmd_complete_evt+0x373/0xab0 hci_event_packet+0x4e8/0xc70 hci_rx_work+0x367/0xf00 process_one_work+0x908/0x19c0 worker_thread+0x65c/0xe40 kthread+0x34f/0x460 ret_from_fork+0x659/0x940 ret_from_fork_asm+0x1a/0x30 The buggy address belongs to the object at ffff88810b036e00 which belongs to the cache kmalloc-64 of size 64 The buggy address is located 22 bytes inside of freed 64-byte region [ffff88810b036e00, ffff88810b036e40) The buggy address belongs to the physical page: page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x10b036 flags: 0x200000000000000(node=0|zone=2) page_type: f5(slab) raw: 0200000000000000 ffff8881000428c0 dead000000000100 dead000000000122 raw: 0000000000000000 0000000000200020 00000000f5000000 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff88810b036d00: 00 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc ffff88810b036d80: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc >ffff88810b036e00: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ^ ffff88810b036e80: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ffff88810b036f00: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ================================================================== Disabling lock debugging due to kernel taint Fixes: e8907f76544f ("Bluetooth: hci_sync: Make use of hci_cmd_sync_queue set 3") Assisted-by: LLM Signed-off-by: Cen Zhang Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_sync.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 4c090d2a6eed..9d71ce96bd8e 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -2448,15 +2448,17 @@ static int hci_le_del_resolve_list_sync(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type) { struct hci_cp_le_del_from_resolv_list cp; - struct bdaddr_list_with_irk *entry; + bool exists; if (!ll_privacy_capable(hdev)) return 0; /* Check if the IRK has been programmed */ - entry = hci_bdaddr_list_lookup_with_irk(&hdev->le_resolv_list, bdaddr, - bdaddr_type); - if (!entry) + hci_dev_lock(hdev); + exists = hci_bdaddr_list_lookup_with_irk(&hdev->le_resolv_list, + bdaddr, bdaddr_type); + hci_dev_unlock(hdev); + if (!exists) return 0; cp.bdaddr_type = bdaddr_type; @@ -2512,8 +2514,8 @@ static int hci_le_add_resolve_list_sync(struct hci_dev *hdev, { struct hci_cp_le_add_to_resolv_list cp; struct smp_irk *irk; - struct bdaddr_list_with_irk *entry; struct hci_conn_params *p; + bool exists; if (!ll_privacy_capable(hdev)) return 0; @@ -2536,10 +2538,11 @@ static int hci_le_add_resolve_list_sync(struct hci_dev *hdev, return 0; /* Check if the IK has _not_ been programmed yet. */ - entry = hci_bdaddr_list_lookup_with_irk(&hdev->le_resolv_list, - ¶ms->addr, - params->addr_type); - if (entry) + hci_dev_lock(hdev); + exists = hci_bdaddr_list_lookup_with_irk( + &hdev->le_resolv_list, ¶ms->addr, params->addr_type); + hci_dev_unlock(hdev); + if (exists) return 0; cp.bdaddr_type = params->addr_type; From 7eac80614300563470cffabf4df2b63616787ee7 Mon Sep 17 00:00:00 2001 From: Tobias Wilken Date: Wed, 21 Oct 2026 08:58:33 +0200 Subject: [PATCH 18/30] Bluetooth: MGMT: Return RFKILLED for Set Powered on a blocked controller Since MGMT_OP_SET_POWERED runs through hci_cmd_sync, powering on a controller that is blocked by rfkill fails with -ERFKILL from hci_dev_open_sync(), and mgmt_set_powered_complete() reports it with mgmt_status(err). mgmt_errno_status() has no case for -ERFKILL, so userspace gets MGMT_STATUS_FAILED instead of MGMT_STATUS_RFKILLED. Before that conversion, power on went through hci_power_on(), whose error path mgmt_set_powered_failed() still maps -ERFKILL to MGMT_STATUS_RFKILLED. bluetoothd relies on that status: for RFKILLED it sets the adapter PowerState to "off-blocked" and returns org.bluez.Error.Blocked for the Powered property, for any other status it returns org.bluez.Error.Failed. With the controller soft blocked, "bluetoothctl power on" printed "Failed to set power on: org.bluez.Error.Failed" and btmon showed "Set Powered (0x0005) Status: Failed (0x03)". With this change it prints org.bluez.Error.Blocked and btmon shows "Status: RFKilled (0x12)". Map -ERFKILL to MGMT_STATUS_RFKILLED in mgmt_errno_status(). Fixes: cf75ad8b41d2 ("Bluetooth: hci_sync: Convert MGMT_SET_POWERED") Assisted-by: LLM Signed-off-by: Tobias Wilken Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/mgmt.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 188c719c50ad..3cb4f9ece83c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -304,6 +304,8 @@ static u8 mgmt_errno_status(int err) return MGMT_STATUS_DISCONNECTED; case -ECANCELED: return MGMT_STATUS_CANCELLED; + case -ERFKILL: + return MGMT_STATUS_RFKILLED; } return MGMT_STATUS_FAILED; From 5b7d0386a4e75c85479da0fbd9fd66a3e9201375 Mon Sep 17 00:00:00 2001 From: Michael McAllister Date: Wed, 21 Oct 2026 20:51:12 +0100 Subject: [PATCH 19/30] Bluetooth: qca: Fix the WCN3950 NVM baud rate offset WCN3950 uses the HCI transport tag layout that stores the UART baud rate at byte 1, like WCN3991. However, QCA_WCN3950 precedes QCA_WCN3991 in qca_btsoc_type, so qca_tlv_check_data() writes the baud rate to byte 2 instead. On a Motorola Moto G10 with WCN3950 and cmnv12.bin, configuring a 3 Mbps UART therefore leaves the NVM baud rate at its default 3.2 Mbps and overwrites the following byte. Firmware download completes, but the subsequent HCI_RESET times out and Bluetooth initialization fails. Include WCN3950 in the byte-1 case so the NVM baud rate matches the host UART without altering the following transport parameter. Fixes: d5712c511cb3 ("Bluetooth: qca: add WCN3950 support") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Michael McAllister Reviewed-by: Bartosz Golaszewski Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btqca.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index 22b08ab05b82..002307000d3c 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c @@ -426,7 +426,8 @@ static int qca_tlv_check_data(struct hci_dev *hdev, tlv_nvm->data[0] |= 0x80; /* UART Baud Rate */ - if (soc_type >= QCA_WCN3991) + if (soc_type == QCA_WCN3950 || + soc_type >= QCA_WCN3991) tlv_nvm->data[1] = nvm_baud_rate; else tlv_nvm->data[2] = nvm_baud_rate; From 3b70dd827b27bfadd89e7b1a2d422b04da38797c Mon Sep 17 00:00:00 2001 From: Ismail Tarim Date: Fri, 30 Oct 2026 01:40:15 +0300 Subject: [PATCH 20/30] Bluetooth: btmtk: fix error handling in btmtk_usb_isointf_init() btmtk_usb_isointf_init() submits the ISO interrupt IN URB and then sends the vendor command 0xfd98. If that command fails, the function returns an error without killing the URB it has just submitted. The caller then leaves BTMTK_ISOPKT_RUNNING clear, so the driver treats the ISO path as inactive while its RX URB is still in flight, and btmtk_usb_suspend() skips killing it. Kill the anchored URBs on this path, as the URB submission failure path already does. The return value of __set_mtk_intr_interface() is also ignored: a failure to select the ISO alternate setting or to find its endpoints is logged, but the function goes on to submit the URB. Return the error instead. Fixes: ceac1cb0259d ("Bluetooth: btusb: mediatek: add ISO data transmission functions") Signed-off-by: Ismail Tarim Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btmtk.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c index bf9bfed3da23..b66cb2f5df35 100644 --- a/drivers/bluetooth/btmtk.c +++ b/drivers/bluetooth/btmtk.c @@ -1747,7 +1747,9 @@ static int btmtk_usb_isointf_init(struct hci_dev *hdev) spin_lock_init(&btmtk_data->isorxlock); - __set_mtk_intr_interface(hdev); + err = __set_mtk_intr_interface(hdev); + if (err < 0) + return err; err = btmtk_submit_intr_urb(hdev, GFP_KERNEL); if (err < 0) { @@ -1759,6 +1761,7 @@ static int btmtk_usb_isointf_init(struct hci_dev *hdev) skb = __hci_cmd_sync(hdev, 0xfd98, sizeof(iso_param), &iso_param, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { + usb_kill_anchored_urbs(&btmtk_data->isopkt_anchor); bt_dev_err(hdev, "Failed to apply iso setting (%ld)", PTR_ERR(skb)); return PTR_ERR(skb); } From 281ddc4e01ab54cab07995f2a1b72cf81bf90eb5 Mon Sep 17 00:00:00 2001 From: Cen Zhang Date: Thu, 29 Oct 2026 21:12:26 +0800 Subject: [PATCH 21/30] Bluetooth: hci_core: Keep link-key filtering inside RCU hci_find_link_key() must keep the matching link key allocated while it checks the key against the blocked-key list. It currently leaves the key-list RCU read-side section before passing k->val to hci_is_blocked_key(). That helper's own RCU section protects the blocked-key list, but it cannot keep an unlinked link key from being reclaimed. The SMP receive path calls the finder without hdev->lock: Secure Connections key distribution over BR/EDR reaches it through smp_distribute_keys() and sc_generate_ltk(). With a stored peer link key and a link-key entry in the blocked-key list, MGMT_OP_LOAD_LINK_KEYS can free the selected key before the comparison: HCI RX worker (SMP) Management / RCU reclamation hci_find_link_key() rcu_read_lock() select k rcu_read_unlock() load_link_keys() hci_dev_lock(hdev) hci_link_keys_clear(hdev) list_del_rcu(), kfree_rcu() hci_dev_unlock(hdev) grace period ends, k is freed hci_is_blocked_key(hdev, ..., k->val) memcmp() reads the freed key Keep the RCU read-side section active through the blocked-key comparison and the warning that prints k->bdaddr, and release it before returning on both matched-key paths. hci_find_ltk() already handles its blocked-key check this way. KASAN reported this on a test kernel whose scheduling hook paused the receive worker after the lookup until the key had been freed. KASAN report as below: ================================================================== BUG: KASAN: slab-use-after-free in hci_is_blocked_key+0x2db/0x300 Read of size 1 at addr ffff88810b5f89a7 by task kworker/u17:0/502 CPU: 1 UID: 0 PID: 502 Comm: kworker/u17:0 Not tainted 7.2.0-rc6-pmb-bt-functional-v1+ #5 PREEMPT(lazy) Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 Workqueue: hci1 hci_rx_work Call Trace: dump_stack_lvl+0x93/0xd0 print_report+0xce/0x630 ? hci_is_blocked_key+0x2db/0x300 ? srso_alias_return_thunk+0x5/0xfbef5 ? __virt_addr_valid+0x20d/0x410 ? hci_is_blocked_key+0x2db/0x300 kasan_report+0xe0/0x110 ? hci_is_blocked_key+0x2db/0x300 hci_is_blocked_key+0x2db/0x300 hci_find_link_key+0x12e/0x400 smp_distribute_keys+0x1830/0x2950 ? trace_hardirqs_on+0x18/0x160 ? srso_alias_return_thunk+0x5/0xfbef5 ? queue_delayed_work_on+0xb3/0xf0 ? __pfx_smp_distribute_keys+0x10/0x10 ? __pfx_smp_send_cmd.isra.0+0x10/0x10 ? __cancel_work+0x1b0/0x290 ? __entry_text_end+0x1020f7/0x1020f9 ? lockdep_hardirqs_on_prepare+0xea/0x1a0 ? srso_alias_return_thunk+0x5/0xfbef5 ? __asan_memset+0x23/0x50 ? smp_recv_cb+0x12c7/0x8d80 ? srso_alias_return_thunk+0x5/0xfbef5 smp_recv_cb+0x12c7/0x8d80 ? __pfx_smp_recv_cb+0x10/0x10 ? __pfx___might_resched+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? stack_depot_save_flags+0x29/0x9a0 ? srso_alias_return_thunk+0x5/0xfbef5 ? __mutex_lock+0x182c/0x2590 ? kasan_save_stack+0x42/0x60 ? l2cap_recv_frame+0x9ef/0x8830 ? __kasan_slab_free+0x5f/0x80 ? kmem_cache_free+0x242/0x580 ? kfree_skbmem+0x15e/0x1d0 ? sk_skb_reason_drop+0x12f/0x490 ? hci_event_packet+0x556/0xc70 ? hci_rx_work+0x367/0xf00 ? process_one_work+0x908/0x19c0 ? worker_thread+0x65c/0xe40 ? __pfx___mutex_lock+0x10/0x10 ? __lock_acquire+0x466/0x2260 ? __pfx_l2cap_chan_hold_unless_zero+0x10/0x10 ? l2cap_recv_frame+0x13cc/0x8830 ? __pfx_smp_recv_cb+0x10/0x10 l2cap_recv_frame+0x13cc/0x8830 ? srso_alias_return_thunk+0x5/0xfbef5 ? __mutex_lock+0x182c/0x2590 ? __pfx_l2cap_recv_frame+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? find_held_lock+0x2b/0x80 ? l2cap_recv_acldata+0x1eb/0x10e0 ? __pfx___mutex_lock+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? __mutex_unlock_slowpath+0x147/0x920 ? __pfx_l2cap_conn_hold_unless_zero+0x10/0x10 ? __pfx_hci_conn_enter_active_mode+0x10/0x10 ? l2cap_recv_acldata+0x13d/0x10e0 ? srso_alias_return_thunk+0x5/0xfbef5 l2cap_recv_acldata+0xe9f/0x10e0 ? srso_alias_return_thunk+0x5/0xfbef5 hci_rx_work+0x5a6/0xf00 ? srso_alias_return_thunk+0x5/0xfbef5 process_one_work+0x908/0x19c0 ? __pfx_process_one_work+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? lock_is_held_type+0x8f/0x100 ? srso_alias_return_thunk+0x5/0xfbef5 worker_thread+0x65c/0xe40 ? __pfx_worker_thread+0x10/0x10 kthread+0x34f/0x460 ? srso_alias_return_thunk+0x5/0xfbef5 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x659/0x940 ? __pfx_ret_from_fork+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? __switch_to+0x74f/0xf80 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 Allocated by task 504: kasan_save_stack+0x33/0x60 kasan_save_track+0x14/0x30 __kasan_kmalloc+0xaa/0xb0 __kmalloc_cache_noprof+0x251/0x610 hci_add_link_key+0x474/0x840 hci_link_key_notify_evt+0x492/0xce0 hci_event_packet+0x894/0xc70 hci_rx_work+0x367/0xf00 process_one_work+0x908/0x19c0 worker_thread+0x65c/0xe40 kthread+0x34f/0x460 ret_from_fork+0x659/0x940 ret_from_fork_asm+0x1a/0x30 Freed by task 29: kasan_save_stack+0x33/0x60 kasan_save_track+0x14/0x30 kasan_save_free_info+0x3b/0x60 __kasan_slab_free+0x5f/0x80 __rcu_free_sheaf_prepare+0x65/0x2a0 rcu_free_sheaf_nobarn+0x1d/0x50 rcu_core+0x661/0x1d10 handle_softirqs+0x201/0x930 run_ksoftirqd+0x33/0x60 smpboot_thread_fn+0x3bd/0x9a0 kthread+0x34f/0x460 ret_from_fork+0x659/0x940 ret_from_fork_asm+0x1a/0x30 The buggy address belongs to the object at ffff88810b5f8980 which belongs to the cache kmalloc-64 of size 64 The buggy address is located 39 bytes inside of freed 64-byte region [ffff88810b5f8980, ffff88810b5f89c0) The buggy address belongs to the physical page: page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x10b5f8 flags: 0x200000000000000(node=0|zone=2) page_type: f5(slab) raw: 0200000000000000 ffff8881000428c0 dead000000000100 dead000000000122 raw: 0000000000000000 0000000000200020 00000000f5000000 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff88810b5f8880: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ffff88810b5f8900: 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc fc >ffff88810b5f8980: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ^ ffff88810b5f8a00: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ffff88810b5f8a80: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ================================================================== Fixes: 600a87490ff9 ("Bluetooth: Implementation of MGMT_OP_SET_BLOCKED_KEYS.") Assisted-by: LLM Signed-off-by: Cen Zhang Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 55fc64db495a..a299aea1dd09 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1075,17 +1075,16 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) rcu_read_lock(); list_for_each_entry_rcu(k, &hdev->link_keys, list) { if (bacmp(bdaddr, &k->bdaddr) == 0) { - rcu_read_unlock(); - if (hci_is_blocked_key(hdev, HCI_BLOCKED_KEY_TYPE_LINKKEY, k->val)) { bt_dev_warn_ratelimited(hdev, "Link key blocked for %pMR", &k->bdaddr); - return NULL; + k = NULL; } + rcu_read_unlock(); return k; } } From ebc4f217c1fbe8364b5ef2ad8e3a8e9a1b2701a7 Mon Sep 17 00:00:00 2001 From: Cen Zhang Date: Thu, 29 Oct 2026 21:12:27 +0800 Subject: [PATCH 22/30] Bluetooth: SMP: Protect link keys during LTK derivation sc_generate_ltk() reads the type and value of the peer link key after hci_find_link_key() has returned. The finder ends its RCU read-side section before returning the borrowed entry, and the SMP receive path does not hold hdev->lock: l2cap_recv_acldata() releases it before the PDU is dispatched. The L2CAP connection and channel locks held by SMP do not serialize with management link-key removal. When BR/EDR Secure Connections pairing derives an LTK from the stored link key, MGMT_OP_LOAD_LINK_KEYS can free that key mid-derivation: HCI RX worker (SMP) Management / RCU reclamation sc_generate_ltk() key = hci_find_link_key() load_link_keys() hci_dev_lock(hdev) hci_link_keys_clear(hdev) list_del_rcu(), kfree_rcu() hci_dev_unlock(hdev) grace period ends, key is freed read key->type smp_h6() or smp_h7() reads key->val Hold an RCU read-side section from the lookup until the type and value have been consumed. smp_h6() and smp_h7() only run the synchronous AES-CMAC library code, which neither sleeps nor allocates. Release the section before sc_add_ltk(), which allocates with GFP_KERNEL. KASAN reported this on a test kernel whose scheduling hook paused the receive worker after the lookup; the hook frames appear in the trace. KASAN report as below: ================================================================== BUG: KASAN: slab-use-after-free in smp_distribute_keys+0x2983/0x2b70 Read of size 1 at addr ffff88810618e9a6 by task kworker/u17:0/500 CPU: 0 UID: 0 PID: 500 Comm: kworker/u17:0 Not tainted 7.2.0-rc6-pmb-bt-functional-v1+ #1 PREEMPT(lazy) Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 Workqueue: hci1 hci_rx_work Call Trace: dump_stack_lvl+0x93/0xd0 print_report+0xce/0x630 ? smp_distribute_keys+0x2983/0x2b70 ? srso_alias_return_thunk+0x5/0xfbef5 ? __virt_addr_valid+0x20d/0x410 ? smp_distribute_keys+0x2983/0x2b70 kasan_report+0xe0/0x110 ? smp_distribute_keys+0x2983/0x2b70 smp_distribute_keys+0x2983/0x2b70 ? __pfx_smp_distribute_keys+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? pmbd_gate_maybe+0x47/0x60 ? srso_alias_return_thunk+0x5/0xfbef5 ? pmbd_probe_hit_cookie+0xe7/0x1c0 ? srso_alias_return_thunk+0x5/0xfbef5 ? pmbd_probe_hit_cookie+0xee/0x1c0 ? __pfx_pmbd_probe_hit_cookie+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? __asan_memset+0x23/0x50 ? smp_recv_cb+0x12e2/0x8f30 ? srso_alias_return_thunk+0x5/0xfbef5 smp_recv_cb+0x12e2/0x8f30 ? __pfx_smp_recv_cb+0x10/0x10 ? __pfx___might_resched+0x10/0x10 ? __pfx_sched_balance_find_src_group+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? __mutex_lock+0x182c/0x2590 ? l2cap_recv_frame+0x9ef/0x8830 ? __pfx___mutex_lock+0x10/0x10 ? __lock_acquire+0x466/0x2260 ? __pfx_l2cap_chan_hold_unless_zero+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? l2cap_recv_frame+0x13cc/0x8830 ? __pfx_smp_recv_cb+0x10/0x10 l2cap_recv_frame+0x13cc/0x8830 ? srso_alias_return_thunk+0x5/0xfbef5 ? __mutex_lock+0x182c/0x2590 ? __pfx_l2cap_recv_frame+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? find_held_lock+0x2b/0x80 ? l2cap_recv_acldata+0x1eb/0x10e0 ? __pfx___mutex_lock+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? __mutex_unlock_slowpath+0x147/0x920 ? __pfx_l2cap_conn_hold_unless_zero+0x10/0x10 ? __pfx_hci_conn_enter_active_mode+0x10/0x10 ? l2cap_recv_acldata+0x13d/0x10e0 ? srso_alias_return_thunk+0x5/0xfbef5 l2cap_recv_acldata+0xe9f/0x10e0 ? srso_alias_return_thunk+0x5/0xfbef5 hci_rx_work+0x5a6/0xf00 ? srso_alias_return_thunk+0x5/0xfbef5 process_one_work+0x908/0x19c0 ? __pfx_process_one_work+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? lock_is_held_type+0x8f/0x100 ? srso_alias_return_thunk+0x5/0xfbef5 worker_thread+0x65c/0xe40 ? __pfx_worker_thread+0x10/0x10 kthread+0x34f/0x460 ? srso_alias_return_thunk+0x5/0xfbef5 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x659/0x940 ? __pfx_ret_from_fork+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? __switch_to+0x74f/0xf80 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 Allocated by task 500: kasan_save_stack+0x33/0x60 kasan_save_track+0x14/0x30 __kasan_kmalloc+0xaa/0xb0 __kmalloc_cache_noprof+0x251/0x610 hci_add_link_key+0x474/0x840 hci_link_key_notify_evt+0x492/0xce0 hci_event_packet+0x894/0xc70 hci_rx_work+0x367/0xf00 process_one_work+0x908/0x19c0 worker_thread+0x65c/0xe40 kthread+0x34f/0x460 ret_from_fork+0x659/0x940 ret_from_fork_asm+0x1a/0x30 Freed by task 0: kasan_save_stack+0x33/0x60 kasan_save_track+0x14/0x30 kasan_save_free_info+0x3b/0x60 __kasan_slab_free+0x5f/0x80 __rcu_free_sheaf_prepare+0x65/0x2a0 rcu_free_sheaf+0x1f/0xe0 rcu_core+0x661/0x1d10 handle_softirqs+0x201/0x930 __irq_exit_rcu+0x110/0x1e0 irq_exit_rcu+0xe/0x20 sysvec_apic_timer_interrupt+0x6c/0x80 asm_sysvec_apic_timer_interrupt+0x1a/0x20 The buggy address belongs to the object at ffff88810618e980 which belongs to the cache kmalloc-64 of size 64 The buggy address is located 38 bytes inside of freed 64-byte region [ffff88810618e980, ffff88810618e9c0) The buggy address belongs to the physical page: page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x10618e flags: 0x200000000000000(node=0|zone=2) page_type: f5(slab) raw: 0200000000000000 ffff8881000428c0 dead000000000122 0000000000000000 raw: 0000000000000000 0000000000200020 00000000f5000000 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff88810618e880: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ffff88810618e900: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc >ffff88810618e980: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ^ ffff88810618ea00: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ffff88810618ea80: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ================================================================== Fixes: b5ae344d4c0f ("Bluetooth: Add full SMP BR/EDR support") Assisted-by: LLM Signed-off-by: Cen Zhang Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/smp.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 984b2d0b5e3e..1d3f3ceb3ecc 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1186,9 +1186,13 @@ static void sc_generate_ltk(struct smp_chan *smp) struct hci_conn *hcon = smp->conn->hcon; struct hci_dev *hdev = hcon->hdev; struct link_key *key; + int err; + + rcu_read_lock(); key = hci_find_link_key(hdev, &hcon->dst); if (!key) { + rcu_read_unlock(); bt_dev_err(hdev, "no Link Key found to generate LTK"); return; } @@ -1200,16 +1204,19 @@ static void sc_generate_ltk(struct smp_chan *smp) /* SALT = 0x000000000000000000000000746D7032 */ const u8 salt[16] = { 0x32, 0x70, 0x6d, 0x74 }; - if (smp_h7(key->val, salt, smp->tk)) - return; + err = smp_h7(key->val, salt, smp->tk); } else { /* From core spec. Spells out in ASCII as 'tmp2'. */ const u8 tmp2[4] = { 0x32, 0x70, 0x6d, 0x74 }; - if (smp_h6(key->val, tmp2, smp->tk)) - return; + err = smp_h6(key->val, tmp2, smp->tk); } + rcu_read_unlock(); + + if (err) + return; + if (smp_h6(smp->tk, brle, smp->tk)) return; From add463a65802bb117e4a17b8c00d747fa70399fc Mon Sep 17 00:00:00 2001 From: Cen Zhang Date: Thu, 29 Oct 2026 21:12:28 +0800 Subject: [PATCH 23/30] Bluetooth: SMP: Protect LTK encryption with RCU smp_ltk_encrypt() checks the security level of the LTK returned by hci_find_ltk() and then starts encryption with its EDIV, Rand, value and key size. The finder ends its RCU read-side section before returning the borrowed entry, and neither caller holds hdev->lock: the SMP Security Request handler runs from the receive path, and setsockopt(BT_SECURITY) reaches smp_conn_security() with only the socket and channel locks held. MGMT_OP_LOAD_LONG_TERM_KEYS can therefore free the LTK in between: Socket security request Management / RCU reclamation smp_ltk_encrypt() key = hci_find_ltk() load_long_term_keys() hci_dev_lock(hdev) hci_smp_ltks_clear(hdev) list_del_rcu(), kfree_rcu() hci_dev_unlock(hdev) grace period ends, key is freed smp_ltk_sec_level(key) hci_le_start_enc(hcon, key->ediv, key->rand, key->val, ...) Keep an RCU read-side section across the lookup and every use of the key. hci_le_start_enc() copies the key into the command and queues it with a GFP_ATOMIC allocation, so the whole sequence can stay inside the section. KFENCE reported this on a test kernel where the socket thread was paused after the lookup until the RCU callback had freed the key. KFENCE report as below: ================================================================== BUG: KFENCE: use-after-free read in smp_ltk_encrypt.isra.0+0xf3/0x370 Use-after-free read at 0x00000000c45332eb (in kfence-#128): smp_ltk_encrypt.isra.0+0xf3/0x370 smp_conn_security+0x489/0x9d0 l2cap_sock_setsockopt+0x1bbe/0x2300 do_sock_setsockopt+0x1fb/0x430 __sys_setsockopt+0x106/0x180 __x64_sys_setsockopt+0xc2/0x160 do_syscall_64+0x115/0x6a0 entry_SYSCALL_64_after_hwframe+0x77/0x7f kfence-#128: 0x00000000d45af9b0-0x0000000053c1365e, size=72, cache=kmalloc-96 allocated by task 533 on cpu 0 at 50.484258s (0.449177s ago): hci_add_ltk+0x1f5/0x3a0 load_long_term_keys+0x6ea/0x930 hci_sock_sendmsg+0x128b/0x22e0 sock_write_iter+0x4c0/0x550 vfs_write+0x637/0x1010 ksys_write+0x1b7/0x200 do_syscall_64+0x115/0x6a0 entry_SYSCALL_64_after_hwframe+0x77/0x7f freed by task 0 on cpu 0 at 50.846944s (0.093664s ago): __rcu_free_sheaf_prepare+0x261/0x2a0 rcu_free_sheaf_nobarn+0x1d/0x50 rcu_core+0x661/0x1d10 handle_softirqs+0x201/0x930 __irq_exit_rcu+0x110/0x1e0 irq_exit_rcu+0xe/0x20 sysvec_apic_timer_interrupt+0x6c/0x80 asm_sysvec_apic_timer_interrupt+0x1a/0x20 pv_native_safe_halt+0xf/0x20 default_idle+0x9/0x10 default_idle_call+0x6c/0xb0 do_idle+0x3a7/0x650 cpu_startup_entry+0x54/0x60 rest_init+0x15e/0x2b0 start_kernel+0x412/0x4b0 x86_64_start_reservations+0x18/0x30 x86_64_start_kernel+0x111/0x120 common_startup_64+0x13e/0x158 CPU: 2 UID: 0 PID: 534 Comm: l2cap-ltk-actor Not tainted 7.2.0-rc6-pmb-bt-functional-v1+ #5 PREEMPT(lazy) Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 ================================================================== Fixes: 988c5997d320 ("Bluetooth: Use the LTK after receiving a LE Security Request") Assisted-by: LLM Signed-off-by: Cen Zhang Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/smp.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 1d3f3ceb3ecc..b7015e37e1f1 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -2209,16 +2209,20 @@ static bool smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level) { struct smp_ltk *key; struct hci_conn *hcon = conn->hcon; + bool ret = false; + + rcu_read_lock(); key = hci_find_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, hcon->role); if (!key) - return false; + goto unlock; if (smp_ltk_sec_level(key) < sec_level) - return false; + goto unlock; + ret = true; if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, hcon->flags)) - return true; + goto unlock; hci_le_start_enc(hcon, key->ediv, key->rand, key->val, key->enc_size); hcon->enc_key_size = key->enc_size; @@ -2226,7 +2230,9 @@ static bool smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level) /* We never store STKs for initiator role, so clear this flag */ clear_bit(HCI_CONN_STK_ENCRYPT, hcon->flags); - return true; +unlock: + rcu_read_unlock(); + return ret; } bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level, From 9ff737119177a6c1ce6083ef8c0fc06355f11869 Mon Sep 17 00:00:00 2001 From: Cen Zhang Date: Thu, 29 Oct 2026 21:12:29 +0800 Subject: [PATCH 24/30] Bluetooth: hci_sync: Copy the resolving-list IRK under RCU hci_le_add_resolve_list_sync() copies the peer IRK into the LE Add Device To Resolving List command after hci_find_irk_by_addr() has returned. The finder ends its RCU read-side section before returning the borrowed entry, and neither the request worker nor interleave_scan_work() holds hdev->lock here. The resolving-list membership check between the lookup and the copy takes hdev->lock and may sleep on it, which widens the window. When LL privacy programs a peer with address resolution enabled, MGMT_OP_LOAD_IRKS can free its IRK before the copy: Request worker Management / RCU reclamation hci_le_add_resolve_list_sync() irk = hci_find_irk_by_addr() load_irks() hci_dev_lock(hdev) hci_smp_irks_clear(hdev) list_del_rcu(), kfree_rcu() hci_dev_unlock(hdev) grace period ends, irk is freed resolving-list membership check memcpy(cp.peer_irk, irk->val, 16) Copy the IRK value in an RCU read-side section right after the lookup, as hci_le_set_privacy_mode_sync() does for the identity address. The section ends before hdev->lock is taken and before the synchronous HCI command is sent. KASAN reported this on a test kernel with scheduling hooks, whose frames appear in the trace. The report predates the hdev->lock taken by the membership check. KASAN report as below: ================================================================== BUG: KASAN: slab-use-after-free in hci_le_add_resolve_list_sync+0x8d9/0x910 Read of size 16 at addr ffff88810d21452d by task kworker/u17:0/504 CPU: 2 UID: 0 PID: 504 Comm: kworker/u17:0 Not tainted 7.2.0-rc6-pmb-bt-functional-v1+ #2 PREEMPT(lazy) Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 Workqueue: hci0 interleave_scan_work Call Trace: dump_stack_lvl+0x93/0xd0 print_report+0xce/0x630 ? hci_le_add_resolve_list_sync+0x8d9/0x910 ? srso_alias_return_thunk+0x5/0xfbef5 ? __virt_addr_valid+0x20d/0x410 ? hci_le_add_resolve_list_sync+0x8d9/0x910 kasan_report+0xe0/0x110 ? hci_le_add_resolve_list_sync+0x8d9/0x910 hci_le_add_resolve_list_sync+0x8d9/0x910 ? __pfx_hci_le_add_resolve_list_sync+0x10/0x10 ? pmbd_probe_hit_cookie+0xe7/0x1c0 ? srso_alias_return_thunk+0x5/0xfbef5 ? pmbd_probe_hit_cookie+0xee/0x1c0 ? __pfx_pmbd_probe_hit_cookie+0x10/0x10 hci_le_add_accept_list_sync+0x18e/0x820 ? conn_params_copy+0x36e/0x650 ? __pfx_hci_le_add_accept_list_sync+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? conn_params_copy+0x3a0/0x650 hci_passive_scan_sync+0x95f/0x1f10 ? __pfx_hci_passive_scan_sync+0x10/0x10 ? debug_object_deactivate+0x2f8/0x3c0 ? pwq_dec_nr_in_flight+0x880/0xdf0 ? srso_alias_return_thunk+0x5/0xfbef5 ? lock_acquire+0x17b/0x2f0 ? process_one_work+0x895/0x19c0 interleave_scan_work+0x11b/0x470 process_one_work+0x908/0x19c0 ? __pfx_process_one_work+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? lock_is_held_type+0x8f/0x100 ? srso_alias_return_thunk+0x5/0xfbef5 worker_thread+0x65c/0xe40 ? __pfx_worker_thread+0x10/0x10 kthread+0x34f/0x460 ? srso_alias_return_thunk+0x5/0xfbef5 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x659/0x940 ? __pfx_ret_from_fork+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? __switch_to+0x74f/0xf80 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 Allocated by task 535: kasan_save_stack+0x33/0x60 kasan_save_track+0x14/0x30 __kasan_kmalloc+0xaa/0xb0 __kmalloc_cache_noprof+0x251/0x610 hci_add_irk+0xb6/0x220 load_irks+0x5f9/0x840 hci_sock_sendmsg+0x128b/0x22e0 __sys_sendto+0x425/0x470 __x64_sys_sendto+0xe5/0x1c0 do_syscall_64+0x115/0x6a0 entry_SYSCALL_64_after_hwframe+0x77/0x7f Freed by task 0: kasan_save_stack+0x33/0x60 kasan_save_track+0x14/0x30 kasan_save_free_info+0x3b/0x60 __kasan_slab_free+0x5f/0x80 __rcu_free_sheaf_prepare+0x65/0x2a0 rcu_free_sheaf+0x1f/0xe0 rcu_core+0x661/0x1d10 handle_softirqs+0x201/0x930 __irq_exit_rcu+0x110/0x1e0 irq_exit_rcu+0xe/0x20 sysvec_apic_timer_interrupt+0x6c/0x80 asm_sysvec_apic_timer_interrupt+0x1a/0x20 The buggy address belongs to the object at ffff88810d214500 which belongs to the cache kmalloc-64 of size 64 The buggy address is located 45 bytes inside of freed 64-byte region [ffff88810d214500, ffff88810d214540) The buggy address belongs to the physical page: page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x10d214 flags: 0x200000000000000(node=0|zone=2) page_type: f5(slab) raw: 0200000000000000 ffff8881000428c0 dead000000000100 dead000000000122 raw: 0000000000000000 0000000000200020 00000000f5000000 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff88810d214400: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ffff88810d214480: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc >ffff88810d214500: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ^ ffff88810d214580: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ffff88810d214600: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ================================================================== Fixes: e8907f76544f ("Bluetooth: hci_sync: Make use of hci_cmd_sync_queue set 3") Assisted-by: LLM Signed-off-by: Cen Zhang Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_sync.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 9d71ce96bd8e..9d829c20c316 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -2533,9 +2533,17 @@ static int hci_le_add_resolve_list_sync(struct hci_dev *hdev, } else if (!(params->flags & HCI_CONN_FLAG_ADDRESS_RESOLUTION)) return 0; + rcu_read_lock(); + irk = hci_find_irk_by_addr(hdev, ¶ms->addr, params->addr_type); - if (!irk) + if (!irk) { + rcu_read_unlock(); return 0; + } + + memcpy(cp.peer_irk, irk->val, 16); + + rcu_read_unlock(); /* Check if the IK has _not_ been programmed yet. */ hci_dev_lock(hdev); @@ -2547,7 +2555,6 @@ static int hci_le_add_resolve_list_sync(struct hci_dev *hdev, cp.bdaddr_type = params->addr_type; bacpy(&cp.bdaddr, ¶ms->addr); - memcpy(cp.peer_irk, irk->val, 16); /* Default privacy mode is always Network */ params->privacy_mode = HCI_NETWORK_PRIVACY; From d90f24dc389b9a7524aaac109021d1530fa180f0 Mon Sep 17 00:00:00 2001 From: Kevin Dewald Date: Thu, 29 Oct 2026 13:28:32 -0700 Subject: [PATCH 25/30] Bluetooth: MGMT: Clear disabled connection parameters when loading none Load Connection Parameters only clears the disabled connection parameters when it loads more than one entry, so that loading a single entry can update the parameters of one device without dropping the others. Loading no entries does not clear them either, though, which is what bluetoothd does when it starts without stored connection parameters. Pair Device adds disabled connection parameters for the device it pairs with, so these now survive bluetoothd restarts, and new connections to the device keep using the parameters they were created with instead of the defaults set since, e.g. the connection interval from main.conf. Clear the disabled connection parameters unless a single entry is loaded, as was done for any number of entries before. Fixes: 0ece498c27d8 ("Bluetooth: MGMT: Make MGMT_OP_LOAD_CONN_PARAM update existing connection") Assisted-by: Claude:claude-opus-5.5 Signed-off-by: Kevin Dewald Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/mgmt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3cb4f9ece83c..cf5256f4a89e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -8175,7 +8175,11 @@ static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data, hci_dev_lock(hdev); - if (param_count > 1) + /* A single entry may be an update for one device, so keep the other + * disabled parameters then, but clear them otherwise, including when + * no entries are loaded. + */ + if (param_count != 1) hci_conn_params_clear_disabled(hdev); for (i = 0; i < param_count; i++) { From a9f9eeb5344fc7dc625e5700ccf09891bc2603b5 Mon Sep 17 00:00:00 2001 From: Jinwang Li Date: Thu, 29 Oct 2026 17:41:04 +0800 Subject: [PATCH 26/30] Bluetooth: L2CAP: Ignore connection responses with wrong ident L2CAP/COS/CED/BI-28-C requires the IUT to ignore a Connection Response that carries an invalid Identifier. l2cap_connect_create_rsp() only checks that a connection request is outstanding, not that the response answers it. Add an ident check against the pending request so that a mismatched response is dropped. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Jinwang Li Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/l2cap_core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 83b622a42811..70ad30b091e4 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4480,11 +4480,11 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn, lockdep_assert_held(&chan->conn->lock); - /* Only accept a response to a connection request we sent and that - * is still outstanding. A channel waiting in BT_CONNECT for security - * or the feature mask has not sent one yet. + /* Only accept a response matching a connection request we sent and + * that is still outstanding. A channel waiting in BT_CONNECT for + * security or the feature mask has not sent one yet. */ - if (!l2cap_chan_connect_pending(chan)) + if (!l2cap_chan_connect_pending(chan) || chan->ident != cmd->ident) goto done; switch (result) { From a7c5c18b7cc30dcd2a9ae5a0fb38378d3998417e Mon Sep 17 00:00:00 2001 From: Cen Zhang Date: Fri, 30 Oct 2026 22:27:45 +0800 Subject: [PATCH 27/30] Bluetooth: hci_core: Initialize advertising RPA work only once hci_add_adv_instance() also updates existing instances and calls INIT_DELAYED_WORK() on their rpa_expired_cb every time, even when the work is pending or running. cancel_delayed_work_sync() then no longer finds the work, so hci_remove_adv_instance() can free the instance under it: hdev->workqueue MGMT_OP_ADD_EXT_ADV_PARAMS adv_instance_rpa_expired() hci_dev_lock(hdev) hci_add_adv_instance() INIT_DELAYED_WORK() mgmt_pending_new() fails hci_remove_adv_instance() cancel_delayed_work_sync() returns without waiting kfree(adv) hci_dev_unlock(hdev) adv->rpa_expired = true The work has been initialized on every update since it was added. Initialize it only when the instance is allocated. KASAN report as below: BUG: KASAN: slab-use-after-free in adv_instance_rpa_expired+0x139/0x160 Write of size 1 at addr ffff888108d84b2e by task kworker/u17:0/504 Workqueue: hci0 adv_instance_rpa_expired Call Trace: adv_instance_rpa_expired+0x139/0x160 Allocated by task 560: hci_add_adv_instance+0x68d/0x9d0 add_ext_adv_params+0x4d4/0xb60 hci_sock_sendmsg+0x128b/0x22e0 Freed by task 594: kfree+0x307/0x580 hci_remove_adv_instance+0x230/0x540 add_ext_adv_params+0xa43/0xb60 hci_sock_sendmsg+0x128b/0x22e0 Last potentially related work creation: insert_work+0x37/0x210 __queue_work+0xaba/0x1270 call_timer_fn+0x171/0x500 The buggy address belongs to the object at ffff888108d84800 which belongs to the cache kmalloc-1k of size 1024 The buggy address is located 814 bytes inside of freed 1024-byte region [ffff888108d84800, ffff888108d84c00) Fixes: a73c046a2869 ("Bluetooth: Implement Set ADV set random address") Signed-off-by: Cen Zhang Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a299aea1dd09..bc77db53b195 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1700,6 +1700,9 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance, if (!adv) return ERR_PTR(-ENOMEM); + INIT_DELAYED_WORK(&adv->rpa_expired_cb, + adv_instance_rpa_expired); + adv->pending = true; adv->instance = instance; @@ -1736,8 +1739,6 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance, else adv->duration = duration; - INIT_DELAYED_WORK(&adv->rpa_expired_cb, adv_instance_rpa_expired); - BT_DBG("%s for %dMR", hdev->name, instance); return adv; From 1eb52f35fc8fb06ab7f2973fff29cba81f96b947 Mon Sep 17 00:00:00 2001 From: Yifan Zhang Date: Mon, 2 Nov 2026 19:58:37 +0800 Subject: [PATCH 28/30] Bluetooth: validate retained LE Create CIS command length hci_cs_le_create_cis() retrieves the parameters of the previously sent command without their length. It then trusts num_cis and walks the flexible cis[] array when a controller reports a failed command. A five-byte HCI command containing only num_cis can therefore make the handler read beyond the command skb. KASAN reports: BUG: KASAN: slab-out-of-bounds in hci_cs_le_create_cis Read of size 2 hci_cs_le_create_cis hci_cmd_status_evt hci_event_packet Add a length-returning saved-command helper and require the fixed header and complete CIS array before walking it. The reproducer no longer triggers a KASAN report with this change. Fixes: 26afbd826ee3 ("Bluetooth: Add initial implementation of CIS connections") Closes: https://lore.kernel.org/linux-bluetooth/179317462624.87574.6271582002629080499@stu.pku.edu.cn/ Signed-off-by: Yifan Zhang Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_core.c | 30 ++++++++++++++++++++---------- net/bluetooth/hci_event.c | 7 ++++++- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3381abdcc28b..908acbad7177 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -2428,6 +2428,8 @@ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); void hci_send_iso(struct hci_conn *conn, struct sk_buff *skb); void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode); +void *hci_sent_cmd_data_len(struct hci_dev *hdev, __u16 opcode, + size_t *len); void *hci_recv_event_data(struct hci_dev *hdev, __u8 event); u32 hci_conn_get_phy(struct hci_conn *conn); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index bc77db53b195..c97aec3caba0 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3175,7 +3175,8 @@ int __hci_cmd_send(struct hci_dev *hdev, u16 opcode, u32 plen, EXPORT_SYMBOL(__hci_cmd_send); /* Get data from the previously sent command */ -static void *hci_cmd_data(struct sk_buff *skb, __u16 opcode) +static void *hci_cmd_data(struct sk_buff *skb, __u16 opcode, + size_t *len) { struct hci_command_hdr *hdr; @@ -3187,21 +3188,30 @@ static void *hci_cmd_data(struct sk_buff *skb, __u16 opcode) if (hdr->opcode != cpu_to_le16(opcode)) return NULL; + if (len) + *len = skb->len - HCI_COMMAND_HDR_SIZE; + return skb->data + HCI_COMMAND_HDR_SIZE; } +/* Get data from the previously sent command */ +void *hci_sent_cmd_data_len(struct hci_dev *hdev, __u16 opcode, size_t *len) +{ + void *data; + + /* Check if opcode matches last sent command */ + data = hci_cmd_data(hdev->sent_cmd, opcode, len); + if (!data) + /* Check if opcode matches last request */ + data = hci_cmd_data(hdev->req_skb, opcode, len); + + return data; +} + /* Get data from the previously sent command */ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode) { - void *data; - - /* Check if opcode matches last sent command */ - data = hci_cmd_data(hdev->sent_cmd, opcode); - if (!data) - /* Check if opcode matches last request */ - data = hci_cmd_data(hdev->req_skb, opcode); - - return data; + return hci_sent_cmd_data_len(hdev, opcode, NULL); } /* Get data from last received event */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 975c63df23c1..bb4249f8e665 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4491,6 +4491,7 @@ static void hci_cs_le_create_cis(struct hci_dev *hdev, u8 status) { struct hci_cp_le_create_cis *cp; bool pending = false; + size_t len; int i; bt_dev_dbg(hdev, "status 0x%2.2x", status); @@ -4498,10 +4499,14 @@ static void hci_cs_le_create_cis(struct hci_dev *hdev, u8 status) if (!status) return; - cp = hci_sent_cmd_data(hdev, HCI_OP_LE_CREATE_CIS); + cp = hci_sent_cmd_data_len(hdev, HCI_OP_LE_CREATE_CIS, &len); if (!cp) return; + if (len < sizeof(*cp) || + len < struct_size(cp, cis, cp->num_cis)) + return; + hci_dev_lock(hdev); /* Remove connection if command failed */ From ed4d302af778b9e2ead28134a2196c09a4ad248a Mon Sep 17 00:00:00 2001 From: Yifan Zhang Date: Mon, 2 Nov 2026 19:58:37 +0800 Subject: [PATCH 29/30] Bluetooth: validate retained LE Set CIG Parameters command length hci_cc_le_set_cig_params() validates the controller response but not the parameters of the previously sent command. A short command can claim a large num_cis without containing the corresponding cis[] array. A complete successful response then makes the handler read beyond the command skb while looking up each CIS ID. KASAN reports: BUG: KASAN: slab-out-of-bounds in hci_cc_le_set_cig_params Read of size 1 hci_cc_le_set_cig_params hci_cmd_complete_evt hci_event_packet Obtain the retained parameter length and require both the fixed header and the complete CIS array before using the command data. The reproducer no longer triggers a KASAN report with this change. Fixes: 71e9588435c3 ("Bluetooth: ISO: use correct CIS order in Set CIG Parameters event") Closes: https://lore.kernel.org/linux-bluetooth/179317463153.87610.8996555110609321376@stu.pku.edu.cn/ Signed-off-by: Yifan Zhang Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_event.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index bb4249f8e665..377e916ccacc 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3985,13 +3985,16 @@ static u8 hci_cc_le_set_cig_params(struct hci_dev *hdev, void *data, struct hci_conn *conn; u8 status = rp->status; bool pending = false; + size_t len; int i; bt_dev_dbg(hdev, "status 0x%2.2x", rp->status); - cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_CIG_PARAMS); + cp = hci_sent_cmd_data_len(hdev, HCI_OP_LE_SET_CIG_PARAMS, &len); if (!rp->status && - (!cp || rp->num_handles != cp->num_cis || + (!cp || len < sizeof(*cp) || + len < struct_size(cp, cis, cp->num_cis) || + rp->num_handles != cp->num_cis || rp->cig_id != cp->cig_id || skb->len < array_size(rp->num_handles, sizeof(*rp->handle)))) { bt_dev_err(hdev, "unexpected Set CIG Parameters response data"); From 60b10121db602a43ada3dbc39792bbf93d25991b Mon Sep 17 00:00:00 2001 From: Kevin Dewald Date: Mon, 2 Nov 2026 09:00:00 -0800 Subject: [PATCH 30/30] Bluetooth: MGMT: Fix discovery stuck after a failed Stop Discovery 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 its inquiry or active LE scan is still running, so that it can be stopped again. Only change the state while the discovery is still stopping, as Inquiry Cancel may already have stopped it, for example when only the passive scan could not be disabled, and a new Start Discovery may have followed. Do this under hci_dev_lock(), like the command completions that change these flags, and before replying, so that a client acting on the reply sees the new state. Only cancel the LE scan timeout once the scan is disabled, so that the discovery still ends on its own, except when suspending, where it is still cancelled first. 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, or while the timeout work waits for the lock. Fixes: 0e05bba6f6f8 ("Bluetooth: Update stop_discovery to use HCI request") Assisted-by: Claude:claude-opus-5.5 Signed-off-by: Kevin Dewald Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_event.c | 12 +++++++++++- net/bluetooth/hci_sync.c | 26 +++++++++++++++++++++++--- net/bluetooth/mgmt.c | 23 ++++++++++++++++++++--- 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 377e916ccacc..a52574003e4f 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 9d829c20c316..9213e3ef9f26 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -376,8 +376,18 @@ static void le_scan_disable(struct work_struct *work) bt_dev_dbg(hdev, ""); hci_dev_lock(hdev); - if (!hci_dev_test_flag(hdev, HCI_LE_SCAN)) + if (!hci_dev_test_flag(hdev, HCI_LE_SCAN)) { + /* The scan of a discovery can be disabled while this work + * waits for the lock, for example by a Stop Discovery that + * timed out and still completed, so end the discovery as + * le_set_scan_enable_complete() does when it cancels this + * work. + */ + if (hdev->discovery.state == DISCOVERY_FINDING) + goto discov_stopped; + goto _return; + } status = hci_cmd_sync_queue(hdev, scan_disable_sync, NULL, NULL); if (status) { @@ -5920,11 +5930,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 { @@ -6559,6 +6573,12 @@ static int hci_pause_discovery_sync(struct hci_dev *hdev) return 0; hci_discovery_set_state(hdev, DISCOVERY_STOPPING); + + /* Cancel the LE scan timeout first, so that it does not run while + * suspended if the scan cannot be disabled. + */ + cancel_delayed_work(&hdev->le_scan_disable); + err = hci_stop_discovery_sync(hdev); if (err) return err; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index cf5256f4a89e..260ef2a45719 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6318,12 +6318,29 @@ static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err) bt_dev_dbg(hdev, "err %d", err); + hci_dev_lock(hdev); + + /* Change the state before replying, so that a client acting on the + * reply sees it, and only while the discovery is still stopping, as + * Inquiry Cancel may already have stopped it and a new Start Discovery + * may have followed. Go back to DISCOVERY_FINDING when stopping failed + * while the inquiry or the active LE scan of the discovery is still + * running, so that it can be stopped again. + */ + if (hdev->discovery.state == DISCOVERY_STOPPING) { + if (err && (test_bit(HCI_INQUIRY, &hdev->flags) || + (hci_dev_test_flag(hdev, HCI_LE_SCAN) && + hdev->le_scan_type == LE_SCAN_ACTIVE))) + hci_discovery_set_state(hdev, DISCOVERY_FINDING); + else + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); + } + + hci_dev_unlock(hdev); + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err), cmd->param, 1); mgmt_pending_free(cmd); - - if (!err) - hci_discovery_set_state(hdev, DISCOVERY_STOPPED); } static int stop_discovery_sync(struct hci_dev *hdev, void *data)