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  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20221024175823.145894-1-saproj@gmail.com>
Date:   Mon, 24 Oct 2022 20:58:23 +0300
From:   Sergei Antonov <saproj@...il.com>
To:     netdev@...r.kernel.org
Cc:     olteanv@...il.com, andrew@...n.ch, pabeni@...hat.com,
        kuba@...nel.org, edumazet@...gle.com, davem@...emloft.net,
        Sergei Antonov <saproj@...il.com>
Subject: [PATCH v5 net-next] net: ftmac100: support mtu > 1500

The ftmac100 controller considers packets >1518 (1500 + Ethernet + FCS)
FTL (frame too long) and drops them. That is fine with mtu 1500 or less
and it saves CPU time. When DSA is present, mtu is bigger (for VLAN
tagging) and the controller's built-in behavior is not desired then. We
can make the controller deliver FTL packets to the driver by setting
FTMAC100_MACCR_RX_FTL. Then we have to check ftmac100_rxdes_frame_length()
(packet length sans FCS) on packets marked with FTMAC100_RXDES0_FTL flag.

Check for mtu > 1500 in .ndo_open() and set FTMAC100_MACCR_RX_FTL to let
the driver FTL packets. Implement .ndo_change_mtu() and check for
mtu > 1500 to set/clear FTMAC100_MACCR_RX_FTL dynamically.

Fixes: 8d77c036b57c ("net: add Faraday FTMAC100 10/100 Ethernet driver")
Signed-off-by: Sergei Antonov <saproj@...il.com>
---
v5:
* Handle ndo_change_mtu().
* Make description and code comments correct (hopefully).

v4:
* Set FTMAC100_MACCR_RX_FTL depending on the "mtu > 1500" condition.
* DSA tagging seems unrelated to the issue - updated description and a
code comment accordingly.

v3:
* Corrected the explanation of the problem: datasheet is correct.
* Rewrote the code to use the currently set mtu to handle DSA frames.

v2:
* Typos in description fixed.

 drivers/net/ethernet/faraday/ftmac100.c | 52 +++++++++++++++++++++++--
 1 file changed, 49 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/faraday/ftmac100.c b/drivers/net/ethernet/faraday/ftmac100.c
index d95d78230828..f276d54bcd85 100644
--- a/drivers/net/ethernet/faraday/ftmac100.c
+++ b/drivers/net/ethernet/faraday/ftmac100.c
@@ -159,6 +159,7 @@ static void ftmac100_set_mac(struct ftmac100 *priv, const unsigned char *mac)
 static int ftmac100_start_hw(struct ftmac100 *priv)
 {
 	struct net_device *netdev = priv->netdev;
+	unsigned int maccr;
 
 	if (ftmac100_reset(priv))
 		return -EIO;
@@ -175,7 +176,20 @@ static int ftmac100_start_hw(struct ftmac100 *priv)
 
 	ftmac100_set_mac(priv, netdev->dev_addr);
 
-	iowrite32(MACCR_ENABLE_ALL, priv->base + FTMAC100_OFFSET_MACCR);
+	maccr = MACCR_ENABLE_ALL;
+
+	/* We have to set FTMAC100_MACCR_RX_FTL in case MTU > 1500
+	 * and do extra length check in ftmac100_rx_packet_error().
+	 * Otherwise the controller silently drops these packets.
+	 *
+	 * When the MTU of the interface is standard 1500, rely on
+	 * the controller's functionality to drop too long packets
+	 * and save some CPU time.
+	 */
+	if (netdev->mtu > 1500)
+		maccr |= FTMAC100_MACCR_RX_FTL;
+
+	iowrite32(maccr, priv->base + FTMAC100_OFFSET_MACCR);
 	return 0;
 }
 
@@ -337,9 +351,18 @@ static bool ftmac100_rx_packet_error(struct ftmac100 *priv,
 		error = true;
 	}
 
-	if (unlikely(ftmac100_rxdes_frame_too_long(rxdes))) {
+	/* If the frame-too-long flag FTMAC100_RXDES0_FTL is set, check
+	 * if ftmac100_rxdes_frame_length(rxdes) exceeds the currently
+	 * set MTU plus ETH_HLEN. FCS is not included here.
+	 * The controller would set FTMAC100_RXDES0_FTL for all incoming
+	 * frames longer than 1518 (includeing FCS) in the presence of
+	 * FTMAC100_MACCR_RX_FTL in the MAC Control Register.
+	 */
+	if (unlikely(ftmac100_rxdes_frame_too_long(rxdes) &&
+		     ftmac100_rxdes_frame_length(rxdes) > netdev->mtu + ETH_HLEN)) {
 		if (net_ratelimit())
-			netdev_info(netdev, "rx frame too long\n");
+			netdev_info(netdev, "rx frame too long (%u)\n",
+				    ftmac100_rxdes_frame_length(rxdes));
 
 		netdev->stats.rx_length_errors++;
 		error = true;
@@ -1037,6 +1060,28 @@ static int ftmac100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int c
 	return generic_mii_ioctl(&priv->mii, data, cmd, NULL);
 }
 
+static int ftmac100_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	struct ftmac100 *priv = netdev_priv(netdev);
+	unsigned int maccr;
+
+	maccr = ioread32(priv->base + FTMAC100_OFFSET_MACCR);
+	if (new_mtu <= 1500) {
+		/* Let the controller drop incoming packets greater
+		 * than 1518 (that is 1500 + 14 Ethernet + 4 FCS).
+		 */
+		maccr &= ~FTMAC100_MACCR_RX_FTL;
+	} else {
+		/* process FTL packets in the driver */
+		maccr |= FTMAC100_MACCR_RX_FTL;
+	}
+	iowrite32(maccr, priv->base + FTMAC100_OFFSET_MACCR);
+
+	netdev->mtu = new_mtu;
+	netdev_info(netdev, "changed mtu to %d\n", new_mtu);
+	return 0;
+}
+
 static const struct net_device_ops ftmac100_netdev_ops = {
 	.ndo_open		= ftmac100_open,
 	.ndo_stop		= ftmac100_stop,
@@ -1044,6 +1089,7 @@ static const struct net_device_ops ftmac100_netdev_ops = {
 	.ndo_set_mac_address	= eth_mac_addr,
 	.ndo_validate_addr	= eth_validate_addr,
 	.ndo_eth_ioctl		= ftmac100_do_ioctl,
+	.ndo_change_mtu		= ftmac100_change_mtu,
 };
 
 /******************************************************************************
-- 
2.34.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ