lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:   Tue, 10 Mar 2020 19:01:43 +0100
From:   Daniele Palmas <dnlplm@...il.com>
To:     Bjørn Mork <bjorn@...k.no>
Cc:     paul.gildea@...il.com, netdev@...r.kernel.org,
        Daniele Palmas <dnlplm@...il.com>
Subject: [RFC PATCH 1/1] net: usb: qmi_wwan: add mtu change functions

The patch introduces mtu change functions both for master and qmimux
network interfaces in order to properly deal with downlink aggregated
packets feature set from user-space.

rmnet can be configured for downling aggregated packets, requiring
the rx_urb_size to be as much as the value set from user-space with
the proper QMI request (see libqmi wda_set_data_format), so a default
value for rx_urb_size is set when the first qmimux netdevice is created.

Since some modems could require a different (usually higher) value,
an mtu change function for the master netdevice has been added, in
order to link the mtu change with rx_urb_size when qmimux is enabled.
This affects also rx_qlen, but not tx_qlen.

The possibility of modifying the tx_qlen is left to the qmimux mtu
change function.

Signed-off-by: Daniele Palmas <dnlplm@...il.com>
---
Hi Bjørn and Paul,

this is an attempt to fix the dl aggregated rx_urb_size related issue
and provide an hook for solving also Paul's issue, that can be done with
a follow-up patch: it currently does not change the behavior when qmap
is not enabled, calling usbnet_change_mtu. Let me know if it is
something that could make sense.

Thanks,
Daniele
---
 drivers/net/usb/qmi_wwan.c | 72 +++++++++++++++++++++++++++++++++++---
 1 file changed, 68 insertions(+), 4 deletions(-)

diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 5754bb6ca0ee..88bb55736413 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -153,11 +153,30 @@ static void qmimux_get_stats64(struct net_device *net,
 	}
 }
 
+static int qmimux_change_mtu(struct net_device *net, int new_mtu)
+{
+	struct qmimux_priv *priv = netdev_priv(net);
+	struct net_device *real_dev = priv->real_dev;
+	struct usbnet *dev = netdev_priv(real_dev);
+
+	net->mtu = new_mtu;
+	if (dev->hard_mtu < new_mtu + sizeof(struct qmimux_hdr)) {
+		/* rx_urb_size is not in sync with hard_mtu and should
+		 * be changed through qmi_wwan_change_mtu
+		 */
+		dev->hard_mtu = new_mtu + sizeof(struct qmimux_hdr);
+		usbnet_update_max_qlen(dev);
+	}
+
+	return 0;
+}
+
 static const struct net_device_ops qmimux_netdev_ops = {
 	.ndo_open        = qmimux_open,
 	.ndo_stop        = qmimux_stop,
 	.ndo_start_xmit  = qmimux_start_xmit,
 	.ndo_get_stats64 = qmimux_get_stats64,
+	.ndo_change_mtu  = qmimux_change_mtu,
 };
 
 static void qmimux_setup(struct net_device *dev)
@@ -322,6 +341,33 @@ static void qmimux_unregister_device(struct net_device *dev,
 	dev_put(real_dev);
 }
 
+static int qmi_wwan_change_mtu(struct net_device *net, int new_mtu)
+{
+	struct usbnet	*dev = netdev_priv(net);
+	struct qmi_wwan_state *info = (void *)&dev->data;
+
+	if (info->flags & QMI_WWAN_FLAG_MUX) {
+		int old_rx_urb_size = dev->rx_urb_size;
+
+		net->mtu = new_mtu;
+		dev->rx_urb_size = net->mtu;
+
+		if (dev->rx_urb_size > old_rx_urb_size) {
+			usbnet_pause_rx(dev);
+			usbnet_unlink_rx_urbs(dev);
+			usbnet_resume_rx(dev);
+		}
+		/* max qlen depend on hard_mtu and rx_urb_size: hard_mtu is used
+		 * for tx_qlen and is set by qmimux_change_mtu
+		 */
+		usbnet_update_max_qlen(dev);
+
+		return 0;
+	} else {
+		return usbnet_change_mtu(net, new_mtu);
+	}
+}
+
 static void qmi_wwan_netdev_setup(struct net_device *net)
 {
 	struct usbnet *dev = netdev_priv(net);
@@ -345,7 +391,7 @@ static void qmi_wwan_netdev_setup(struct net_device *net)
 	}
 
 	/* recalculate buffers after changing hard_header_len */
-	usbnet_change_mtu(net, net->mtu);
+	qmi_wwan_change_mtu(net, net->mtu);
 }
 
 static ssize_t raw_ip_show(struct device *d, struct device_attribute *attr, char *buf)
@@ -450,7 +496,19 @@ static ssize_t add_mux_store(struct device *d,  struct device_attribute *attr, c
 
 	ret = qmimux_register_device(dev->net, mux_id);
 	if (!ret) {
-		info->flags |= QMI_WWAN_FLAG_MUX;
+		if (!(info->flags & QMI_WWAN_FLAG_MUX)) {
+			info->flags |= QMI_WWAN_FLAG_MUX;
+			/* Setting a default rx_urb_size for dealing with qmap
+			 * downlink data aggregation: this should be good for
+			 * most of the modems, but some could require a larger
+			 * value to be set changing the MTU of the master
+			 * interface
+			 */
+			dev->rx_urb_size = 16384;
+			dev->hard_mtu =
+				ETH_DATA_LEN + sizeof(struct qmimux_hdr);
+			usbnet_update_max_qlen(dev);
+		}
 		ret = len;
 	}
 err:
@@ -492,8 +550,14 @@ static ssize_t del_mux_store(struct device *d,  struct device_attribute *attr, c
 	}
 	qmimux_unregister_device(del_dev, NULL);
 
-	if (!qmimux_has_slaves(dev))
+	if (!qmimux_has_slaves(dev)) {
 		info->flags &= ~QMI_WWAN_FLAG_MUX;
+		/* Restore mtu to eth default */
+		dev->net->mtu = ETH_DATA_LEN;
+		dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
+		dev->rx_urb_size = dev->hard_mtu;
+		qmi_wwan_netdev_setup(dev->net);
+	}
 	ret = len;
 err:
 	rtnl_unlock();
@@ -619,7 +683,7 @@ static const struct net_device_ops qmi_wwan_netdev_ops = {
 	.ndo_stop		= usbnet_stop,
 	.ndo_start_xmit		= usbnet_start_xmit,
 	.ndo_tx_timeout		= usbnet_tx_timeout,
-	.ndo_change_mtu		= usbnet_change_mtu,
+	.ndo_change_mtu		= qmi_wwan_change_mtu,
 	.ndo_get_stats64	= usbnet_get_stats64,
 	.ndo_set_mac_address	= qmi_wwan_mac_addr,
 	.ndo_validate_addr	= eth_validate_addr,
-- 
2.17.1

Powered by blists - more mailing lists