FAQ Search Today's Posts Mark Forums Read
» Video Reviews

» Linux Archive

Linux-archive is a website aiming to archive linux email lists and to make them easily accessible for linux users/developers.


» Sponsor

» Partners

» Sponsor

Go Back   Linux Archive > Ubuntu > Ubuntu Kernel Team

 
 
LinkBack Thread Tools
 
Old 07-17-2012, 03:04 AM
Ming Lei
 
Default asix: asix_rx_fixup surgery to reduce skb truesizes

BugLink:https://bugs.launchpad.net/ubuntu/+source/linux/+bug/947723

== SRU Justification ==

At least one guy reported that the patch does fix the bug, see #38
of the bug link.

== Fix ==

This patch is backported from an upstream fix(commit ia9e0aca4b37885b5599e),
but this one isn't marked as -stable.

== Impact ==

kernel log with messages below:
[68246.610332] asix 1-5:1.0: eth1: asix_rx_fixup() Bad RX Length 1416

ifconfig showed RX errors incrementing as traffic passed through the
interface, and throughput dwindled as low as 100Kb/s on a 100Mb network.


Signed-off-by: Ming Lei <ming.lei@canonical.com>
---
drivers/net/usb/asix.c | 88 +++++++++++-------------------------------------
1 files changed, 20 insertions(+), 68 deletions(-)

diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index fc147a5..1806ab5 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -306,88 +306,40 @@ asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,

static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
- u8 *head;
- u32 header;
- char *packet;
- struct sk_buff *ax_skb;
- u16 size;
+ int offset = 0;

- head = (u8 *) skb->data;
- memcpy(&header, head, sizeof(header));
- le32_to_cpus(&header);
- packet = head + sizeof(header);
+ while (offset + sizeof(u32) < skb->len) {
+ struct sk_buff *ax_skb;
+ u16 size;
+ u32 header = get_unaligned_le32(skb->data + offset);

- skb_pull(skb, 4);
-
- while (skb->len > 0) {
- if ((header & 0x07ff) != ((~header >> 16) & 0x07ff))
- netdev_err(dev->net, "asix_rx_fixup() Bad Header Length
");
+ offset += sizeof(u32);

/* get the packet length */
- size = (u16) (header & 0x000007ff);
-
- if ((skb->len) - ((size + 1) & 0xfffe) == 0) {
- u8 alignment = (unsigned long)skb->data & 0x3;
- if (alignment != 0x2) {
- /*
- * not 16bit aligned so use the room provided by
- * the 32 bit header to align the data
- *
- * note we want 16bit alignment as MAC header is
- * 14bytes thus ip header will be aligned on
- * 32bit boundary so accessing ipheader elements
- * using a cast to struct ip header wont cause
- * an unaligned accesses.
- */
- u8 realignment = (alignment + 2) & 0x3;
- memmove(skb->data - realignment,
- skb->data,
- size);
- skb->data -= realignment;
- skb_set_tail_pointer(skb, size);
- }
- return 2;
+ size = (u16) (header & 0x7ff);
+ if (size != ((~header >> 16) & 0x07ff)) {
+ netdev_err(dev->net, "asix_rx_fixup() Bad Header Length
");
+ return 0;
}

- if (size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) {
+ if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) ||
+ (size + offset > skb->len)) {
netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d
",
size);
return 0;
}
- ax_skb = skb_clone(skb, GFP_ATOMIC);
- if (ax_skb) {
- u8 alignment = (unsigned long)packet & 0x3;
- ax_skb->len = size;
-
- if (alignment != 0x2) {
- /*
- * not 16bit aligned use the room provided by
- * the 32 bit header to align the data
- */
- u8 realignment = (alignment + 2) & 0x3;
- memmove(packet - realignment, packet, size);
- packet -= realignment;
- }
- ax_skb->data = packet;
- skb_set_tail_pointer(ax_skb, size);
- usbnet_skb_return(dev, ax_skb);
- } else {
+ ax_skb = netdev_alloc_skb_ip_align(dev->net, size);
+ if (!ax_skb)
return 0;
- }
-
- skb_pull(skb, (size + 1) & 0xfffe);

- if (skb->len < sizeof(header))
- break;
+ skb_put(ax_skb, size);
+ memcpy(ax_skb->data, skb->data + offset, size);
+ usbnet_skb_return(dev, ax_skb);

- head = (u8 *) skb->data;
- memcpy(&header, head, sizeof(header));
- le32_to_cpus(&header);
- packet = head + sizeof(header);
- skb_pull(skb, 4);
+ offset += (size + 1) & 0xfffe;
}

- if (skb->len < 0) {
+ if (skb->len != offset) {
netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d
",
skb->len);
return 0;
@@ -1538,7 +1490,7 @@ 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,
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET,
.rx_fixup = asix_rx_fixup,
.tx_fixup = asix_tx_fixup,
};
--
1.7.0.4


--
kernel-team mailing list
kernel-team@lists.ubuntu.com
https://lists.ubuntu.com/mailman/listinfo/kernel-team
 

Thread Tools




All times are GMT. The time now is 12:23 PM.

VBulletin, Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO ©2007, Crawlability, Inc.
Copyright 2007 - 2008, www.linux-archive.org