]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 8 Mar 2014 01:05:39 +0000 (17:05 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 8 Mar 2014 01:05:39 +0000 (17:05 -0800)
added patches:
net-asix-add-missing-flag-to-struct-driver_info.patch
net-asix-handle-packets-crossing-urb-boundaries.patch

queue-3.4/net-asix-add-missing-flag-to-struct-driver_info.patch [new file with mode: 0644]
queue-3.4/net-asix-handle-packets-crossing-urb-boundaries.patch [new file with mode: 0644]
queue-3.4/series

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 (file)
index 0000000..80fc9a0
--- /dev/null
@@ -0,0 +1,40 @@
+From d43ff4cd798911736fb39025ec8004284b1b0bc2 Mon Sep 17 00:00:00 2001
+From: Emil Goode <emilgoode@gmail.com>
+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 <emilgoode@gmail.com>
+
+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 <emilgoode@gmail.com>
+Reported-by: Bjørn Mork <bjorn@mork.no>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..d1474e7
--- /dev/null
@@ -0,0 +1,221 @@
+From emilgoode@gmail.com  Fri Mar  7 17:03:47 2014
+From: Lucas Stach <dev@lynxeye.de>
+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 <emilgoode@gmail.com>, Lucas Stach <dev@lynxeye.de>, "David S. Miller" <davem@davemloft.net>
+Message-ID: <1393501899-17169-2-git-send-email-emilgoode@gmail.com>
+
+From: Lucas Stach <dev@lynxeye.de>
+
+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 <dev@lynxeye.de>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+[ Emil: backported to 3.4: dropped changes to drivers/net/usb/ax88172a.c ]
+Signed-off-by: Emil Goode <emilgoode@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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,
+ };
index 3416d6675f1f6e6898ad461b40b63c17fdab519d..87efdb112bfa19ebde347aa0c8d5fca6ce5c693f 100644 (file)
@@ -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