Re: commit 662dc80a5e86 breaks rmnet over usb
From: Laurent Vivier
Date: Wed Feb 25 2026 - 06:07:54 EST
On 2/25/26 08:48, Laurent Vivier wrote:
On 2/25/26 08:19, Daniele Palmas wrote:
Hello,
Hello Daniele,
Il giorno lun 23 feb 2026 alle ore 15:08 Laurent Vivier
<lvivier@xxxxxxxxxx> ha scritto:
On 2/23/26 13:04, Koen Vandeputte wrote:
Hi Laurent,
Hi Koen,
I'm testing the latest openwrt state and found an issue probably
caused by your usb mtu limit patch :-)
I'm talking about this one:
662dc80a5e86 ("usbnet: limit max_mtu based on device's hard_mtu")
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/? h=v6.12.74&id=662dc80a5e86b35bbf339e0b87b7cc3f07c09de1
When using wwan0 iface normally, this makes sense, but the problem is
when using QMI modems combined with the rmnet driver and aggregated
frames.
- The modem is configured to frame sizes of 16383 or 32767 using QMI
- wwan0 (using qmi_wwan) is configured to match this frame size by
setting it's MTU to the same value
- Frames of this size are sent over to qmi_wwan driver (containing
multiple data packets)
- Frames are then forwarded to the rmnet driver
- Frames get de-aggregated here and sent to the network stack for processing.
The reason here is to reduce USB transfers heavily.
As you see, it's perfectly possible here to use very large MTU sizes
as the aggregation feature by rmnet relies on this.
Also the modem can be perfectly configured to send very large aggregated frames.
After your patch, wwan0 is limited to 1500 bytes it seems, effectively
breaking aggregation.
On my tests, download speeds are reduced from >300Mbps to ~.8Mbps
I also made a build reverting this patch and all works well again.
Is there any other solution to fix this?
I guess it should be reverted otherwise :-)
It's weird to be able to set an MTU that is not supported by the hardware.
To restore performance I think the rx_usb_size should be decoupled from MTU max in qmi_wwan.
Could you try something like:
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 3a4985b582cb..6b4796fac692 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -788,6 +788,8 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
usbnet_get_ethernet_addr(dev, cdc_ether->iMACAddress);
}
+ dev->rx_urb_size = 32768;
+
So far userspace tools (e.g. also the most important one which is
ModemManager) rely on changing the rx_urb_size by changing the MTU: I
know this is ugly, but it is a behavior that has been there since a
lot of time, not sure how many tools based on this assumption could
break.
There's also the chance that there are modems which require a higher
rx_urb_size, so having this fixed could not work well.
Unfortunately usbnet serves many drivers, I agree with Koen that a
revert is the safest option.
And there is no intermediate driver (qmi_wwan or rmnet) that can define a max_mtu higher than that defined by usbnet?
Perhaps we can remove the change from usbnet and move it to the device bind function?
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index a032c1ded406..836915e4abad 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -235,6 +235,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
if (header.usb_cdc_ether_desc && info->ether->wMaxSegmentSize) {
dev->hard_mtu = le16_to_cpu(info->ether->wMaxSegmentSize);
+ if (dev->net->max_mtu > (dev->hard_mtu - dev->net->hard_header_len))
+ dev->net->max_mtu = dev->hard_mtu - dev->net->hard_header_len;
/* because of Zaurus, we may be ignoring the host
* side link address we were given.
*/
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index ed86ba87ca4e..295c3614878b 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1829,11 +1829,9 @@ usbnet_probe(struct usb_interface *udev, const struct usb_device_id *prod)
if ((dev->driver_info->flags & FLAG_NOARP) != 0)
net->flags |= IFF_NOARP;
- if (net->max_mtu > (dev->hard_mtu - net->hard_header_len))
- net->max_mtu = dev->hard_mtu - net->hard_header_len;
-
- if (net->mtu > net->max_mtu)
- net->mtu = net->max_mtu;
+ /* maybe the remote can't receive an Ethernet MTU */
+ if (net->mtu > (dev->hard_mtu - net->hard_header_len))
+ net->mtu = dev->hard_mtu - net->hard_header_len;
} else if (!info->in || !info->out)
status = usbnet_get_endpoints(dev, udev);
An other solution would be to add a FLAG_NOMAXMTU in qmi_wwan driver_info->flags to disable the setting of max_mtu in usbnet_probe() to keep the change generic and qmi_wwan the exception.
Thanks,
Laurent