* [PATCH v4 1/3] Bluetooth: btmtk: drop zero-length ISO packets from endpoint padding
2026-10-22 3:21 [PATCH v4 0/3] Bluetooth: btmtk: fix ISO data reception Chris Lu
@ 2026-10-22 3:21 ` Chris Lu
2026-10-22 3:21 ` [PATCH v4 2/3] Bluetooth: btmtk: bound the ISO payload length by the controller's MTU Chris Lu
2026-10-22 3:21 ` [PATCH v4 3/3] Bluetooth: btmtk: derive the firmware ISO setting from MTK_ISO_THRESHOLD Chris Lu
2 siblings, 0 replies; 4+ messages in thread
From: Chris Lu @ 2026-10-22 3:21 UTC (permalink / raw)
To: Marcel Holtmann, Johan Hedberg, Luiz Von Dentz
Cc: Hao Qin, Wenlong Tian, Sean Wang, Will Lee, SS Wu,
linux-bluetooth, linux-kernel, linux-mediatek, Chris Lu
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 <hao.qin@mediatek.com>
Signed-off-by: Hao Qin <hao.qin@mediatek.com>
Co-developed-by: Wenlong Tian <ot_wenlong.tian@mediatek.com>
Signed-off-by: Wenlong Tian <ot_wenlong.tian@mediatek.com>
Signed-off-by: Chris Lu <chris.lu@mediatek.com>
---
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 <linux/usb.h>
#include <linux/iopoll.h>
#include <linux/overflow.h>
+#include <linux/string.h>
#include <linux/unaligned.h>
#include <net/bluetooth/bluetooth.h>
@@ -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;
--
2.45.2
^ permalink raw reply [flat|nested] 4+ messages in thread* [PATCH v4 2/3] Bluetooth: btmtk: bound the ISO payload length by the controller's MTU
2026-10-22 3:21 [PATCH v4 0/3] Bluetooth: btmtk: fix ISO data reception Chris Lu
2026-10-22 3:21 ` [PATCH v4 1/3] Bluetooth: btmtk: drop zero-length ISO packets from endpoint padding Chris Lu
@ 2026-10-22 3:21 ` Chris Lu
2026-10-22 3:21 ` [PATCH v4 3/3] Bluetooth: btmtk: derive the firmware ISO setting from MTK_ISO_THRESHOLD Chris Lu
2 siblings, 0 replies; 4+ messages in thread
From: Chris Lu @ 2026-10-22 3:21 UTC (permalink / raw)
To: Marcel Holtmann, Johan Hedberg, Luiz Von Dentz
Cc: Hao Qin, Wenlong Tian, Sean Wang, Will Lee, SS Wu,
linux-bluetooth, linux-kernel, linux-mediatek, Chris Lu
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 <hao.qin@mediatek.com>
Signed-off-by: Hao Qin <hao.qin@mediatek.com>
Co-developed-by: Wenlong Tian <ot_wenlong.tian@mediatek.com>
Signed-off-by: Wenlong Tian <ot_wenlong.tian@mediatek.com>
Signed-off-by: Chris Lu <chris.lu@mediatek.com>
---
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;
--
2.45.2
^ permalink raw reply [flat|nested] 4+ messages in thread* [PATCH v4 3/3] Bluetooth: btmtk: derive the firmware ISO setting from MTK_ISO_THRESHOLD
2026-10-22 3:21 [PATCH v4 0/3] Bluetooth: btmtk: fix ISO data reception Chris Lu
2026-10-22 3:21 ` [PATCH v4 1/3] Bluetooth: btmtk: drop zero-length ISO packets from endpoint padding Chris Lu
2026-10-22 3:21 ` [PATCH v4 2/3] Bluetooth: btmtk: bound the ISO payload length by the controller's MTU Chris Lu
@ 2026-10-22 3:21 ` Chris Lu
2 siblings, 0 replies; 4+ messages in thread
From: Chris Lu @ 2026-10-22 3:21 UTC (permalink / raw)
To: Marcel Holtmann, Johan Hedberg, Luiz Von Dentz
Cc: Hao Qin, Wenlong Tian, Sean Wang, Will Lee, SS Wu,
linux-bluetooth, linux-kernel, linux-mediatek, Chris Lu
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 <chris.lu@mediatek.com>
---
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));
--
2.45.2
^ permalink raw reply [flat|nested] 4+ messages in thread