netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2 v2] usbnet: fix bad header length bug
@ 2014-02-09 23:06 Emil Goode
  2014-02-09 23:06 ` [PATCH 2/2] net: asix: add missing flag to struct driver_info Emil Goode
  2014-02-10  6:40 ` [PATCH 1/2 v2] usbnet: fix bad header length bug Oliver Neukum
  0 siblings, 2 replies; 9+ messages in thread
From: Emil Goode @ 2014-02-09 23:06 UTC (permalink / raw)
  To: David S. Miller, Ming Lei, Mark Brown, Jeff Kirsher, Glen Turner
  Cc: netdev, linux-usb, linux-kernel, Emil Goode

The AX88772B occasionally send rx packets that cross urb boundaries
and the remaining partial packet is sent with no hardware header.
When the buffer with a partial packet is of less number of octets
than the value of hard_header_len the buffer is discarded by the
usbnet module. This is causing dropped packages and error messages
in dmesg.

This can be reproduced by using ping with a packet size
between 1965-1976.

The bug has been reported here:

https://bugzilla.kernel.org/show_bug.cgi?id=29082

This patch introduces a new flag that enable minidrivers to disable
the cleaning up of small partial packets with no hardware header.
It is likely that other minidrivers will want to use this flag,
currently the cx82310_eth is describing the same problem and solving
it by setting the hard_header_len to 0. This patch also makes it more
obvious to minidriver writers that the usbnet module is discarding
small skbs, which I believe has caused some confusion.

Signed-off-by: Emil Goode <emilgoode@gmail.com>
Reported-by: Igor Gnatenko <i.gnatenko.brain@gmail.com>
---
v2: This patch solves the bug by introducing a new flag instead of
    setting hard_header_len to 0. I realize that there are already
    a lot of flags but hard_header_len is used to calculate the
    mtu values in the usbnet_change_mtu, usbnet_probe functions
    and I believe it's better not to change it.

 drivers/net/usb/asix_devices.c |   10 ++++++----
 drivers/net/usb/usbnet.c       |    3 ++-
 include/linux/usb/usbnet.h     |    3 +++
 3 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c
index 9765a7d..7ced4ed 100644
--- a/drivers/net/usb/asix_devices.c
+++ b/drivers/net/usb/asix_devices.c
@@ -891,7 +891,8 @@ static const struct driver_info ax88772_info = {
 	.status = asix_status,
 	.link_reset = ax88772_link_reset,
 	.reset = ax88772_reset,
-	.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET,
+	.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
+		 FLAG_MULTI_PACKET | FLAG_PARTIAL_RX_PKT,
 	.rx_fixup = asix_rx_fixup_common,
 	.tx_fixup = asix_tx_fixup,
 };
@@ -904,7 +905,7 @@ static const struct driver_info ax88772b_info = {
 	.link_reset = ax88772_link_reset,
 	.reset = ax88772_reset,
 	.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
-	         FLAG_MULTI_PACKET,
+		 FLAG_MULTI_PACKET | FLAG_PARTIAL_RX_PKT,
 	.rx_fixup = asix_rx_fixup_common,
 	.tx_fixup = asix_tx_fixup,
 	.data = FLAG_EEPROM_MAC,
@@ -917,7 +918,8 @@ static const struct driver_info ax88178_info = {
 	.status = asix_status,
 	.link_reset = ax88178_link_reset,
 	.reset = ax88178_reset,
-	.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR,
+	.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
+		 FLAG_PARTIAL_RX_PKT,
 	.rx_fixup = asix_rx_fixup_common,
 	.tx_fixup = asix_tx_fixup,
 };
@@ -939,7 +941,7 @@ static const struct driver_info hg20f9_info = {
 	.link_reset = ax88772_link_reset,
 	.reset = ax88772_reset,
 	.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
-	         FLAG_MULTI_PACKET,
+		 FLAG_MULTI_PACKET | FLAG_PARTIAL_RX_PKT,
 	.rx_fixup = asix_rx_fixup_common,
 	.tx_fixup = asix_tx_fixup,
 	.data = FLAG_EEPROM_MAC,
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 4671da7..a1e6964 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -574,7 +574,8 @@ static void rx_complete (struct urb *urb)
 	switch (urb_status) {
 	/* success */
 	case 0:
-		if (skb->len < dev->net->hard_header_len) {
+		if (skb->len < dev->net->hard_header_len &&
+		    !(dev->driver_info->flags & FLAG_PARTIAL_RX_PKT)) {
 			state = rx_cleanup;
 			dev->net->stats.rx_errors++;
 			dev->net->stats.rx_length_errors++;
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index e303eef..818da3b 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -117,6 +117,9 @@ struct driver_info {
 #define FLAG_RX_ASSEMBLE	0x4000	/* rx packets may span >1 frames */
 #define FLAG_NOARP		0x8000	/* device can't do ARP */
 
+/* Disables cleanup of small partial rx packets with no hardware header */
+#define FLAG_PARTIAL_RX_PKT    0x10000
+
 	/* init device ... can sleep, or cause probe() failure */
 	int	(*bind)(struct usbnet *, struct usb_interface *);
 
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2014-02-11  8:18 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-02-09 23:06 [PATCH 1/2 v2] usbnet: fix bad header length bug Emil Goode
2014-02-09 23:06 ` [PATCH 2/2] net: asix: add missing flag to struct driver_info Emil Goode
2014-02-10  6:40 ` [PATCH 1/2 v2] usbnet: fix bad header length bug Oliver Neukum
     [not found]   ` <1392014458.21271.6.camel-B2T3B9s34ElbnMAlSieJcQ@public.gmane.org>
2014-02-10 12:00     ` Emil Goode
2014-02-10 12:22       ` Oliver Neukum
     [not found]         ` <1392034947.2082.30.camel-B2T3B9s34ElbnMAlSieJcQ@public.gmane.org>
2014-02-10 12:39           ` David Laight
2014-02-10 13:05         ` Bjørn Mork
2014-02-10 15:54           ` Emil Goode
2014-02-11  7:43             ` Oliver Neukum

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).