* [PATCH v2 1/3] Bluetooth: btmtk: drop zero-length ISO packets from endpoint padding
2026-10-15 8:14 [PATCH v2 0/3] Bluetooth: btmtk: fix ISO data reception Chris Lu
@ 2026-10-15 8:14 ` Chris Lu
2026-10-15 8:14 ` [PATCH v2 2/3] Bluetooth: btmtk: bound the ISO payload length by the controller's MTU Chris Lu
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Chris Lu @ 2026-10-15 8:14 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. The padding runs to the end of the transfer, so
stop parsing once one is seen.
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 | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index bdc85147b97f..869eb2176379 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -1201,6 +1201,19 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count)
/* Complete ISO header */
hci_skb_expect(skb) = __le16_to_cpu(dlen);
+ /* The interrupt endpoint zero-fills the remainder of
+ * each transfer, and that padding parses as a header
+ * with a zero Data_Total_Length. Such a packet carries
+ * no ISO Data Load at all and is never emitted by the
+ * controller, so stop parsing here rather than hand a
+ * bogus handle 0 packet to the stack.
+ */
+ if (!hci_skb_expect(skb)) {
+ kfree_skb(skb);
+ skb = NULL;
+ break;
+ }
+
if (skb_tailroom(skb) < hci_skb_expect(skb)) {
kfree_skb(skb);
skb = NULL;
--
2.45.2
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v2 2/3] Bluetooth: btmtk: bound the ISO payload length by the controller's MTU
2026-10-15 8:14 [PATCH v2 0/3] Bluetooth: btmtk: fix ISO data reception Chris Lu
2026-10-15 8:14 ` [PATCH v2 1/3] Bluetooth: btmtk: drop zero-length ISO packets from endpoint padding Chris Lu
@ 2026-10-15 8:14 ` Chris Lu
2026-10-15 8:14 ` [PATCH v2 3/3] Bluetooth: btmtk: derive the firmware ISO setting from MTK_ISO_THRESHOLD Chris Lu
2026-10-15 13:47 ` [PATCH v2 0/3] Bluetooth: btmtk: fix ISO data reception Luiz Augusto von Dentz
3 siblings, 0 replies; 6+ messages in thread
From: Chris Lu @ 2026-10-15 8:14 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 869eb2176379..7c3fffcefdf1 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -1169,8 +1169,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;
@@ -1178,7 +1185,8 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count)
int len;
if (!skb) {
- 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;
@@ -1214,7 +1222,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] 6+ messages in thread* [PATCH v2 3/3] Bluetooth: btmtk: derive the firmware ISO setting from MTK_ISO_THRESHOLD
2026-10-15 8:14 [PATCH v2 0/3] Bluetooth: btmtk: fix ISO data reception Chris Lu
2026-10-15 8:14 ` [PATCH v2 1/3] Bluetooth: btmtk: drop zero-length ISO packets from endpoint padding Chris Lu
2026-10-15 8:14 ` [PATCH v2 2/3] Bluetooth: btmtk: bound the ISO payload length by the controller's MTU Chris Lu
@ 2026-10-15 8:14 ` Chris Lu
2026-10-15 13:47 ` [PATCH v2 0/3] Bluetooth: btmtk: fix ISO data reception Luiz Augusto von Dentz
3 siblings, 0 replies; 6+ messages in thread
From: Chris Lu @ 2026-10-15 8:14 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 7c3fffcefdf1..9424125ce539 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -24,7 +24,7 @@
#define MTK_SEC_MAP_NEED_SEND_SIZE 52
/* 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];
@@ -1347,7 +1347,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;
@@ -1362,7 +1362,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] 6+ messages in thread* Re: [PATCH v2 0/3] Bluetooth: btmtk: fix ISO data reception
2026-10-15 8:14 [PATCH v2 0/3] Bluetooth: btmtk: fix ISO data reception Chris Lu
` (2 preceding siblings ...)
2026-10-15 8:14 ` [PATCH v2 3/3] Bluetooth: btmtk: derive the firmware ISO setting from MTK_ISO_THRESHOLD Chris Lu
@ 2026-10-15 13:47 ` Luiz Augusto von Dentz
2026-10-16 8:51 ` Chris Lu (陸稚泓)
3 siblings, 1 reply; 6+ messages in thread
From: Luiz Augusto von Dentz @ 2026-10-15 13:47 UTC (permalink / raw)
To: Chris Lu
Cc: Marcel Holtmann, Johan Hedberg, Hao Qin, Wenlong Tian, Sean Wang,
Will Lee, SS Wu, linux-bluetooth, linux-kernel, linux-mediatek
Hi Chris,
On Thu, Oct 15, 2026 at 4:15 AM Chris Lu <chris.lu@mediatek.com> wrote:
>
> Three fixes for ISO data handling in btmtk, found while debugging LE Audio
> on MT7925. The code is shared by every MediaTek USB controller that
> supports ISO data, so none of this is specific to that part.
>
> Patch 1 drops the zero padding that the ISO interrupt IN endpoint appends
> to each transfer instead of parsing it as ISO packets. The driver turns
> that padding into handle 0 packets with a Data_Total_Length of zero and
> hands them to the stack, which is what fills the HCI log with malformed
> ISO frames, and a valid SDU is lost whenever handle 0 belongs to a live
> CIS/BIS.
>
> Patch 2 bounds Data_Total_Length by hdev->iso_mtu. The existing
> skb_tailroom() test enforces no protocol limit, because the skb head
> allocation is rounded up to a kmalloc bucket and skb_tailroom() reports
> the bucket size rather than what was requested.
>
> Patch 3 updates the mt79xx ISO data transmission setting.
>
> The three hunks do not overlap, so any prefix of the series applies on its
> own.
>
> Changes in v2:
> - Patch 2 reworked and retitled. v1 only enlarged the receive skb, which
> turned out to be a no-op, and added no bound at all. v2 bounds
> Data_Total_Length by hdev->iso_mtu and sizes the skb from the same
> value.
> - Patch 3 added.
> - Patch 1 unchanged.
>
> Based on bluetooth-next.
>
> Chris Lu (3):
> Bluetooth: btmtk: drop zero-length ISO packets from endpoint padding
> Bluetooth: btmtk: bound the ISO payload length by the controller's MTU
> Bluetooth: btmtk: derive the firmware ISO setting from
> MTK_ISO_THRESHOLD
>
> drivers/bluetooth/btmtk.c | 37 ++++++++++++++++++++++++++++++++-----
> 1 file changed, 32 insertions(+), 5 deletions(-)
>
> --
> 2.45.2
>
In case you haven't seen it sashiko flagged a problem with this set:
https://sashiko.dev/#/patchset/20261015081450.1241194-1-chris.lu%40mediatek.com
Unsuccessful packets shall still be delivered to the host, this is
used, for example, to implement Packet Loss Concealment (PLC) logic.
--
Luiz Augusto von Dentz
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH v2 0/3] Bluetooth: btmtk: fix ISO data reception
2026-10-15 13:47 ` [PATCH v2 0/3] Bluetooth: btmtk: fix ISO data reception Luiz Augusto von Dentz
@ 2026-10-16 8:51 ` Chris Lu (陸稚泓)
0 siblings, 0 replies; 6+ messages in thread
From: Chris Lu (陸稚泓) @ 2026-10-16 8:51 UTC (permalink / raw)
To: luiz.dentz
Cc: Hao Qin (秦浩),
Will-CY Lee (李政穎),
Wenlong Tian (田文龙),
marcel, SS Wu (巫憲欣),
linux-kernel, johan.hedberg, Sean Wang, linux-bluetooth,
linux-mediatek
Hi Luiz,
Thanks for reminder and review, I've seen Sashiko's feedback and just
about to discuss with you.
On Thu, 2026-10-15 at 09:47 -0400, Luiz Augusto von Dentz wrote:
> Hi Chris,
>
> On Thu, Oct 15, 2026 at 4:15 AM Chris Lu <chris.lu@mediatek.com>
> wrote:
> >
> > Three fixes for ISO data handling in btmtk, found while debugging
> > LE Audio
> > on MT7925. The code is shared by every MediaTek USB controller that
> > supports ISO data, so none of this is specific to that part.
> >
> > Patch 1 drops the zero padding that the ISO interrupt IN endpoint
> > appends
> > to each transfer instead of parsing it as ISO packets. The driver
> > turns
> > that padding into handle 0 packets with a Data_Total_Length of zero
> > and
> > hands them to the stack, which is what fills the HCI log with
> > malformed
> > ISO frames, and a valid SDU is lost whenever handle 0 belongs to a
> > live
> > CIS/BIS.
> >
> > Patch 2 bounds Data_Total_Length by hdev->iso_mtu. The existing
> > skb_tailroom() test enforces no protocol limit, because the skb
> > head
> > allocation is rounded up to a kmalloc bucket and skb_tailroom()
> > reports
> > the bucket size rather than what was requested.
> >
> > Patch 3 updates the mt79xx ISO data transmission setting.
> >
> > The three hunks do not overlap, so any prefix of the series applies
> > on its
> > own.
> >
> > Changes in v2:
> > - Patch 2 reworked and retitled. v1 only enlarged the receive skb,
> > which
> > turned out to be a no-op, and added no bound at all. v2 bounds
> > Data_Total_Length by hdev->iso_mtu and sizes the skb from the
> > same
> > value.
> > - Patch 3 added.
> > - Patch 1 unchanged.
> >
> > Based on bluetooth-next.
> >
> > Chris Lu (3):
> > Bluetooth: btmtk: drop zero-length ISO packets from endpoint
> > padding
> > Bluetooth: btmtk: bound the ISO payload length by the
> > controller's MTU
> > Bluetooth: btmtk: derive the firmware ISO setting from
> > MTK_ISO_THRESHOLD
> >
> > drivers/bluetooth/btmtk.c | 37 ++++++++++++++++++++++++++++++++---
> > --
> > 1 file changed, 32 insertions(+), 5 deletions(-)
> >
> > --
> > 2.45.2
> >
>
> In case you haven't seen it sashiko flagged a problem with this set:
>
> https://urldefense.com/v3/__https://sashiko.dev/*/patchset/20261015081450.1241194-1-chris.lu*40mediatek.com__;IyU!!CTRNKA9wMg0ARbw!mYdsqeN7_YBH4bm3y5AVx7pNg8Vf3PCejWejyil945dveZUs2iYohrBujiU-AlOerUeQuTMdUpu6UKOXKRY$
>
>
> Unsuccessful packets shall still be delivered to the host, this is
> used, for example, to implement Packet Loss Concealment (PLC) logic.
>
Agreed, and that is why the condition here is Data_Total_Length == 0
rather than ISO_SDU_Length == 0:
-unsuccessful SDU : Data_Total_Length = 4 (8 with TS), ISO_SDU_Length =
0
-endpoint padding : Data_Total_Length = 0, no ISO_Data_Load at all
An unsuccessful packet carries its Packet_Status_Flag inside the
ISO_Data_Load, alongside the Packet_Sequence_Number and ISO_SDU_Length,
so it still has a Data_Total_Length of 4 even when the SDU itself is
empty. That is what reaches the socket today: iso_recv() pulls
HCI_ISO_DATA_HDR_SIZE, then derives ISO_SDU_Length via
hci_iso_data_len() and the Packet_Status_Flag via hci_iso_data_flags()
from that same slen field, sees len == skb->len == 0, and delivers a
zero-length skb with hci_skb_pkt_status() set, which af_bluetooth.c
passes up as BT_SCM_PKT_STATUS. This patch does not touch any
of that, so PLC keeps getting its indications.
What this patch drops is the second line: a packet with no
ISO_Data_Load at all. It cannot carry a Packet_Status_Flag, since the
four octets holding it are simply not there, so it cannot express an
unsuccessful packet in the first place.
The reason this is handled in the driver is how MediaTek controllers
transport ISO data: the ISO interrupt IN endpoint delivers a fixed-size
transfer per completion and zero-fills whatever is left after the ISO
packet it carries. That padding belongs to the transfer rather than to
the stream, and since it is always trailing, parsing can stop at the
first zero-length header instead of skipping it and looking for more
packets behind it.
On the AI review's other suggestion, gating this on a non-zero
connection handle: handle 0 is a valid connection handle, so that would
treat a stream on handle 0 differently from the same stream on any
other handle, which is the behaviour this patch removes.
I can make the comment say explicitly that unsuccessful packets are
preserved, if that helps the next reader.
My preference is to keep the series as proposed, since
Data_Total_Length == 0 already identifies the padding without
ambiguity. If you'd still rather not rely on that check alone, there is
another way to confirm this is padding rather than infer it from the
header, and I'm glad to send a v3 with that instead if you'd prefer.
Thanks,
Chris Lu
^ permalink raw reply [flat|nested] 6+ messages in thread