From 926e8bfaaa11471b3df25befc284da62b11a1e92 Mon Sep 17 00:00:00 2001 From: Kiran K Date: Thu, 24 Jul 2025 17:58:24 +0530 Subject: [PATCH 01/30] Bluetooth: btintel: Add support for BlazarIW core Add support for the BlazarIW Bluetooth core used in the Wildcat Lake platform. HCI traces: < HCI Command: Intel Read Version (0x3f|0x0005) plen 1 Requested Type: All Supported Types(0xff) > HCI Event: Command Complete (0x0e) plen 122 Intel Read Version (0x3f|0x0005) ncmd 1 Status: Success (0x00) ..... CNVi BT(18): 0x00223700 - BlazarIW(0x22) ..... ..... Signed-off-by: Vijay Satija Signed-off-by: Kiran K Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btintel.c | 3 +++ drivers/bluetooth/btintel_pcie.c | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index be69d21c9aa7..9d29ab811f80 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -484,6 +484,7 @@ int btintel_version_info_tlv(struct hci_dev *hdev, case 0x1d: /* BlazarU (BzrU) */ case 0x1e: /* BlazarI (Bzr) */ case 0x1f: /* Scorpious Peak */ + case 0x22: /* BlazarIW (BzrIW) */ break; default: bt_dev_err(hdev, "Unsupported Intel hardware variant (0x%x)", @@ -3253,6 +3254,7 @@ void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant) case 0x1d: case 0x1e: case 0x1f: + case 0x22: hci_set_msft_opcode(hdev, 0xFC1E); break; default: @@ -3593,6 +3595,7 @@ static int btintel_setup_combined(struct hci_dev *hdev) case 0x1d: case 0x1e: case 0x1f: + case 0x22: /* Display version information of TLV type */ btintel_version_info_tlv(hdev, &ver_tlv); diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index 6e7bbbd35279..d08f59ae7720 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -2149,6 +2149,7 @@ static int btintel_pcie_setup_internal(struct hci_dev *hdev) switch (INTEL_HW_VARIANT(ver_tlv.cnvi_bt)) { case 0x1e: /* BzrI */ case 0x1f: /* ScP */ + case 0x22: /* BzrIW */ /* Display version information of TLV type */ btintel_version_info_tlv(hdev, &ver_tlv); From e57362f4911b025c31e032c7e1c67389b7eb8dd1 Mon Sep 17 00:00:00 2001 From: Chandrashekar Devegowda Date: Fri, 25 Jul 2025 14:31:33 +0530 Subject: [PATCH 02/30] Bluetooth: btintel_pcie: Add support for _suspend() / _resume() This patch implements _suspend() and _resume() functions for the Bluetooth controller. When the system enters a suspended state, the driver notifies the controller to perform necessary housekeeping tasks by writing to the sleep control register and waits for an alive interrupt. The firmware raises the alive interrupt when it has transitioned to the D3 state. The same flow occurs when the system resumes. Command to test host initiated wakeup after 60 seconds sudo rtcwake -m mem -s 60 dmesg log (tested on Whale Peak2 on Panther Lake platform) On system suspend: [Fri Jul 25 11:05:37 2025] Bluetooth: hci0: device entered into d3 state from d0 in 80 us On system resume: [Fri Jul 25 11:06:36 2025] Bluetooth: hci0: device entered into d0 state from d3 in 7117 us Signed-off-by: Chandrashekar Devegowda Signed-off-by: Kiran K Signed-off-by: Arnd Bergmann Reviewed-by: Paul Menzel Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btintel_pcie.c | 89 ++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index d08f59ae7720..b3c197b26e89 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -2574,11 +2574,100 @@ static void btintel_pcie_coredump(struct device *dev) } #endif +static int btintel_pcie_suspend_late(struct device *dev, pm_message_t mesg) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct btintel_pcie_data *data; + ktime_t start; + u32 dxstate; + int err; + + data = pci_get_drvdata(pdev); + + dxstate = (mesg.event == PM_EVENT_SUSPEND ? + BTINTEL_PCIE_STATE_D3_HOT : BTINTEL_PCIE_STATE_D3_COLD); + + data->gp0_received = false; + + start = ktime_get(); + + /* Refer: 6.4.11.7 -> Platform power management */ + btintel_pcie_wr_sleep_cntrl(data, dxstate); + err = wait_event_timeout(data->gp0_wait_q, data->gp0_received, + msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS)); + if (err == 0) { + bt_dev_err(data->hdev, + "Timeout (%u ms) on alive interrupt for D3 entry", + BTINTEL_DEFAULT_INTR_TIMEOUT_MS); + return -EBUSY; + } + + bt_dev_dbg(data->hdev, + "device entered into d3 state from d0 in %lld us", + ktime_to_us(ktime_get() - start)); + + return 0; +} + +static int btintel_pcie_suspend(struct device *dev) +{ + return btintel_pcie_suspend_late(dev, PMSG_SUSPEND); +} + +static int btintel_pcie_hibernate(struct device *dev) +{ + return btintel_pcie_suspend_late(dev, PMSG_HIBERNATE); +} + +static int btintel_pcie_freeze(struct device *dev) +{ + return btintel_pcie_suspend_late(dev, PMSG_FREEZE); +} + +static int btintel_pcie_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct btintel_pcie_data *data; + ktime_t start; + int err; + + data = pci_get_drvdata(pdev); + data->gp0_received = false; + + start = ktime_get(); + + /* Refer: 6.4.11.7 -> Platform power management */ + btintel_pcie_wr_sleep_cntrl(data, BTINTEL_PCIE_STATE_D0); + err = wait_event_timeout(data->gp0_wait_q, data->gp0_received, + msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS)); + if (err == 0) { + bt_dev_err(data->hdev, + "Timeout (%u ms) on alive interrupt for D0 entry", + BTINTEL_DEFAULT_INTR_TIMEOUT_MS); + return -EBUSY; + } + + bt_dev_dbg(data->hdev, + "device entered into d0 state from d3 in %lld us", + ktime_to_us(ktime_get() - start)); + return 0; +} + +static const struct dev_pm_ops btintel_pcie_pm_ops = { + .suspend = btintel_pcie_suspend, + .resume = btintel_pcie_resume, + .freeze = btintel_pcie_freeze, + .thaw = btintel_pcie_resume, + .poweroff = btintel_pcie_hibernate, + .restore = btintel_pcie_resume, +}; + static struct pci_driver btintel_pcie_driver = { .name = KBUILD_MODNAME, .id_table = btintel_pcie_table, .probe = btintel_pcie_probe, .remove = btintel_pcie_remove, + .driver.pm = pm_sleep_ptr(&btintel_pcie_pm_ops), #ifdef CONFIG_DEV_COREDUMP .driver.coredump = btintel_pcie_coredump #endif From 2bae7d46149339905a4b89543c5c5b98c1771b30 Mon Sep 17 00:00:00 2001 From: Kiran K Date: Mon, 28 Jul 2025 21:19:08 +0530 Subject: [PATCH 03/30] Bluetooth: btintel_pcie: Add Bluetooth core/platform as comments Add Bluetooth CNVi core and platform names to the PCI device table for each device ID as a comment. Reviewed-by: Paul Menzel Signed-off-by: Kiran K Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btintel_pcie.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index b3c197b26e89..969e22c674cb 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -35,9 +35,9 @@ /* Intel Bluetooth PCIe device id table */ static const struct pci_device_id btintel_pcie_table[] = { - { BTINTEL_PCI_DEVICE(0x4D76, PCI_ANY_ID) }, - { BTINTEL_PCI_DEVICE(0xA876, PCI_ANY_ID) }, - { BTINTEL_PCI_DEVICE(0xE476, PCI_ANY_ID) }, + { BTINTEL_PCI_DEVICE(0x4D76, PCI_ANY_ID) }, /* BlazarI, Wildcat Lake */ + { BTINTEL_PCI_DEVICE(0xA876, PCI_ANY_ID) }, /* BlazarI, Lunar Lake */ + { BTINTEL_PCI_DEVICE(0xE476, PCI_ANY_ID) }, /* Scorpious, Panther Lake-H404 */ { 0 } }; MODULE_DEVICE_TABLE(pci, btintel_pcie_table); From 04efaba1d7615a000195762e9f1dac69bd3b089a Mon Sep 17 00:00:00 2001 From: Kiran K Date: Mon, 28 Jul 2025 21:19:09 +0530 Subject: [PATCH 04/30] Bluetooth: btintel_pcie: Add id of Scorpious, Panther Lake-H484 sudo lspci -v -k -d 8086:e376 00:14.7 Bluetooth: Intel Corporation Device e376 Subsystem: Intel Corporation Device 0011 Flags: bus master, fast devsel, latency 0, IRQ 16, IOMMU group 14 Memory at 14815368000 (64-bit, non-prefetchable) [size=16K] Capabilities: [c8] Power Management version 3 Capabilities: [d0] MSI: Enable- Count=1/1 Maskable- 64bit+ Capabilities: [40] Express Root Complex Integrated Endpoint, MSI 00 Capabilities: [80] MSI-X: Enable+ Count=32 Masked- Capabilities: [100] Latency Tolerance Reporting Kernel driver in use: btintel_pcie Kernel modules: btintel_pcie Reviewed-by: Paul Menzel Signed-off-by: Kiran K Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btintel_pcie.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index 969e22c674cb..f7cf5a9033fc 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -37,6 +37,7 @@ static const struct pci_device_id btintel_pcie_table[] = { { BTINTEL_PCI_DEVICE(0x4D76, PCI_ANY_ID) }, /* BlazarI, Wildcat Lake */ { BTINTEL_PCI_DEVICE(0xA876, PCI_ANY_ID) }, /* BlazarI, Lunar Lake */ + { BTINTEL_PCI_DEVICE(0xE376, PCI_ANY_ID) }, /* Scorpious, Panther Lake-H484 */ { BTINTEL_PCI_DEVICE(0xE476, PCI_ANY_ID) }, /* Scorpious, Panther Lake-H404 */ { 0 } }; From ee333727de222345e8c0a1ddcb8141e176fc147a Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Mon, 28 Jul 2025 14:05:14 -0400 Subject: [PATCH 05/30] Bluetooth: btintel_pcie: Move model comment before its definition This prevents the comments going over 80 columns which is still required for Bluetooth code. Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btintel_pcie.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index f7cf5a9033fc..ce17c5ea67e8 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -35,10 +35,14 @@ /* Intel Bluetooth PCIe device id table */ static const struct pci_device_id btintel_pcie_table[] = { - { BTINTEL_PCI_DEVICE(0x4D76, PCI_ANY_ID) }, /* BlazarI, Wildcat Lake */ - { BTINTEL_PCI_DEVICE(0xA876, PCI_ANY_ID) }, /* BlazarI, Lunar Lake */ - { BTINTEL_PCI_DEVICE(0xE376, PCI_ANY_ID) }, /* Scorpious, Panther Lake-H484 */ - { BTINTEL_PCI_DEVICE(0xE476, PCI_ANY_ID) }, /* Scorpious, Panther Lake-H404 */ + /* BlazarI, Wildcat Lake */ + { BTINTEL_PCI_DEVICE(0x4D76, PCI_ANY_ID) }, + /* BlazarI, Lunar Lake */ + { BTINTEL_PCI_DEVICE(0xA876, PCI_ANY_ID) }, + /* Scorpious, Panther Lake-H484 */ + { BTINTEL_PCI_DEVICE(0xE376, PCI_ANY_ID) }, + /* Scorpious, Panther Lake-H404 */ + { BTINTEL_PCI_DEVICE(0xE476, PCI_ANY_ID) }, { 0 } }; MODULE_DEVICE_TABLE(pci, btintel_pcie_table); From 34ecb8760190606472f71ebf4ca2817928ce5d40 Mon Sep 17 00:00:00 2001 From: Zenm Chen Date: Sat, 26 Jul 2025 00:14:32 +0800 Subject: [PATCH 06/30] Bluetooth: btusb: Add USB ID 2001:332a for D-Link AX9U rev. A1 Add USB ID 2001:332a for D-Link AX9U rev. A1 which is based on a Realtek RTL8851BU chip. The information in /sys/kernel/debug/usb/devices about the Bluetooth device is listed as the below: T: Bus=03 Lev=01 Prnt=01 Port=02 Cnt=01 Dev#= 2 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=2001 ProdID=332a Rev= 0.00 S: Manufacturer=Realtek S: Product=802.11ax WLAN Adapter S: SerialNumber=00e04c000001 C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=500mA A: FirstIf#= 0 IfCount= 2 Cls=e0(wlcon) Sub=01 Prot=01 I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms I:* If#= 2 Alt= 0 #EPs= 8 Cls=ff(vend.) Sub=ff Prot=ff Driver=rtw89_8851bu_git E: Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=06(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=07(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=09(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=0a(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=0b(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=0c(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms Cc: stable@vger.kernel.org # 6.12.x Signed-off-by: Zenm Chen Reviewed-by: Paul Menzel Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 8085fabadde8..3595a8bad6bd 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -522,6 +522,8 @@ static const struct usb_device_id quirks_table[] = { /* Realtek 8851BU Bluetooth devices */ { USB_DEVICE(0x3625, 0x010b), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x2001, 0x332a), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, /* Realtek 8852AE Bluetooth devices */ { USB_DEVICE(0x0bda, 0x2852), .driver_info = BTUSB_REALTEK | From 3e94262921990e2884ff7a49064c12fb6d3a0733 Mon Sep 17 00:00:00 2001 From: Chandrashekar Devegowda Date: Thu, 31 Jul 2025 16:47:11 +0530 Subject: [PATCH 07/30] Bluetooth: btintel_pcie: Define hdev->wakeup() callback Implement hdev->wakeup() callback to support Wake On BT feature. Test steps: 1. echo enabled > /sys/bus/pci/devices/0000:00:14.7/power/wakeup 2. connect bluetooth hid device 3. put the system to suspend - rtcwake -m mem -s 300 4. press any key on hid to wake up the system Signed-off-by: Kiran K Signed-off-by: Chandrashekar Devegowda Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btintel_pcie.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index ce17c5ea67e8..22a2953adbd6 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -2416,6 +2416,13 @@ static void btintel_pcie_hw_error(struct hci_dev *hdev, u8 code) btintel_pcie_reset(hdev); } +static bool btintel_pcie_wakeup(struct hci_dev *hdev) +{ + struct btintel_pcie_data *data = hci_get_drvdata(hdev); + + return device_may_wakeup(&data->pdev->dev); +} + static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data) { int err; @@ -2441,6 +2448,7 @@ static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data) hdev->set_diag = btintel_set_diag; hdev->set_bdaddr = btintel_set_bdaddr; hdev->reset = btintel_pcie_reset; + hdev->wakeup = btintel_pcie_wakeup; err = hci_register_dev(hdev); if (err < 0) { From d4e99db3d942c8099006f3b7536bc52f766b475a Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sun, 10 Aug 2025 23:53:20 +0200 Subject: [PATCH 08/30] Bluetooth: Annotate struct hci_drv_rp_read_info with __counted_by_le() Add the __counted_by_le() compiler attribute to the flexible array member 'supported_commands' to improve access bounds-checking via CONFIG_UBSAN_BOUNDS and CONFIG_FORTIFY_SOURCE. Signed-off-by: Thorsten Blum Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci_drv.h b/include/net/bluetooth/hci_drv.h index 2f01c44f05ec..3fd6fdbdb02e 100644 --- a/include/net/bluetooth/hci_drv.h +++ b/include/net/bluetooth/hci_drv.h @@ -47,7 +47,7 @@ struct hci_drv_ev_cmd_complete { struct hci_drv_rp_read_info { __u8 driver_name[HCI_DRV_MAX_DRIVER_NAME_LENGTH]; __le16 num_supported_commands; - __le16 supported_commands[]; + __le16 supported_commands[] __counted_by_le(num_supported_commands); } __packed; /* Driver specific OGF (Opcode Group Field) From 5967c08545e9d591e06c205b74fd25f8a702029c Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 11 Aug 2025 11:19:06 +0200 Subject: [PATCH 09/30] Bluetooth: btintel_pcie: Use strscpy() instead of strscpy_pad() kzalloc() already zero-initializes the destination buffer 'data', making strscpy() sufficient for safely copying 'name'. The additional NUL-padding performed by strscpy_pad() is unnecessary. Add a new local variable to store the length of 'name' and reuse it instead of recalculating the same length. Signed-off-by: Thorsten Blum Reviewed-by: Paul Menzel Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btintel_pcie.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index 22a2953adbd6..a625a5b2154b 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -2242,6 +2242,7 @@ btintel_pcie_get_recovery(struct pci_dev *pdev, struct device *dev) { struct btintel_pcie_dev_recovery *tmp, *data = NULL; const char *name = pci_name(pdev); + const size_t name_len = strlen(name) + 1; struct hci_dev *hdev = to_hci_dev(dev); spin_lock(&btintel_pcie_recovery_lock); @@ -2258,11 +2259,11 @@ btintel_pcie_get_recovery(struct pci_dev *pdev, struct device *dev) return data; } - data = kzalloc(struct_size(data, name, strlen(name) + 1), GFP_ATOMIC); + data = kzalloc(struct_size(data, name, name_len), GFP_ATOMIC); if (!data) return NULL; - strscpy_pad(data->name, name, strlen(name) + 1); + strscpy(data->name, name, name_len); spin_lock(&btintel_pcie_recovery_lock); list_add_tail(&data->list, &btintel_pcie_recovery_list); spin_unlock(&btintel_pcie_recovery_lock); From 58fddb364dd5c4e9bf223a2113a42538d9c040de Mon Sep 17 00:00:00 2001 From: Kiran K Date: Wed, 6 Aug 2025 12:18:49 +0530 Subject: [PATCH 10/30] Bluetooth: btintel_pcie: Refactor Device Coredump As device coredumps are not HCI traces, maintain the device coredump at the driver level and eliminate the dependency on hdev_devcd*() Signed-off-by: Kiran K Fixes: 07e6bddb54b4 ("Bluetooth: btintel_pcie: Add support for device coredump") Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btintel_pcie.c | 218 +++++++++++-------------------- drivers/bluetooth/btintel_pcie.h | 2 + 2 files changed, 76 insertions(+), 144 deletions(-) diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index a625a5b2154b..6d3963bd56a9 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -559,25 +560,6 @@ static void btintel_pcie_mac_init(struct btintel_pcie_data *data) btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg); } -static int btintel_pcie_add_dmp_data(struct hci_dev *hdev, const void *data, int size) -{ - struct sk_buff *skb; - int err; - - skb = alloc_skb(size, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - skb_put_data(skb, data, size); - err = hci_devcd_append(hdev, skb); - if (err) { - bt_dev_err(hdev, "Failed to append data in the coredump"); - return err; - } - - return 0; -} - static int btintel_pcie_get_mac_access(struct btintel_pcie_data *data) { u32 reg; @@ -622,30 +604,35 @@ static void btintel_pcie_release_mac_access(struct btintel_pcie_data *data) btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg); } -static void btintel_pcie_copy_tlv(struct sk_buff *skb, enum btintel_pcie_tlv_type type, - void *data, int size) +static void *btintel_pcie_copy_tlv(void *dest, enum btintel_pcie_tlv_type type, + void *data, size_t size) { struct intel_tlv *tlv; - tlv = skb_put(skb, sizeof(*tlv) + size); + tlv = dest; tlv->type = type; tlv->len = size; memcpy(tlv->val, data, tlv->len); + return dest + sizeof(*tlv) + size; } static int btintel_pcie_read_dram_buffers(struct btintel_pcie_data *data) { - u32 offset, prev_size, wr_ptr_status, dump_size, i; + u32 offset, prev_size, wr_ptr_status, dump_size, data_len; struct btintel_pcie_dbgc *dbgc = &data->dbgc; - u8 buf_idx, dump_time_len, fw_build; struct hci_dev *hdev = data->hdev; + u8 *pdata, *p, buf_idx; struct intel_tlv *tlv; struct timespec64 now; - struct sk_buff *skb; struct tm tm_now; - char buf[256]; - u16 hdr_len; - int ret; + char fw_build[128]; + char ts[128]; + char vendor[64]; + char driver[64]; + + if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) + return -EOPNOTSUPP; + wr_ptr_status = btintel_pcie_rd_dev_mem(data, BTINTEL_PCIE_DBGC_CUR_DBGBUFF_STATUS); offset = wr_ptr_status & BTINTEL_PCIE_DBG_OFFSET_BIT_MASK; @@ -662,88 +649,84 @@ static int btintel_pcie_read_dram_buffers(struct btintel_pcie_data *data) else return -EINVAL; + snprintf(vendor, sizeof(vendor), "Vendor: Intel\n"); + snprintf(driver, sizeof(driver), "Driver: %s\n", + data->dmp_hdr.driver_name); + ktime_get_real_ts64(&now); time64_to_tm(now.tv_sec, 0, &tm_now); - dump_time_len = snprintf(buf, sizeof(buf), "Dump Time: %02d-%02d-%04ld %02d:%02d:%02d", + snprintf(ts, sizeof(ts), "Dump Time: %02d-%02d-%04ld %02d:%02d:%02d", tm_now.tm_mday, tm_now.tm_mon + 1, tm_now.tm_year + 1900, tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec); - fw_build = snprintf(buf + dump_time_len, sizeof(buf) - dump_time_len, + snprintf(fw_build, sizeof(fw_build), "Firmware Timestamp: Year %u WW %02u buildtype %u build %u", 2000 + (data->dmp_hdr.fw_timestamp >> 8), data->dmp_hdr.fw_timestamp & 0xff, data->dmp_hdr.fw_build_type, data->dmp_hdr.fw_build_num); - hdr_len = sizeof(*tlv) + sizeof(data->dmp_hdr.cnvi_bt) + - sizeof(*tlv) + sizeof(data->dmp_hdr.write_ptr) + - sizeof(*tlv) + sizeof(data->dmp_hdr.wrap_ctr) + - sizeof(*tlv) + sizeof(data->dmp_hdr.trigger_reason) + - sizeof(*tlv) + sizeof(data->dmp_hdr.fw_git_sha1) + - sizeof(*tlv) + sizeof(data->dmp_hdr.cnvr_top) + - sizeof(*tlv) + sizeof(data->dmp_hdr.cnvi_top) + - sizeof(*tlv) + dump_time_len + - sizeof(*tlv) + fw_build; + data_len = sizeof(*tlv) + sizeof(data->dmp_hdr.cnvi_bt) + + sizeof(*tlv) + sizeof(data->dmp_hdr.write_ptr) + + sizeof(*tlv) + sizeof(data->dmp_hdr.wrap_ctr) + + sizeof(*tlv) + sizeof(data->dmp_hdr.trigger_reason) + + sizeof(*tlv) + sizeof(data->dmp_hdr.fw_git_sha1) + + sizeof(*tlv) + sizeof(data->dmp_hdr.cnvr_top) + + sizeof(*tlv) + sizeof(data->dmp_hdr.cnvi_top) + + sizeof(*tlv) + strlen(ts) + + sizeof(*tlv) + strlen(fw_build) + + sizeof(*tlv) + strlen(vendor) + + sizeof(*tlv) + strlen(driver); - dump_size = hdr_len + sizeof(hdr_len); + /* + * sizeof(u32) - signature + * sizeof(data_len) - to store tlv data size + * data_len - TLV data + */ + dump_size = sizeof(u32) + sizeof(data_len) + data_len; - skb = alloc_skb(dump_size, GFP_KERNEL); - if (!skb) - return -ENOMEM; /* Add debug buffers data length to dump size */ dump_size += BTINTEL_PCIE_DBGC_BUFFER_SIZE * dbgc->count; - ret = hci_devcd_init(hdev, dump_size); - if (ret) { - bt_dev_err(hdev, "Failed to init devcoredump, err %d", ret); - kfree_skb(skb); - return ret; - } + pdata = vmalloc(dump_size); + if (!pdata) + return -ENOMEM; + p = pdata; - skb_put_data(skb, &hdr_len, sizeof(hdr_len)); + *(u32 *)p = BTINTEL_PCIE_MAGIC_NUM; + p += sizeof(u32); - btintel_pcie_copy_tlv(skb, BTINTEL_CNVI_BT, &data->dmp_hdr.cnvi_bt, - sizeof(data->dmp_hdr.cnvi_bt)); + *(u32 *)p = data_len; + p += sizeof(u32); - btintel_pcie_copy_tlv(skb, BTINTEL_WRITE_PTR, &data->dmp_hdr.write_ptr, - sizeof(data->dmp_hdr.write_ptr)); + + p = btintel_pcie_copy_tlv(p, BTINTEL_VENDOR, vendor, strlen(vendor)); + p = btintel_pcie_copy_tlv(p, BTINTEL_DRIVER, driver, strlen(driver)); + p = btintel_pcie_copy_tlv(p, BTINTEL_DUMP_TIME, ts, strlen(ts)); + p = btintel_pcie_copy_tlv(p, BTINTEL_FW_BUILD, fw_build, + strlen(fw_build)); + p = btintel_pcie_copy_tlv(p, BTINTEL_CNVI_BT, &data->dmp_hdr.cnvi_bt, + sizeof(data->dmp_hdr.cnvi_bt)); + p = btintel_pcie_copy_tlv(p, BTINTEL_WRITE_PTR, &data->dmp_hdr.write_ptr, + sizeof(data->dmp_hdr.write_ptr)); + p = btintel_pcie_copy_tlv(p, BTINTEL_WRAP_CTR, &data->dmp_hdr.wrap_ctr, + sizeof(data->dmp_hdr.wrap_ctr)); data->dmp_hdr.wrap_ctr = btintel_pcie_rd_dev_mem(data, BTINTEL_PCIE_DBGC_DBGBUFF_WRAP_ARND); - btintel_pcie_copy_tlv(skb, BTINTEL_WRAP_CTR, &data->dmp_hdr.wrap_ctr, - sizeof(data->dmp_hdr.wrap_ctr)); + p = btintel_pcie_copy_tlv(p, BTINTEL_TRIGGER_REASON, &data->dmp_hdr.trigger_reason, + sizeof(data->dmp_hdr.trigger_reason)); + p = btintel_pcie_copy_tlv(p, BTINTEL_FW_SHA, &data->dmp_hdr.fw_git_sha1, + sizeof(data->dmp_hdr.fw_git_sha1)); + p = btintel_pcie_copy_tlv(p, BTINTEL_CNVR_TOP, &data->dmp_hdr.cnvr_top, + sizeof(data->dmp_hdr.cnvr_top)); + p = btintel_pcie_copy_tlv(p, BTINTEL_CNVI_TOP, &data->dmp_hdr.cnvi_top, + sizeof(data->dmp_hdr.cnvi_top)); - btintel_pcie_copy_tlv(skb, BTINTEL_TRIGGER_REASON, &data->dmp_hdr.trigger_reason, - sizeof(data->dmp_hdr.trigger_reason)); - - btintel_pcie_copy_tlv(skb, BTINTEL_FW_SHA, &data->dmp_hdr.fw_git_sha1, - sizeof(data->dmp_hdr.fw_git_sha1)); - - btintel_pcie_copy_tlv(skb, BTINTEL_CNVR_TOP, &data->dmp_hdr.cnvr_top, - sizeof(data->dmp_hdr.cnvr_top)); - - btintel_pcie_copy_tlv(skb, BTINTEL_CNVI_TOP, &data->dmp_hdr.cnvi_top, - sizeof(data->dmp_hdr.cnvi_top)); - - btintel_pcie_copy_tlv(skb, BTINTEL_DUMP_TIME, buf, dump_time_len); - - btintel_pcie_copy_tlv(skb, BTINTEL_FW_BUILD, buf + dump_time_len, fw_build); - - ret = hci_devcd_append(hdev, skb); - if (ret) - goto exit_err; - - for (i = 0; i < dbgc->count; i++) { - ret = btintel_pcie_add_dmp_data(hdev, dbgc->bufs[i].data, - BTINTEL_PCIE_DBGC_BUFFER_SIZE); - if (ret) - break; - } - -exit_err: - hci_devcd_complete(hdev); - return ret; + memcpy(p, dbgc->bufs[0].data, dbgc->count * BTINTEL_PCIE_DBGC_BUFFER_SIZE); + dev_coredumpv(&hdev->dev, pdata, dump_size, GFP_KERNEL); + return 0; } static void btintel_pcie_dump_traces(struct hci_dev *hdev) @@ -765,51 +748,6 @@ static void btintel_pcie_dump_traces(struct hci_dev *hdev) bt_dev_err(hdev, "Failed to dump traces: (%d)", ret); } -static void btintel_pcie_dump_hdr(struct hci_dev *hdev, struct sk_buff *skb) -{ - struct btintel_pcie_data *data = hci_get_drvdata(hdev); - u16 len = skb->len; - u16 *hdrlen_ptr; - char buf[80]; - - hdrlen_ptr = skb_put_zero(skb, sizeof(len)); - - snprintf(buf, sizeof(buf), "Controller Name: 0x%X\n", - INTEL_HW_VARIANT(data->dmp_hdr.cnvi_bt)); - skb_put_data(skb, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "Firmware Build Number: %u\n", - data->dmp_hdr.fw_build_num); - skb_put_data(skb, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "Driver: %s\n", data->dmp_hdr.driver_name); - skb_put_data(skb, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "Vendor: Intel\n"); - skb_put_data(skb, buf, strlen(buf)); - - *hdrlen_ptr = skb->len - len; -} - -static void btintel_pcie_dump_notify(struct hci_dev *hdev, int state) -{ - struct btintel_pcie_data *data = hci_get_drvdata(hdev); - - switch (state) { - case HCI_DEVCOREDUMP_IDLE: - data->dmp_hdr.state = HCI_DEVCOREDUMP_IDLE; - break; - case HCI_DEVCOREDUMP_ACTIVE: - data->dmp_hdr.state = HCI_DEVCOREDUMP_ACTIVE; - break; - case HCI_DEVCOREDUMP_TIMEOUT: - case HCI_DEVCOREDUMP_ABORT: - case HCI_DEVCOREDUMP_DONE: - data->dmp_hdr.state = HCI_DEVCOREDUMP_IDLE; - break; - } -} - /* This function enables BT function by setting BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT bit in * BTINTEL_PCIE_CSR_FUNC_CTRL_REG register and wait for MSI-X with * BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0. @@ -1383,6 +1321,11 @@ static void btintel_pcie_rx_work(struct work_struct *work) struct btintel_pcie_data, rx_work); struct sk_buff *skb; + if (test_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags)) { + btintel_pcie_dump_traces(data->hdev); + clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags); + } + if (test_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags)) { /* Unlike usb products, controller will not send hardware * exception event on exception. Instead controller writes the @@ -1395,11 +1338,6 @@ static void btintel_pcie_rx_work(struct work_struct *work) clear_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags); } - if (test_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags)) { - btintel_pcie_dump_traces(data->hdev); - clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags); - } - /* Process the sk_buf in queue and send to the HCI layer */ while ((skb = skb_dequeue(&data->rx_skb_q))) { btintel_pcie_recv_frame(data, skb); @@ -2190,13 +2128,6 @@ static int btintel_pcie_setup_internal(struct hci_dev *hdev) if (ver_tlv.img_type == 0x02 || ver_tlv.img_type == 0x03) data->dmp_hdr.fw_git_sha1 = ver_tlv.git_sha1; - err = hci_devcd_register(hdev, btintel_pcie_dump_traces, btintel_pcie_dump_hdr, - btintel_pcie_dump_notify); - if (err) { - bt_dev_err(hdev, "Failed to register coredump (%d)", err); - goto exit_error; - } - btintel_print_fseq_info(hdev); exit_error: kfree_skb(skb); @@ -2326,7 +2257,6 @@ static void btintel_pcie_removal_work(struct work_struct *wk) btintel_pcie_synchronize_irqs(data); flush_work(&data->rx_work); - flush_work(&data->hdev->dump.dump_rx); bt_dev_dbg(data->hdev, "Release bluetooth interface"); btintel_pcie_release_hdev(data); diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h index 0fa876c5b954..04b21f968ad3 100644 --- a/drivers/bluetooth/btintel_pcie.h +++ b/drivers/bluetooth/btintel_pcie.h @@ -132,6 +132,8 @@ enum btintel_pcie_tlv_type { BTINTEL_CNVI_TOP, BTINTEL_DUMP_TIME, BTINTEL_FW_BUILD, + BTINTEL_VENDOR, + BTINTEL_DRIVER }; /* causes for the MBOX interrupts */ From 8183c8ea8762b1de6d2e32f36531d6ea81878f11 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 11 Aug 2025 17:04:00 +0200 Subject: [PATCH 11/30] MAINTAINERS: add a sub-entry for the Qualcomm bluetooth driver Patches modifying drivers/bluetooth/hci_qca.c should be Cc'ed to the linux-arm-msm mailing list so that Qualcomm maintainers and reviewers can get notified about proposed changes to it. Add a sub-entry that adds the mailing list to the list of addresses returned by get_maintainer.pl. Acked-by: Konrad Dybcio Signed-off-by: Bartosz Golaszewski Signed-off-by: Luiz Augusto von Dentz --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 2ba1e447f720..7b5a3caebf68 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20686,6 +20686,13 @@ S: Maintained F: Documentation/devicetree/bindings/net/qcom,bam-dmux.yaml F: drivers/net/wwan/qcom_bam_dmux.c +QUALCOMM BLUETOOTH DRIVER +L: linux-arm-msm@vger.kernel.org +S: Maintained +F: drivers/bluetooth/btqca.[ch] +F: drivers/bluetooth/btqcomsmd.c +F: drivers/bluetooth/hci_qca.c + QUALCOMM CAMERA SUBSYSTEM DRIVER M: Robert Foss M: Todor Tomov From d79c7d01f1c8bcf9a48337c8960d618fbe31fc0c Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Fri, 27 Jun 2025 11:18:29 -0400 Subject: [PATCH 12/30] Bluetooth: ISO: Don't initiate CIS connections if there are no buffers If the controller has no buffers left return -ENOBUFF to indicate that iso_cnt might be out of sync. Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/iso.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index 5ce823ca3aaf..ac6e83313b9b 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -458,6 +458,13 @@ static int iso_connect_cis(struct sock *sk) goto unlock; } + /* Check if there are available buffers for output/TX. */ + if (iso_pi(sk)->qos.ucast.out.sdu && !hci_iso_count(hdev) && + (hdev->iso_pkts && !hdev->iso_cnt)) { + err = -ENOBUFS; + goto unlock; + } + /* Just bind if DEFER_SETUP has been set */ if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { hcon = hci_bind_cis(hdev, &iso_pi(sk)->dst, From 69a86cc17811c411fe336eb484a23bc0b425a814 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Fri, 27 Jun 2025 11:18:30 -0400 Subject: [PATCH 13/30] Bluetooth: HCI: Fix using LE/ACL buffers for ISO packets ISO packets shall not use LE/ACL buffer pool, that feature seem to be exclusive to LE-ACL only. Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_conn.c | 7 +++---- net/bluetooth/hci_core.c | 6 ++---- net/bluetooth/hci_event.c | 16 +++------------- 3 files changed, 8 insertions(+), 21 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index e524bb59bff2..091cff2155e6 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -924,10 +924,9 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t case CIS_LINK: case BIS_LINK: case PA_LINK: - if (hdev->iso_mtu) - /* Dedicated ISO Buffer exists */ - break; - fallthrough; + if (!hdev->iso_mtu) + return ERR_PTR(-ECONNREFUSED); + break; case LE_LINK: if (hdev->le_mtu && hdev->le_mtu < HCI_MIN_LE_MTU) return ERR_PTR(-ECONNREFUSED); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 55e0722fd066..e2bffad9816f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3399,8 +3399,7 @@ static inline void hci_quote_sent(struct hci_conn *conn, int num, int *quote) case CIS_LINK: case BIS_LINK: case PA_LINK: - cnt = hdev->iso_mtu ? hdev->iso_cnt : - hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt; + cnt = hdev->iso_cnt; break; default: cnt = 0; @@ -3759,8 +3758,7 @@ static void hci_sched_iso(struct hci_dev *hdev, __u8 type) if (!hci_conn_num(hdev, type)) return; - cnt = hdev->iso_pkts ? &hdev->iso_cnt : - hdev->le_pkts ? &hdev->le_cnt : &hdev->acl_cnt; + cnt = &hdev->iso_cnt; while (*cnt && (conn = hci_low_sent(hdev, type, "e))) { while (quote-- && (skb = skb_dequeue(&conn->data_q))) { BT_DBG("skb %p len %d", skb, skb->len); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index fe49e8a7969f..d790b0d4eb9a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4461,19 +4461,9 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data, case CIS_LINK: case BIS_LINK: case PA_LINK: - if (hdev->iso_pkts) { - hdev->iso_cnt += count; - if (hdev->iso_cnt > hdev->iso_pkts) - hdev->iso_cnt = hdev->iso_pkts; - } else if (hdev->le_pkts) { - hdev->le_cnt += count; - if (hdev->le_cnt > hdev->le_pkts) - hdev->le_cnt = hdev->le_pkts; - } else { - hdev->acl_cnt += count; - if (hdev->acl_cnt > hdev->acl_pkts) - hdev->acl_cnt = hdev->acl_pkts; - } + hdev->iso_cnt += count; + if (hdev->iso_cnt > hdev->iso_pkts) + hdev->iso_cnt = hdev->iso_pkts; break; default: From 339a87883a14d6a818ca436fed41aa5d10e0f4bd Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 13 Aug 2025 15:21:19 -0400 Subject: [PATCH 14/30] Bluetooth: ISO: Use sk_sndtimeo as conn_timeout This aligns the usage of socket sk_sndtimeo as conn_timeout when initiating a connection and then use it when scheduling the resulting HCI command, similar to what has been done in bf98feea5b65 ("Bluetooth: hci_conn: Always use sk_timeo as conn_timeout"). Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci_core.h | 10 ++++++---- net/bluetooth/hci_conn.c | 20 ++++++++++++-------- net/bluetooth/iso.c | 16 ++++++++++------ 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 6560b32f3125..a068beae9318 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1587,16 +1587,18 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, __u16 setting, struct bt_codec *codec, u16 timeout); struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst, - __u8 dst_type, struct bt_iso_qos *qos); + __u8 dst_type, struct bt_iso_qos *qos, + u16 timeout); struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid, struct bt_iso_qos *qos, - __u8 base_len, __u8 *base); + __u8 base_len, __u8 *base, u16 timeout); struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst, - __u8 dst_type, struct bt_iso_qos *qos); + __u8 dst_type, struct bt_iso_qos *qos, + u16 timeout); struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type, __u8 sid, struct bt_iso_qos *qos, - __u8 data_len, __u8 *data); + __u8 data_len, __u8 *data, u16 timeout); struct hci_conn *hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type, __u8 sid, struct bt_iso_qos *qos); int hci_conn_big_create_sync(struct hci_dev *hdev, struct hci_conn *hcon, diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 091cff2155e6..111f0e37b672 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -1539,7 +1539,7 @@ static int qos_set_bis(struct hci_dev *hdev, struct bt_iso_qos *qos) /* This function requires the caller holds hdev->lock */ static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid, struct bt_iso_qos *qos, - __u8 base_len, __u8 *base) + __u8 base_len, __u8 *base, u16 timeout) { struct hci_conn *conn; int err; @@ -1581,6 +1581,7 @@ static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst, conn->state = BT_CONNECT; conn->sid = sid; + conn->conn_timeout = timeout; hci_conn_hold(conn); return conn; @@ -1921,7 +1922,8 @@ static bool hci_le_set_cig_params(struct hci_conn *conn, struct bt_iso_qos *qos) } struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst, - __u8 dst_type, struct bt_iso_qos *qos) + __u8 dst_type, struct bt_iso_qos *qos, + u16 timeout) { struct hci_conn *cis; @@ -1936,6 +1938,7 @@ struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst, cis->dst_type = dst_type; cis->iso_qos.ucast.cig = BT_ISO_QOS_CIG_UNSET; cis->iso_qos.ucast.cis = BT_ISO_QOS_CIS_UNSET; + cis->conn_timeout = timeout; } if (cis->state == BT_CONNECTED) @@ -2175,7 +2178,7 @@ static void create_big_complete(struct hci_dev *hdev, void *data, int err) struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid, struct bt_iso_qos *qos, - __u8 base_len, __u8 *base) + __u8 base_len, __u8 *base, u16 timeout) { struct hci_conn *conn; struct hci_conn *parent; @@ -2196,7 +2199,7 @@ struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid, base, base_len); /* We need hci_conn object using the BDADDR_ANY as dst */ - conn = hci_add_bis(hdev, dst, sid, qos, base_len, eir); + conn = hci_add_bis(hdev, dst, sid, qos, base_len, eir, timeout); if (IS_ERR(conn)) return conn; @@ -2249,13 +2252,13 @@ static void bis_mark_per_adv(struct hci_conn *conn, void *data) struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type, __u8 sid, struct bt_iso_qos *qos, - __u8 base_len, __u8 *base) + __u8 base_len, __u8 *base, u16 timeout) { struct hci_conn *conn; int err; struct iso_list_data data; - conn = hci_bind_bis(hdev, dst, sid, qos, base_len, base); + conn = hci_bind_bis(hdev, dst, sid, qos, base_len, base, timeout); if (IS_ERR(conn)) return conn; @@ -2298,7 +2301,8 @@ struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, } struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst, - __u8 dst_type, struct bt_iso_qos *qos) + __u8 dst_type, struct bt_iso_qos *qos, + u16 timeout) { struct hci_conn *le; struct hci_conn *cis; @@ -2322,7 +2326,7 @@ struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst, hci_iso_qos_setup(hdev, le, &qos->ucast.in, le->le_rx_phy ? le->le_rx_phy : hdev->le_rx_def_phys); - cis = hci_bind_cis(hdev, dst, dst_type, qos); + cis = hci_bind_cis(hdev, dst, dst_type, qos, timeout); if (IS_ERR(cis)) { hci_conn_drop(le); return cis; diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index ac6e83313b9b..5c68c0ea7d97 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -91,8 +91,8 @@ static struct sock *iso_get_sock(bdaddr_t *src, bdaddr_t *dst, iso_sock_match_t match, void *data); /* ---- ISO timers ---- */ -#define ISO_CONN_TIMEOUT (HZ * 40) -#define ISO_DISCONN_TIMEOUT (HZ * 2) +#define ISO_CONN_TIMEOUT secs_to_jiffies(20) +#define ISO_DISCONN_TIMEOUT secs_to_jiffies(2) static void iso_conn_free(struct kref *ref) { @@ -367,7 +367,8 @@ static int iso_connect_bis(struct sock *sk) if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { hcon = hci_bind_bis(hdev, &iso_pi(sk)->dst, iso_pi(sk)->bc_sid, &iso_pi(sk)->qos, iso_pi(sk)->base_len, - iso_pi(sk)->base); + iso_pi(sk)->base, + READ_ONCE(sk->sk_sndtimeo)); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); goto unlock; @@ -376,7 +377,8 @@ static int iso_connect_bis(struct sock *sk) hcon = hci_connect_bis(hdev, &iso_pi(sk)->dst, le_addr_type(iso_pi(sk)->dst_type), iso_pi(sk)->bc_sid, &iso_pi(sk)->qos, - iso_pi(sk)->base_len, iso_pi(sk)->base); + iso_pi(sk)->base_len, iso_pi(sk)->base, + READ_ONCE(sk->sk_sndtimeo)); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); goto unlock; @@ -469,7 +471,8 @@ static int iso_connect_cis(struct sock *sk) if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { hcon = hci_bind_cis(hdev, &iso_pi(sk)->dst, le_addr_type(iso_pi(sk)->dst_type), - &iso_pi(sk)->qos); + &iso_pi(sk)->qos, + READ_ONCE(sk->sk_sndtimeo)); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); goto unlock; @@ -477,7 +480,8 @@ static int iso_connect_cis(struct sock *sk) } else { hcon = hci_connect_cis(hdev, &iso_pi(sk)->dst, le_addr_type(iso_pi(sk)->dst_type), - &iso_pi(sk)->qos); + &iso_pi(sk)->qos, + READ_ONCE(sk->sk_sndtimeo)); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); goto unlock; From c9beb36c14660713b948e289b1e352cc3d386d44 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 13 Aug 2025 15:57:39 -0400 Subject: [PATCH 15/30] Bluetooth: hci_core: Detect if an ISO link has stalled This attempts to detect if an ISO link has been waiting for an ISO buffer for longer than the maximum allowed transport latency then proceed to use hci_link_tx_to which prints an error and disconnects. Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci.h | 1 + include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 34 ++++++++++++++++++++++++-------- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index df1847b74e55..9ecc70baaca9 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -488,6 +488,7 @@ enum { #define HCI_AUTO_OFF_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ #define HCI_ACL_CONN_TIMEOUT msecs_to_jiffies(20000) /* 20 seconds */ #define HCI_LE_CONN_TIMEOUT msecs_to_jiffies(20000) /* 20 seconds */ +#define HCI_ISO_TX_TIMEOUT usecs_to_jiffies(0x7fffff) /* 8388607 usecs */ /* HCI data types */ #define HCI_COMMAND_PKT 0x01 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index a068beae9318..2924c2bf2a98 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -487,6 +487,7 @@ struct hci_dev { unsigned long acl_last_tx; unsigned long le_last_tx; + unsigned long iso_last_tx; __u8 le_tx_def_phys; __u8 le_rx_def_phys; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e2bffad9816f..4cf4bb1187dc 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3585,24 +3585,37 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type) static void __check_timeout(struct hci_dev *hdev, unsigned int cnt, u8 type) { - unsigned long last_tx; + unsigned long timeout; if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) return; switch (type) { + case ACL_LINK: + /* tx timeout must be longer than maximum link supervision + * timeout (40.9 seconds) + */ + timeout = hdev->acl_last_tx + HCI_ACL_TX_TIMEOUT; + break; case LE_LINK: - last_tx = hdev->le_last_tx; + /* tx timeout must be longer than maximum link supervision + * timeout (40.9 seconds) + */ + timeout = hdev->le_last_tx + HCI_ACL_TX_TIMEOUT; + break; + case CIS_LINK: + case BIS_LINK: + case PA_LINK: + /* tx timeout must be longer than the maximum transport latency + * (8.388607 seconds) + */ + timeout = hdev->iso_last_tx + HCI_ISO_TX_TIMEOUT; break; default: - last_tx = hdev->acl_last_tx; - break; + return; } - /* tx timeout must be longer than maximum link supervision timeout - * (40.9 seconds) - */ - if (!cnt && time_after(jiffies, last_tx + HCI_ACL_TX_TIMEOUT)) + if (!cnt && time_after(jiffies, timeout)) hci_link_tx_to(hdev, type); } @@ -3759,10 +3772,15 @@ static void hci_sched_iso(struct hci_dev *hdev, __u8 type) return; cnt = &hdev->iso_cnt; + + __check_timeout(hdev, *cnt, type); + while (*cnt && (conn = hci_low_sent(hdev, type, "e))) { while (quote-- && (skb = skb_dequeue(&conn->data_q))) { BT_DBG("skb %p len %d", skb, skb->len); + hci_send_conn_frame(hdev, conn, skb); + hdev->iso_last_tx = jiffies; conn->sent++; if (conn->sent == ~0) From 79e562a52adea4afa0601a15964498fae66c823c Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 20 Aug 2025 08:50:12 -0400 Subject: [PATCH 16/30] Bluetooth: MGMT: Fix not exposing debug UUID on MGMT_OP_READ_EXP_FEATURES_INFO The debug UUID was only getting set if MGMT_OP_READ_EXP_FEATURES_INFO was not called with a specific index which breaks the likes of bluetoothd since it only invokes MGMT_OP_READ_EXP_FEATURES_INFO when an adapter is plugged, so instead of depending hdev not to be set just enable the UUID on any index like it was done with iso_sock_uuid. Fixes: e625e50ceee1 ("Bluetooth: Introduce debug feature when dynamic debug is disabled") Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/mgmt.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 225140fcb3d6..a3d16eece0d2 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4542,13 +4542,11 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev, return -ENOMEM; #ifdef CONFIG_BT_FEATURE_DEBUG - if (!hdev) { - flags = bt_dbg_get() ? BIT(0) : 0; + flags = bt_dbg_get() ? BIT(0) : 0; - memcpy(rp->features[idx].uuid, debug_uuid, 16); - rp->features[idx].flags = cpu_to_le32(flags); - idx++; - } + memcpy(rp->features[idx].uuid, debug_uuid, 16); + rp->features[idx].flags = cpu_to_le32(flags); + idx++; #endif if (hdev && hci_dev_le_state_simultaneous(hdev)) { From 9eb14331885b09adfa7fe69a5a4603e24909c88f Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Mon, 18 Aug 2025 16:43:53 -0400 Subject: [PATCH 17/30] Bluetooth: Add function and line information to bt_dbg When enabling debug via CONFIG_BT_FEATURE_DEBUG include function and line information by default otherwise it is hard to make any sense of which function the logs comes from. Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/bluetooth.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index e5751f3070b8..d46ed9011ee5 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -272,7 +272,8 @@ void bt_err_ratelimited(const char *fmt, ...); #define BT_ERR(fmt, ...) bt_err(fmt "\n", ##__VA_ARGS__) #if IS_ENABLED(CONFIG_BT_FEATURE_DEBUG) -#define BT_DBG(fmt, ...) bt_dbg(fmt "\n", ##__VA_ARGS__) +#define BT_DBG(fmt, ...) \ + bt_dbg("%s:%d: " fmt "\n", __func__, __LINE__, ##__VA_ARGS__) #else #define BT_DBG(fmt, ...) pr_debug(fmt "\n", ##__VA_ARGS__) #endif From 3c34d6428740e47b29ae3afd85d6f9eb656a3ea3 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Tue, 19 Aug 2025 15:31:28 -0400 Subject: [PATCH 18/30] Bluetooth: hci_core: Print number of packets in conn->data_q This attempts to print the number of packets pending to be transmitted in the conn->data_q. Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_core.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 4cf4bb1187dc..198819577fe5 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3267,6 +3267,8 @@ static void hci_queue_acl(struct hci_chan *chan, struct sk_buff_head *queue, spin_unlock_bh(&queue->lock); } + + bt_dev_dbg(hdev, "chan %p queued %d", chan, skb_queue_len(queue)); } void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags) @@ -3298,6 +3300,10 @@ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb) hci_skb_pkt_type(skb) = HCI_SCODATA_PKT; skb_queue_tail(&conn->data_q, skb); + + bt_dev_dbg(hdev, "hcon %p queued %d", conn, + skb_queue_len(&conn->data_q)); + queue_work(hdev->workqueue, &hdev->tx_work); } @@ -3357,6 +3363,8 @@ static void hci_queue_iso(struct hci_conn *conn, struct sk_buff_head *queue, __skb_queue_tail(queue, skb); } while (list); } + + bt_dev_dbg(hdev, "hcon %p queued %d", conn, skb_queue_len(queue)); } void hci_send_iso(struct hci_conn *conn, struct sk_buff *skb) From 48a258b198c12685747beaf6392f2b68e6c542c2 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 20 Aug 2025 12:21:09 -0400 Subject: [PATCH 19/30] Bluetooth: hci_core: Print information of hcon on hci_low_sent This prints the information about the hcon on hci_low_sent to confirm all connection are being processed. Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 198819577fe5..3418d7b964a1 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3435,6 +3435,10 @@ static struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, skb_queue_empty(&c->data_q)) continue; + bt_dev_dbg(hdev, "hcon %p state %s queued %d", c, + state_to_string(c->state), + skb_queue_len(&c->data_q)); + if (c->state != BT_CONNECTED && c->state != BT_CONFIG) continue; From 7722d6fb54e428a8f657fccf422095a8d7e2d72c Mon Sep 17 00:00:00 2001 From: Arkadiusz Bokowy Date: Wed, 27 Aug 2025 18:40:16 +0200 Subject: [PATCH 20/30] Bluetooth: btusb: Check for unexpected bytes when defragmenting HCI frames Some Barrot based USB Bluetooth dongles erroneously send one extra random byte for the HCI_OP_READ_LOCAL_EXT_FEATURES command. The consequence of that is that the next HCI transfer is misaligned by one byte causing undefined behavior. In most cases the response event for the next command fails with random error code. Since the HCI_OP_READ_LOCAL_EXT_FEATURES command is used during HCI controller initialization, the initialization fails rendering the USB dongle not usable. > [59.464099] usb 1-1.3: new full-speed USB device number 11 using xhci_hcd > [59.561617] usb 1-1.3: New USB device found, idVendor=33fa, idProduct=0012, bcdDevice=88.91 > [59.561642] usb 1-1.3: New USB device strings: Mfr=0, Product=2, SerialNumber=0 > [59.561656] usb 1-1.3: Product: UGREEN BT6.0 Adapter > [61.720116] Bluetooth: hci1: command 0x1005 tx timeout > [61.720167] Bluetooth: hci1: Opcode 0x1005 failed: -110 This patch was tested with the 33fa:0012 device. The info from the /sys/kernel/debug/usb/devices is shown below: T: Bus=01 Lev=02 Prnt=02 Port=02 Cnt=01 Dev#= 12 Spd=12 MxCh= 0 D: Ver= 2.00 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=33fa ProdID=0012 Rev=88.91 S: Product=UGREEN BT6.0 Adapter C:* #Ifs= 2 Cfg#= 1 Atr=c0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms Now the device is initialized properly: > [43.329852] usb 1-1.4: new full-speed USB device number 4 using dwc_otg > [43.446790] usb 1-1.4: New USB device found, idVendor=33fa, idProduct=0012, bcdDevice=88.91 > [43.446813] usb 1-1.4: New USB device strings: Mfr=0, Product=2, SerialNumber=0 > [43.446821] usb 1-1.4: Product: UGREEN BT6.0 Adapter > [43.582024] Bluetooth: hci1: Unexpected continuation: 1 bytes > [43.703025] Bluetooth: hci1: Unexpected continuation: 1 bytes > [43.750141] Bluetooth: MGMT ver 1.23 Link: https://github.com/bluez/bluez/issues/1326 Signed-off-by: Arkadiusz Bokowy Tested-by: Arkadiusz Bokowy Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 3595a8bad6bd..505efc4872c3 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -66,6 +66,7 @@ static struct usb_driver btusb_driver; #define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25) #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) #define BTUSB_ACTIONS_SEMI BIT(27) +#define BTUSB_BARROT BIT(28) static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ @@ -812,6 +813,10 @@ static const struct usb_device_id quirks_table[] = { { USB_DEVICE(0x0cb5, 0xc547), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, + /* Barrot Technology Bluetooth devices */ + { USB_DEVICE(0x33fa, 0x0010), .driver_info = BTUSB_BARROT }, + { USB_DEVICE(0x33fa, 0x0012), .driver_info = BTUSB_BARROT }, + /* Actions Semiconductor ATS2851 based devices */ { USB_DEVICE(0x10d7, 0xb012), .driver_info = BTUSB_ACTIONS_SEMI }, @@ -1194,6 +1199,18 @@ static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count) } if (!hci_skb_expect(skb)) { + /* Each chunk should correspond to at least 1 or more + * events so if there are still bytes left that doesn't + * constitute a new event this is likely a bug in the + * controller. + */ + if (count && count < HCI_EVENT_HDR_SIZE) { + bt_dev_warn(data->hdev, + "Unexpected continuation: %d bytes", + count); + count = 0; + } + /* Complete frame */ btusb_recv_event(data, skb); skb = NULL; From 93f06f8f0daf43d87b4f61a3535a9cda62c61dd7 Mon Sep 17 00:00:00 2001 From: Calvin Owens Date: Mon, 25 Aug 2025 21:11:08 -0700 Subject: [PATCH 21/30] Bluetooth: remove duplicate h4_recv_buf() in header The "h4_recv.h" header contains a duplicate h4_recv_buf() that is nearly but not quite identical to the h4_recv_buf() in hci_h4.c. This duplicated header was added in commit 07eb96a5a7b0 ("Bluetooth: bpa10x: Use separate h4_recv_buf helper"). I wasn't able to find any explanation for duplicating the code in the discussion: https://lore.kernel.org/all/20180320181855.37297-1-marcel@holtmann.org/ https://lore.kernel.org/all/20180324091954.73229-2-marcel@holtmann.org/ Unfortunately, in the years since, several other drivers have come to also rely on this duplicated function, probably by accident. This is, at the very least, *extremely* confusing. It's also caused real issues when it's become out-of-sync, see the following: ef564119ba83 ("Bluetooth: hci_h4: Add support for ISO packets") 61b27cdf025b ("Bluetooth: hci_h4: Add support for ISO packets in h4_recv.h") This is the full diff between the two implementations today: --- orig.c +++ copy.c @@ -1,117 +1,100 @@ { - struct hci_uart *hu = hci_get_drvdata(hdev); - u8 alignment = hu->alignment ? hu->alignment : 1; - /* Check for error from previous call */ if (IS_ERR(skb)) skb = NULL; while (count) { int i, len; - /* remove padding bytes from buffer */ - for (; hu->padding && count > 0; hu->padding--) { - count--; - buffer++; - } - if (!count) - break; - if (!skb) { for (i = 0; i < pkts_count; i++) { if (buffer[0] != (&pkts[i])->type) continue; skb = bt_skb_alloc((&pkts[i])->maxlen, GFP_ATOMIC); if (!skb) return ERR_PTR(-ENOMEM); hci_skb_pkt_type(skb) = (&pkts[i])->type; hci_skb_expect(skb) = (&pkts[i])->hlen; break; } /* Check for invalid packet type */ if (!skb) return ERR_PTR(-EILSEQ); count -= 1; buffer += 1; } len = min_t(uint, hci_skb_expect(skb) - skb->len, count); skb_put_data(skb, buffer, len); count -= len; buffer += len; /* Check for partial packet */ if (skb->len < hci_skb_expect(skb)) continue; for (i = 0; i < pkts_count; i++) { if (hci_skb_pkt_type(skb) == (&pkts[i])->type) break; } if (i >= pkts_count) { kfree_skb(skb); return ERR_PTR(-EILSEQ); } if (skb->len == (&pkts[i])->hlen) { u16 dlen; switch ((&pkts[i])->lsize) { case 0: /* No variable data length */ dlen = 0; break; case 1: /* Single octet variable length */ dlen = skb->data[(&pkts[i])->loff]; hci_skb_expect(skb) += dlen; if (skb_tailroom(skb) < dlen) { kfree_skb(skb); return ERR_PTR(-EMSGSIZE); } break; case 2: /* Double octet variable length */ dlen = get_unaligned_le16(skb->data + (&pkts[i])->loff); hci_skb_expect(skb) += dlen; if (skb_tailroom(skb) < dlen) { kfree_skb(skb); return ERR_PTR(-EMSGSIZE); } break; default: /* Unsupported variable length */ kfree_skb(skb); return ERR_PTR(-EILSEQ); } if (!dlen) { - hu->padding = (skb->len + 1) % alignment; - hu->padding = (alignment - hu->padding) % alignment; - /* No more data, complete frame */ (&pkts[i])->recv(hdev, skb); skb = NULL; } } else { - hu->padding = (skb->len + 1) % alignment; - hu->padding = (alignment - hu->padding) % alignment; - /* Complete frame */ (&pkts[i])->recv(hdev, skb); skb = NULL; } } return skb; } -EXPORT_SYMBOL_GPL(h4_recv_buf) As I read this: If alignment is one, and padding is zero, padding remains zero throughout the loop. So it seems to me that the two functions behave strictly identically in that case. All the duplicated defines are also identical, as is the duplicated h4_recv_pkt structure declaration. All four drivers which use the duplicated function use the default alignment of one, and the default padding of zero. I therefore conclude the duplicate function may be safely replaced with the core one. I raised this in an RFC a few months ago, and didn't get much interest: https://lore.kernel.org/all/CABBYNZ+ONkYtq2fR-8PtL3X-vetvJ0BdP4MTw9cNpjLDzG3HUQ@mail.gmail.com/ ...but I'm still wary I've missed something, and I'd really appreciate more eyeballs on it. I tested this successfully on btnxpuart a few months ago, but unfortunately I no longer have access to that hardware. Cc: Marcel Holtmann Signed-off-by: Calvin Owens Reviewed-by: Paul Menzel Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/bpa10x.c | 2 +- drivers/bluetooth/btmtksdio.c | 2 +- drivers/bluetooth/btmtkuart.c | 2 +- drivers/bluetooth/btnxpuart.c | 2 +- drivers/bluetooth/h4_recv.h | 153 ---------------------------------- 5 files changed, 4 insertions(+), 157 deletions(-) delete mode 100644 drivers/bluetooth/h4_recv.h diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c index 8b43dfc755de..b7ba667a3d09 100644 --- a/drivers/bluetooth/bpa10x.c +++ b/drivers/bluetooth/bpa10x.c @@ -20,7 +20,7 @@ #include #include -#include "h4_recv.h" +#include "hci_uart.h" #define VERSION "0.11" diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index 4fc673640bfc..50abefba6d04 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -29,7 +29,7 @@ #include #include -#include "h4_recv.h" +#include "hci_uart.h" #include "btmtk.h" #define VERSION "0.1" diff --git a/drivers/bluetooth/btmtkuart.c b/drivers/bluetooth/btmtkuart.c index 76995cfcd534..d9b90ea2ad38 100644 --- a/drivers/bluetooth/btmtkuart.c +++ b/drivers/bluetooth/btmtkuart.c @@ -27,7 +27,7 @@ #include #include -#include "h4_recv.h" +#include "hci_uart.h" #include "btmtk.h" #define VERSION "0.2" diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c index 76e7f857fb7d..d5153fed0518 100644 --- a/drivers/bluetooth/btnxpuart.c +++ b/drivers/bluetooth/btnxpuart.c @@ -24,7 +24,7 @@ #include #include -#include "h4_recv.h" +#include "hci_uart.h" #define MANUFACTURER_NXP 37 diff --git a/drivers/bluetooth/h4_recv.h b/drivers/bluetooth/h4_recv.h deleted file mode 100644 index 28cf2d8c2d48..000000000000 --- a/drivers/bluetooth/h4_recv.h +++ /dev/null @@ -1,153 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * - * Generic Bluetooth HCI UART driver - * - * Copyright (C) 2015-2018 Intel Corporation - */ - -#include - -struct h4_recv_pkt { - u8 type; /* Packet type */ - u8 hlen; /* Header length */ - u8 loff; /* Data length offset in header */ - u8 lsize; /* Data length field size */ - u16 maxlen; /* Max overall packet length */ - int (*recv)(struct hci_dev *hdev, struct sk_buff *skb); -}; - -#define H4_RECV_ACL \ - .type = HCI_ACLDATA_PKT, \ - .hlen = HCI_ACL_HDR_SIZE, \ - .loff = 2, \ - .lsize = 2, \ - .maxlen = HCI_MAX_FRAME_SIZE \ - -#define H4_RECV_SCO \ - .type = HCI_SCODATA_PKT, \ - .hlen = HCI_SCO_HDR_SIZE, \ - .loff = 2, \ - .lsize = 1, \ - .maxlen = HCI_MAX_SCO_SIZE - -#define H4_RECV_EVENT \ - .type = HCI_EVENT_PKT, \ - .hlen = HCI_EVENT_HDR_SIZE, \ - .loff = 1, \ - .lsize = 1, \ - .maxlen = HCI_MAX_EVENT_SIZE - -#define H4_RECV_ISO \ - .type = HCI_ISODATA_PKT, \ - .hlen = HCI_ISO_HDR_SIZE, \ - .loff = 2, \ - .lsize = 2, \ - .maxlen = HCI_MAX_FRAME_SIZE - -static inline struct sk_buff *h4_recv_buf(struct hci_dev *hdev, - struct sk_buff *skb, - const unsigned char *buffer, - int count, - const struct h4_recv_pkt *pkts, - int pkts_count) -{ - /* Check for error from previous call */ - if (IS_ERR(skb)) - skb = NULL; - - while (count) { - int i, len; - - if (!skb) { - for (i = 0; i < pkts_count; i++) { - if (buffer[0] != (&pkts[i])->type) - continue; - - skb = bt_skb_alloc((&pkts[i])->maxlen, - GFP_ATOMIC); - if (!skb) - return ERR_PTR(-ENOMEM); - - hci_skb_pkt_type(skb) = (&pkts[i])->type; - hci_skb_expect(skb) = (&pkts[i])->hlen; - break; - } - - /* Check for invalid packet type */ - if (!skb) - return ERR_PTR(-EILSEQ); - - count -= 1; - buffer += 1; - } - - len = min_t(uint, hci_skb_expect(skb) - skb->len, count); - skb_put_data(skb, buffer, len); - - count -= len; - buffer += len; - - /* Check for partial packet */ - if (skb->len < hci_skb_expect(skb)) - continue; - - for (i = 0; i < pkts_count; i++) { - if (hci_skb_pkt_type(skb) == (&pkts[i])->type) - break; - } - - if (i >= pkts_count) { - kfree_skb(skb); - return ERR_PTR(-EILSEQ); - } - - if (skb->len == (&pkts[i])->hlen) { - u16 dlen; - - switch ((&pkts[i])->lsize) { - case 0: - /* No variable data length */ - dlen = 0; - break; - case 1: - /* Single octet variable length */ - dlen = skb->data[(&pkts[i])->loff]; - hci_skb_expect(skb) += dlen; - - if (skb_tailroom(skb) < dlen) { - kfree_skb(skb); - return ERR_PTR(-EMSGSIZE); - } - break; - case 2: - /* Double octet variable length */ - dlen = get_unaligned_le16(skb->data + - (&pkts[i])->loff); - hci_skb_expect(skb) += dlen; - - if (skb_tailroom(skb) < dlen) { - kfree_skb(skb); - return ERR_PTR(-EMSGSIZE); - } - break; - default: - /* Unsupported variable length */ - kfree_skb(skb); - return ERR_PTR(-EILSEQ); - } - - if (!dlen) { - /* No more data, complete frame */ - (&pkts[i])->recv(hdev, skb); - skb = NULL; - } - } else { - /* Complete frame */ - (&pkts[i])->recv(hdev, skb); - skb = NULL; - } - } - - return skb; -} From 576952cf981b7d2b7d3227b246b4326e5548a133 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Thu, 4 Sep 2025 15:58:00 +0800 Subject: [PATCH 22/30] Bluetooth: btusb: Add new VID/PID 13d3/3627 for MT7925 Add VID 13d3 & PID 3627 for MediaTek MT7922 USB Bluetooth chip. The information in /sys/kernel/debug/usb/devices about the Bluetooth device is listed as the below. T: Bus=07 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=13d3 ProdID=3627 Rev= 1.00 S: Manufacturer=MediaTek Inc. S: Product=Wireless_Device S: SerialNumber=000000000 C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA A: FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01 I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=125us E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms I:* If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us I: If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) E: Ad=8a(I) Atr=03(Int.) MxPS= 512 Ivl=125us E: Ad=0a(O) Atr=03(Int.) MxPS= 512 Ivl=125us Signed-off-by: Chris Lu Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 505efc4872c3..b231caa84757 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -735,6 +735,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3613), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3627), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3628), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3630), .driver_info = BTUSB_MEDIATEK | From 70cd38d22d4659ca8133c7124528c90678215dda Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Thu, 4 Sep 2025 19:46:11 +0800 Subject: [PATCH 23/30] Bluetooth: btusb: Add new VID/PID 13d3/3633 for MT7922 Add VID 13d3 & PID 3633 for MediaTek MT7922 USB Bluetooth chip. The information in /sys/kernel/debug/usb/devices about the Bluetooth device is listed as the below. T: Bus=06 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=13d3 ProdID=3633 Rev= 1.00 S: Manufacturer=MediaTek Inc. S: Product=Wireless_Device S: SerialNumber=000000000 C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA A: FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01 I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=125us E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms I:* If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us I: If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) E: Ad=8a(I) Atr=03(Int.) MxPS= 512 Ivl=125us E: Ad=0a(O) Atr=03(Int.) MxPS= 512 Ivl=125us Signed-off-by: Chris Lu Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index b231caa84757..5e9ebf0c5312 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -701,6 +701,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3615), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3633), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x35f5, 0x7922), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, From ca94b2b036c22556c3a66f1b80f490882deef7a6 Mon Sep 17 00:00:00 2001 From: Ivan Pravdin Date: Sat, 30 Aug 2025 16:03:40 -0400 Subject: [PATCH 24/30] Bluetooth: bcsp: receive data only if registered Currently, bcsp_recv() can be called even when the BCSP protocol has not been registered. This leads to a NULL pointer dereference, as shown in the following stack trace: KASAN: null-ptr-deref in range [0x0000000000000108-0x000000000000010f] RIP: 0010:bcsp_recv+0x13d/0x1740 drivers/bluetooth/hci_bcsp.c:590 Call Trace: hci_uart_tty_receive+0x194/0x220 drivers/bluetooth/hci_ldisc.c:627 tiocsti+0x23c/0x2c0 drivers/tty/tty_io.c:2290 tty_ioctl+0x626/0xde0 drivers/tty/tty_io.c:2706 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:907 [inline] __se_sys_ioctl+0xfc/0x170 fs/ioctl.c:893 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xfa/0x3b0 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f To prevent this, ensure that the HCI_UART_REGISTERED flag is set before processing received data. If the protocol is not registered, return -EUNATCH. Reported-by: syzbot+4ed6852d4da4606c93da@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=4ed6852d4da4606c93da Tested-by: syzbot+4ed6852d4da4606c93da@syzkaller.appspotmail.com Signed-off-by: Ivan Pravdin Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/hci_bcsp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 664d82d1e613..591abe6d63dd 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -582,6 +582,9 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count) struct bcsp_struct *bcsp = hu->priv; const unsigned char *ptr; + if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) + return -EUNATCH; + BT_DBG("hu %p count %d rx_state %d rx_count %ld", hu, count, bcsp->rx_state, bcsp->rx_count); From ecb9a843be4d6fd710d7026e359f21015a062572 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Mon, 22 Sep 2025 13:13:13 -0400 Subject: [PATCH 25/30] Bluetooth: SCO: Fix UAF on sco_conn_free BUG: KASAN: slab-use-after-free in sco_conn_free net/bluetooth/sco.c:87 [inline] BUG: KASAN: slab-use-after-free in kref_put include/linux/kref.h:65 [inline] BUG: KASAN: slab-use-after-free in sco_conn_put+0xdd/0x410 net/bluetooth/sco.c:107 Write of size 8 at addr ffff88811cb96b50 by task kworker/u17:4/352 CPU: 1 UID: 0 PID: 352 Comm: kworker/u17:4 Not tainted 6.17.0-rc5-g717368f83676 #4 PREEMPT(voluntary) Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 Workqueue: hci13 hci_cmd_sync_work Call Trace: __dump_stack lib/dump_stack.c:94 [inline] dump_stack_lvl+0x10b/0x170 lib/dump_stack.c:120 print_address_description mm/kasan/report.c:378 [inline] print_report+0x191/0x550 mm/kasan/report.c:482 kasan_report+0xc4/0x100 mm/kasan/report.c:595 sco_conn_free net/bluetooth/sco.c:87 [inline] kref_put include/linux/kref.h:65 [inline] sco_conn_put+0xdd/0x410 net/bluetooth/sco.c:107 sco_connect_cfm+0xb4/0xae0 net/bluetooth/sco.c:1441 hci_connect_cfm include/net/bluetooth/hci_core.h:2082 [inline] hci_conn_failed+0x20a/0x2e0 net/bluetooth/hci_conn.c:1313 hci_conn_unlink+0x55f/0x810 net/bluetooth/hci_conn.c:1121 hci_conn_del+0xb6/0x1110 net/bluetooth/hci_conn.c:1147 hci_abort_conn_sync+0x8c5/0xbb0 net/bluetooth/hci_sync.c:5689 hci_cmd_sync_work+0x281/0x380 net/bluetooth/hci_sync.c:332 process_one_work kernel/workqueue.c:3236 [inline] process_scheduled_works+0x77e/0x1040 kernel/workqueue.c:3319 worker_thread+0xbee/0x1200 kernel/workqueue.c:3400 kthread+0x3c7/0x870 kernel/kthread.c:463 ret_from_fork+0x13a/0x1e0 arch/x86/kernel/process.c:148 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 Allocated by task 31370: kasan_save_stack mm/kasan/common.c:47 [inline] kasan_save_track+0x30/0x70 mm/kasan/common.c:68 poison_kmalloc_redzone mm/kasan/common.c:388 [inline] __kasan_kmalloc+0x82/0x90 mm/kasan/common.c:405 kasan_kmalloc include/linux/kasan.h:260 [inline] __do_kmalloc_node mm/slub.c:4382 [inline] __kmalloc_noprof+0x22f/0x390 mm/slub.c:4394 kmalloc_noprof include/linux/slab.h:909 [inline] sk_prot_alloc+0xae/0x220 net/core/sock.c:2239 sk_alloc+0x34/0x5a0 net/core/sock.c:2295 bt_sock_alloc+0x3c/0x330 net/bluetooth/af_bluetooth.c:151 sco_sock_alloc net/bluetooth/sco.c:562 [inline] sco_sock_create+0xc0/0x350 net/bluetooth/sco.c:593 bt_sock_create+0x161/0x3b0 net/bluetooth/af_bluetooth.c:135 __sock_create+0x3ad/0x780 net/socket.c:1589 sock_create net/socket.c:1647 [inline] __sys_socket_create net/socket.c:1684 [inline] __sys_socket+0xd5/0x330 net/socket.c:1731 __do_sys_socket net/socket.c:1745 [inline] __se_sys_socket net/socket.c:1743 [inline] __x64_sys_socket+0x7a/0x90 net/socket.c:1743 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xc7/0x240 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f Freed by task 31374: kasan_save_stack mm/kasan/common.c:47 [inline] kasan_save_track+0x30/0x70 mm/kasan/common.c:68 kasan_save_free_info+0x40/0x50 mm/kasan/generic.c:576 poison_slab_object mm/kasan/common.c:243 [inline] __kasan_slab_free+0x3d/0x50 mm/kasan/common.c:275 kasan_slab_free include/linux/kasan.h:233 [inline] slab_free_hook mm/slub.c:2428 [inline] slab_free mm/slub.c:4701 [inline] kfree+0x199/0x3b0 mm/slub.c:4900 sk_prot_free net/core/sock.c:2278 [inline] __sk_destruct+0x4aa/0x630 net/core/sock.c:2373 sco_sock_release+0x2ad/0x300 net/bluetooth/sco.c:1333 __sock_release net/socket.c:649 [inline] sock_close+0xb8/0x230 net/socket.c:1439 __fput+0x3d1/0x9e0 fs/file_table.c:468 task_work_run+0x206/0x2a0 kernel/task_work.c:227 get_signal+0x1201/0x1410 kernel/signal.c:2807 arch_do_signal_or_restart+0x34/0x740 arch/x86/kernel/signal.c:337 exit_to_user_mode_loop+0x68/0xc0 kernel/entry/common.c:40 exit_to_user_mode_prepare include/linux/irq-entry-common.h:225 [inline] syscall_exit_to_user_mode_work include/linux/entry-common.h:175 [inline] syscall_exit_to_user_mode include/linux/entry-common.h:210 [inline] do_syscall_64+0x1dd/0x240 arch/x86/entry/syscall_64.c:100 entry_SYSCALL_64_after_hwframe+0x77/0x7f Reported-by: cen zhang Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/sco.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index d382d980fd9a..ab0cf442d57b 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -498,6 +498,13 @@ static void sco_sock_kill(struct sock *sk) BT_DBG("sk %p state %d", sk, sk->sk_state); + /* Sock is dead, so set conn->sk to NULL to avoid possible UAF */ + if (sco_pi(sk)->conn) { + sco_conn_lock(sco_pi(sk)->conn); + sco_pi(sk)->conn->sk = NULL; + sco_conn_unlock(sco_pi(sk)->conn); + } + /* Kill poor orphan */ bt_sock_unlink(&sco_sk_list, sk); sock_set_flag(sk, SOCK_DEAD); From 9950f095d6c875dbe0c9ebfcf972ec88fdf26fc8 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Mon, 22 Sep 2025 16:27:51 -0400 Subject: [PATCH 26/30] Bluetooth: ISO: Fix possible UAF on iso_conn_free This attempt to fix similar issue to sco_conn_free where if the conn->sk is not set to NULL may lead to UAF on iso_conn_free. Fixes: ccf74f2390d6 ("Bluetooth: Add BTPROTO_ISO socket type") Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/iso.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index 5c68c0ea7d97..d24c7a1ace92 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -761,6 +761,13 @@ static void iso_sock_kill(struct sock *sk) BT_DBG("sk %p state %d", sk, sk->sk_state); + /* Sock is dead, so set conn->sk to NULL to avoid possible UAF */ + if (iso_pi(sk)->conn) { + iso_conn_lock(iso_pi(sk)->conn); + iso_pi(sk)->conn->sk = NULL; + iso_conn_unlock(iso_pi(sk)->conn); + } + /* Kill poor orphan */ bt_sock_unlink(&iso_sk_list, sk); sock_set_flag(sk, SOCK_DEAD); From 6ba85da5804efffe15c89b03742ea868f20b4172 Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Mon, 22 Sep 2025 21:11:21 +0300 Subject: [PATCH 27/30] Bluetooth: ISO: free rx_skb if not consumed If iso_conn is freed when RX is incomplete, free any leftover skb piece. Fixes: dc26097bdb86 ("Bluetooth: ISO: Use kref to track lifetime of iso_conn") Signed-off-by: Pauli Virtanen Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/iso.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index d24c7a1ace92..ad5c8118a6e3 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -111,6 +111,8 @@ static void iso_conn_free(struct kref *ref) /* Ensure no more work items will run since hci_conn has been dropped */ disable_delayed_work_sync(&conn->timeout_work); + kfree_skb(conn->rx_skb); + kfree(conn); } From 5bf863f4c5da055c1eb08887ae4f26d99dbc4aac Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Mon, 22 Sep 2025 21:11:22 +0300 Subject: [PATCH 28/30] Bluetooth: ISO: don't leak skb in ISO_CONT RX For ISO_CONT RX, the data from skb is copied to conn->rx_skb, but the skb is leaked. Free skb after copying its data. Fixes: ccf74f2390d6 ("Bluetooth: Add BTPROTO_ISO socket type") Signed-off-by: Pauli Virtanen Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/iso.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index ad5c8118a6e3..9b263d061e05 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -2427,7 +2427,7 @@ void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len), skb->len); conn->rx_len -= skb->len; - return; + break; case ISO_END: skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len), From 03ddb4ac251463ec5b7b069395d9ab89163dd56c Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Fri, 19 Sep 2025 12:30:05 -0400 Subject: [PATCH 29/30] Bluetooth: hci_sync: Fix using random address for BIG/PA advertisements When creating an advertisement for BIG the address shall not be non-resolvable since in case of acting as BASS/Broadcast Assistant the address must be the same as the connection in order to use the PAST method and even when PAST/BASS are not in the picture a Periodic Advertisement can still be synchronized thus the same argument as to connectable advertisements still stand. Fixes: eca0ae4aea66 ("Bluetooth: Add initial implementation of BIS connections") Signed-off-by: Luiz Augusto von Dentz Reviewed-by: Paul Menzel --- net/bluetooth/hci_sync.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 7a7d49890858..eefdb6134ca5 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -1325,7 +1325,7 @@ int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance) { struct hci_cp_le_set_ext_adv_params cp; struct hci_rp_le_set_ext_adv_params rp; - bool connectable; + bool connectable, require_privacy; u32 flags; bdaddr_t random_addr; u8 own_addr_type; @@ -1363,10 +1363,12 @@ int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance) return -EPERM; /* Set require_privacy to true only when non-connectable - * advertising is used. In that case it is fine to use a - * non-resolvable private address. + * advertising is used and it is not periodic. + * In that case it is fine to use a non-resolvable private address. */ - err = hci_get_random_address(hdev, !connectable, + require_privacy = !connectable && !(adv && adv->periodic); + + err = hci_get_random_address(hdev, require_privacy, adv_use_rpa(hdev, flags), adv, &own_addr_type, &random_addr); if (err < 0) From be812ace0378a9db86344ad637c5ed2a5d11f216 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 9 Sep 2025 14:13:35 +0200 Subject: [PATCH 30/30] Bluetooth: Avoid a couple dozen -Wflex-array-member-not-at-end warnings -Wflex-array-member-not-at-end was introduced in GCC-14, and we are getting ready to enable it, globally. Use the __struct_group() helper to fix 31 instances of the following type of warnings: 30 net/bluetooth/mgmt_config.c:16:33: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] 1 net/bluetooth/mgmt_config.c:22:33: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] Signed-off-by: Gustavo A. R. Silva Reviewed-by: Simon Horman Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/mgmt.h | 9 +++++++-- net/bluetooth/mgmt_config.c | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 3575cd16049a..74edea06985b 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -53,10 +53,15 @@ struct mgmt_hdr { } __packed; struct mgmt_tlv { - __le16 type; - __u8 length; + /* New members MUST be added within the __struct_group() macro below. */ + __struct_group(mgmt_tlv_hdr, __hdr, __packed, + __le16 type; + __u8 length; + ); __u8 value[]; } __packed; +static_assert(offsetof(struct mgmt_tlv, value) == sizeof(struct mgmt_tlv_hdr), + "struct member likely outside of __struct_group()"); struct mgmt_addr_info { bdaddr_t bdaddr; diff --git a/net/bluetooth/mgmt_config.c b/net/bluetooth/mgmt_config.c index 6ef701c27da4..c4063d200c0a 100644 --- a/net/bluetooth/mgmt_config.c +++ b/net/bluetooth/mgmt_config.c @@ -13,13 +13,13 @@ #define HDEV_PARAM_U16(_param_name_) \ struct {\ - struct mgmt_tlv entry; \ + struct mgmt_tlv_hdr entry; \ __le16 value; \ } __packed _param_name_ #define HDEV_PARAM_U8(_param_name_) \ struct {\ - struct mgmt_tlv entry; \ + struct mgmt_tlv_hdr entry; \ __u8 value; \ } __packed _param_name_