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 <[email protected]>
Reported-by: Igor Gnatenko <[email protected]>
---
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
The struct driver_info ax88178_info is assigned the function
asix_rx_fixup_common as it's rx_fixup callback. This means that
FLAG_MULTI_PACKET must be set as this function is cloning the
data and calling usbnet_skb_return. Not setting this flag leads
to usbnet_skb_return beeing called a second time from within
the rx_process function in the usbnet module.
Signed-off-by: Emil Goode <[email protected]>
Reported-by: Bjørn Mork <[email protected]>
---
drivers/net/usb/asix_devices.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c
index 7ced4ed..19d8821 100644
--- a/drivers/net/usb/asix_devices.c
+++ b/drivers/net/usb/asix_devices.c
@@ -919,7 +919,7 @@ static const struct driver_info ax88178_info = {
.link_reset = ax88178_link_reset,
.reset = ax88178_reset,
.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
- FLAG_PARTIAL_RX_PKT,
+ FLAG_MULTI_PACKET | FLAG_PARTIAL_RX_PKT,
.rx_fixup = asix_rx_fixup_common,
.tx_fixup = asix_tx_fixup,
};
--
1.7.10.4
On Mon, 2014-02-10 at 00:06 +0100, Emil Goode wrote:
> 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.
Well, then how about simply removing the check?
It seems to have outlived its usefulness.
Regards
Oliver
On Mon, Feb 10, 2014 at 07:40:58AM +0100, Oliver Neukum wrote:
> On Mon, 2014-02-10 at 00:06 +0100, Emil Goode wrote:
> > 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.
>
> Well, then how about simply removing the check?
> It seems to have outlived its usefulness.
>
> Regards
> Oliver
>
>
I did consider that and I think it is probably the best thing to do.
However, I think the removal of the check could have negative effects
on the other minidrivers, at least the qmi_wwan minidriver explicitly
states that it is depending on this check to be made in rx_complete().
For safety the check could be added at the top of the rx_fixup callback
of the affected minidrivers.
There are devices that depend on the usbnet module that do not have
a rx_fixup callback assigned to it's driver_info struct, the check
could be added for these in the rx_process function.
This led me to think it would be a lot of noise about a small check :)
My conclusion is that 12 rx_fixup callbacks might need the check
to be added. There are 18 driver_info structs with no rx_fixup
callback assigned, these devices might need the check to be added
to the rx_process function.
Patches could be sent out to notify the affected minidrivers of the
change and hopefully someone has the hardware to test if it's
necessary to add the check to the minidriver?
I'm happy to do this if it seem like a good idea.
Best regards,
Emil Goode
On Mon, 2014-02-10 at 13:00 +0100, Emil Goode wrote:
> On Mon, Feb 10, 2014 at 07:40:58AM +0100, Oliver Neukum wrote:
> > On Mon, 2014-02-10 at 00:06 +0100, Emil Goode wrote:
> > > 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.
> >
> > Well, then how about simply removing the check?
> > It seems to have outlived its usefulness.
> >
> > Regards
> > Oliver
> >
> >
>
> I did consider that and I think it is probably the best thing to do.
> However, I think the removal of the check could have negative effects
> on the other minidrivers, at least the qmi_wwan minidriver explicitly
> states that it is depending on this check to be made in rx_complete().
<censored>. Oh well. But how about merging it with FLAG_MULTI_PACKET?
I really don't want to add more flags. There is a point where enough
flags make absurd having a common code. We are closing in on that point.
Regards
Oliver
From: Oliver Neukum
> <censored>. Oh well. But how about merging it with FLAG_MULTI_PACKET?
> I really don't want to add more flags. There is a point where enough
> flags make absurd having a common code. We are closing in on that point.
Any sub-driver that supports multi-packet either has to use stupidly
long URB and/or set the rx_urb_size to a multiple of the usb transfer
size.
It will also have to detect illegal short headers.
Actually it might be worth double-checking the encapsulations used.
IIRC the ax88179_178a uses different headers for tx and rx.
So there might be some that support multi-packet but still have
a short(ish) limit on the bulk receive size (before the short fragment).
I'm sat at the wrong desk to look at the code...
David
????{.n?+???????+%?????ݶ??w??{.n?+????{??G?????{ay?ʇڙ?,j??f???h?????????z_??(?階?ݢj"???m??????G????????????&???~???iO???z??v?^?m????????????I?
Oliver Neukum <[email protected]> writes:
> On Mon, 2014-02-10 at 13:00 +0100, Emil Goode wrote:
>> On Mon, Feb 10, 2014 at 07:40:58AM +0100, Oliver Neukum wrote:
>
>> > Well, then how about simply removing the check?
>> > It seems to have outlived its usefulness.
>> >
>> > Regards
>> > Oliver
>> >
>> >
>>
>> I did consider that and I think it is probably the best thing to do.
>> However, I think the removal of the check could have negative effects
>> on the other minidrivers, at least the qmi_wwan minidriver explicitly
>> states that it is depending on this check to be made in rx_complete().
>
> <censored>.
No need to do that. I had the exact same reaction myself :-)
Anyway, I put that comment there mostly as a note to myself why the
check would be redundant at that point. I don't see any problem with
removing the generic check in usbnet as long as we add similar checks
whereever they are needed, like in qmi_wwan.
Note that usbnet_skb_return will be one of those places. It calls
eth_type_trans() on the skb, so it should verify that the length is at
least ETH_HLEN first.
> Oh well. But how about merging it with FLAG_MULTI_PACKET?
> I really don't want to add more flags. There is a point where enough
> flags make absurd having a common code. We are closing in on that point.
Agreed. I would even say we are past that point...
Bjørn
On Mon, Feb 10, 2014 at 02:05:20PM +0100, Bjørn Mork wrote:
> Oliver Neukum <[email protected]> writes:
> > On Mon, 2014-02-10 at 13:00 +0100, Emil Goode wrote:
> >> On Mon, Feb 10, 2014 at 07:40:58AM +0100, Oliver Neukum wrote:
> >
> >> > Well, then how about simply removing the check?
> >> > It seems to have outlived its usefulness.
> >> >
> >> > Regards
> >> > Oliver
> >> >
> >> >
> >>
> >> I did consider that and I think it is probably the best thing to do.
> >> However, I think the removal of the check could have negative effects
> >> on the other minidrivers, at least the qmi_wwan minidriver explicitly
> >> states that it is depending on this check to be made in rx_complete().
> >
> > <censored>.
>
> No need to do that. I had the exact same reaction myself :-)
>
> Anyway, I put that comment there mostly as a note to myself why the
> check would be redundant at that point. I don't see any problem with
> removing the generic check in usbnet as long as we add similar checks
> whereever they are needed, like in qmi_wwan.
I think it could be worth the trouble of removing the generic check in
the usbnet module.
I believe that if you define your own rx_fixup callback then the
usbnet module should not make it's own assumptions on what packets
to discard.
Since the checks that need to be added in various places are all in
the same subsystem I think it could be done in as little as one patch?
> Note that usbnet_skb_return will be one of those places. It calls
> eth_type_trans() on the skb, so it should verify that the length is at
> least ETH_HLEN first.
>
> > Oh well. But how about merging it with FLAG_MULTI_PACKET?
> > I really don't want to add more flags. There is a point where enough
> > flags make absurd having a common code. We are closing in on that point.
>
> Agreed. I would even say we are past that point...
If nobody have any objections I will try removing the generic check and
introduce checks where nessecary.
Best regards,
Emil Goode
On Mon, 2014-02-10 at 16:54 +0100, Emil Goode wrote:
> Since the checks that need to be added in various places are all in
> the same subsystem I think it could be done in as little as one patch?
Yes, please definitely. Best for bisectability.
> If nobody have any objections I will try removing the generic check and
> introduce checks where nessecary.
Thank you
Regards
Oliver