From patchwork Tue Jul 17 03:04:05 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ming Lei X-Patchwork-Id: 171312 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from chlorine.canonical.com (chlorine.canonical.com [91.189.94.204]) by ozlabs.org (Postfix) with ESMTP id CA3102C016B for ; Tue, 17 Jul 2012 13:04:28 +1000 (EST) Received: from localhost ([127.0.0.1] helo=chlorine.canonical.com) by chlorine.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1Sqy59-0007Dc-Cx; Tue, 17 Jul 2012 03:04:15 +0000 Received: from mail-pb0-f49.google.com ([209.85.160.49]) by chlorine.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1Sqy55-0007DV-TE for kernel-team@lists.ubuntu.com; Tue, 17 Jul 2012 03:04:12 +0000 Received: by pbbrq13 with SMTP id rq13so40131pbb.8 for ; Mon, 16 Jul 2012 20:04:10 -0700 (PDT) Received: by 10.68.194.234 with SMTP id hz10mr2122465pbc.126.1342494250844; Mon, 16 Jul 2012 20:04:10 -0700 (PDT) Received: from localhost ([183.37.196.213]) by mx.google.com with ESMTPS id ot4sm13073743pbb.65.2012.07.16.20.04.08 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 16 Jul 2012 20:04:09 -0700 (PDT) From: Ming Lei To: kernel-team@lists.ubuntu.com Subject: [SRU][Precise][PATCH] asix: asix_rx_fixup surgery to reduce skb truesizes Date: Tue, 17 Jul 2012 11:04:05 +0800 Message-Id: <1342494245-17937-1-git-send-email-ming.lei@canonical.com> X-Mailer: git-send-email 1.7.9.5 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.13 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: kernel-team-bounces@lists.ubuntu.com Errors-To: kernel-team-bounces@lists.ubuntu.com 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 --- 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\n"); + 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\n"); + 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\n", 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\n", 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, };