From: Greg Kroah-Hartman Date: Sat, 8 Mar 2014 01:05:39 +0000 (-0800) Subject: 3.4-stable patches X-Git-Tag: v3.4.83~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=911efd6e6a88bb3469ea59cc2d1a0afb1a26d9c5;p=thirdparty%2Fkernel%2Fstable-queue.git 3.4-stable patches added patches: net-asix-add-missing-flag-to-struct-driver_info.patch net-asix-handle-packets-crossing-urb-boundaries.patch --- diff --git a/queue-3.4/net-asix-add-missing-flag-to-struct-driver_info.patch b/queue-3.4/net-asix-add-missing-flag-to-struct-driver_info.patch new file mode 100644 index 00000000000..80fc9a0b929 --- /dev/null +++ b/queue-3.4/net-asix-add-missing-flag-to-struct-driver_info.patch @@ -0,0 +1,40 @@ +From d43ff4cd798911736fb39025ec8004284b1b0bc2 Mon Sep 17 00:00:00 2001 +From: Emil Goode +Date: Thu, 13 Feb 2014 19:30:39 +0100 +Subject: net: asix: add missing flag to struct driver_info +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Emil Goode + +commit d43ff4cd798911736fb39025ec8004284b1b0bc2 upstream. + +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 +Reported-by: Bjørn Mork +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/usb/asix.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/usb/asix.c ++++ b/drivers/net/usb/asix.c +@@ -1574,7 +1574,8 @@ static const struct driver_info ax88178_ + .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_MULTI_PACKET, + .rx_fixup = asix_rx_fixup_common, + .tx_fixup = asix_tx_fixup, + }; diff --git a/queue-3.4/net-asix-handle-packets-crossing-urb-boundaries.patch b/queue-3.4/net-asix-handle-packets-crossing-urb-boundaries.patch new file mode 100644 index 00000000000..d1474e72f11 --- /dev/null +++ b/queue-3.4/net-asix-handle-packets-crossing-urb-boundaries.patch @@ -0,0 +1,221 @@ +From emilgoode@gmail.com Fri Mar 7 17:03:47 2014 +From: Lucas Stach +Date: Thu, 27 Feb 2014 12:51:38 +0100 +Subject: net: asix: handle packets crossing URB boundaries +To: gregkh@linuxfoundation.org +Cc: i.gnatenko.brain@gmail.com, stable@vger.kernel.org, stable-commits@vger.kernel.org, Emil Goode , Lucas Stach , "David S. Miller" +Message-ID: <1393501899-17169-2-git-send-email-emilgoode@gmail.com> + +From: Lucas Stach + +commit 8b5b6f5413e97c3e8bafcdd67553d508f4f698cd upstream. + +ASIX AX88772B started to pack data even more tightly. Packets and the ASIX packet +header may now cross URB boundaries. To handle this we have to introduce +some state between individual calls to asix_rx_fixup(). + +Signed-off-by: Lucas Stach +Signed-off-by: David S. Miller +[ Emil: backported to 3.4: dropped changes to drivers/net/usb/ax88172a.c ] +Signed-off-by: Emil Goode +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/usb/asix.c | 125 ++++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 97 insertions(+), 28 deletions(-) + +--- a/drivers/net/usb/asix.c ++++ b/drivers/net/usb/asix.c +@@ -183,6 +183,17 @@ struct ax88172_int_data { + __le16 res3; + } __packed; + ++struct asix_rx_fixup_info { ++ struct sk_buff *ax_skb; ++ u32 header; ++ u16 size; ++ bool split_head; ++}; ++ ++struct asix_common_private { ++ struct asix_rx_fixup_info rx_fixup_info; ++}; ++ + static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data) + { +@@ -304,49 +315,89 @@ asix_write_cmd_async(struct usbnet *dev, + } + } + +-static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) ++static int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb, ++ struct asix_rx_fixup_info *rx) + { + int offset = 0; + +- while (offset + sizeof(u32) < skb->len) { +- struct sk_buff *ax_skb; +- u16 size; +- u32 header = get_unaligned_le32(skb->data + offset); +- +- offset += sizeof(u32); +- +- /* get the packet length */ +- size = (u16) (header & 0x7ff); +- if (size != ((~header >> 16) & 0x07ff)) { +- netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n"); +- return 0; ++ while (offset + sizeof(u16) <= skb->len) { ++ u16 remaining = 0; ++ unsigned char *data; ++ ++ if (!rx->size) { ++ if ((skb->len - offset == sizeof(u16)) || ++ rx->split_head) { ++ if (!rx->split_head) { ++ rx->header = get_unaligned_le16( ++ skb->data + offset); ++ rx->split_head = true; ++ offset += sizeof(u16); ++ break; ++ } else { ++ rx->header |= (get_unaligned_le16( ++ skb->data + offset) ++ << 16); ++ rx->split_head = false; ++ offset += sizeof(u16); ++ } ++ } else { ++ rx->header = get_unaligned_le32(skb->data + ++ offset); ++ offset += sizeof(u32); ++ } ++ ++ /* get the packet length */ ++ rx->size = (u16) (rx->header & 0x7ff); ++ if (rx->size != ((~rx->header >> 16) & 0x7ff)) { ++ netdev_err(dev->net, "asix_rx_fixup() Bad Header Length 0x%x, offset %d\n", ++ rx->header, offset); ++ rx->size = 0; ++ return 0; ++ } ++ rx->ax_skb = netdev_alloc_skb_ip_align(dev->net, ++ rx->size); ++ if (!rx->ax_skb) ++ return 0; + } + +- if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) || +- (size + offset > skb->len)) { ++ if (rx->size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) { + netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n", +- size); ++ rx->size); ++ kfree_skb(rx->ax_skb); + return 0; + } +- ax_skb = netdev_alloc_skb_ip_align(dev->net, size); +- if (!ax_skb) +- return 0; + +- skb_put(ax_skb, size); +- memcpy(ax_skb->data, skb->data + offset, size); +- usbnet_skb_return(dev, ax_skb); ++ if (rx->size > skb->len - offset) { ++ remaining = rx->size - (skb->len - offset); ++ rx->size = skb->len - offset; ++ } ++ ++ data = skb_put(rx->ax_skb, rx->size); ++ memcpy(data, skb->data + offset, rx->size); ++ if (!remaining) ++ usbnet_skb_return(dev, rx->ax_skb); + +- offset += (size + 1) & 0xfffe; ++ offset += (rx->size + 1) & 0xfffe; ++ rx->size = remaining; + } + + if (skb->len != offset) { +- netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n", +- skb->len); ++ netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d, %d\n", ++ skb->len, offset); + return 0; + } ++ + return 1; + } + ++static int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb) ++{ ++ struct asix_common_private *dp = dev->driver_priv; ++ struct asix_rx_fixup_info *rx = &dp->rx_fixup_info; ++ ++ return asix_rx_fixup_internal(dev, skb, rx); ++} ++ + static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, + gfp_t flags) + { +@@ -1110,9 +1161,19 @@ static int ax88772_bind(struct usbnet *d + dev->rx_urb_size = 2048; + } + ++ dev->driver_priv = kzalloc(sizeof(struct asix_common_private), ++ GFP_KERNEL); ++ if (!dev->driver_priv) ++ return -ENOMEM; ++ + return 0; + } + ++static void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf) ++{ ++ kfree(dev->driver_priv); ++} ++ + static const struct ethtool_ops ax88178_ethtool_ops = { + .get_drvinfo = asix_get_drvinfo, + .get_link = asix_get_link, +@@ -1445,6 +1506,11 @@ static int ax88178_bind(struct usbnet *d + dev->rx_urb_size = 2048; + } + ++ dev->driver_priv = kzalloc(sizeof(struct asix_common_private), ++ GFP_KERNEL); ++ if (!dev->driver_priv) ++ return -ENOMEM; ++ + return 0; + } + +@@ -1491,22 +1557,25 @@ static const struct driver_info hawking_ + static const struct driver_info ax88772_info = { + .description = "ASIX AX88772 USB 2.0 Ethernet", + .bind = ax88772_bind, ++ .unbind = ax88772_unbind, + .status = asix_status, + .link_reset = ax88772_link_reset, + .reset = ax88772_reset, +- .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET, +- .rx_fixup = asix_rx_fixup, ++ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | ++ FLAG_MULTI_PACKET, ++ .rx_fixup = asix_rx_fixup_common, + .tx_fixup = asix_tx_fixup, + }; + + static const struct driver_info ax88178_info = { + .description = "ASIX AX88178 USB 2.0 Ethernet", + .bind = ax88178_bind, ++ .unbind = ax88772_unbind, + .status = asix_status, + .link_reset = ax88178_link_reset, + .reset = ax88178_reset, + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR, +- .rx_fixup = asix_rx_fixup, ++ .rx_fixup = asix_rx_fixup_common, + .tx_fixup = asix_tx_fixup, + }; + diff --git a/queue-3.4/series b/queue-3.4/series index 3416d6675f1..87efdb112bf 100644 --- a/queue-3.4/series +++ b/queue-3.4/series @@ -95,3 +95,5 @@ iwlwifi-dvm-don-t-send-bt_config-on-devices-w-o-bluetooth.patch iwlwifi-dvm-fix-calling-ieee80211_chswitch_done-with-null.patch iwlwifi-pcie-add-skus-for-6000-6005-and-6235-series.patch rtlwifi-fix-endian-error-in-extracting-packet-type.patch +net-asix-handle-packets-crossing-urb-boundaries.patch +net-asix-add-missing-flag-to-struct-driver_info.patch