--- /dev/null
+From foo@baz Wed Feb 26 20:38:29 PST 2014
+From: Jiri Bohac <jiri@boha.cz>
+Date: Fri, 14 Feb 2014 18:13:50 +0100
+Subject: bonding: 802.3ad: make aggregator_identifier bond-private
+
+From: Jiri Bohac <jiri@boha.cz>
+
+[ Upstream commit 163c8ff30dbe473abfbb24a7eac5536c87f3baa9 ]
+
+aggregator_identifier is used to assign unique aggregator identifiers
+to aggregators of a bond during device enslaving.
+
+aggregator_identifier is currently a global variable that is zeroed in
+bond_3ad_initialize().
+
+This sequence will lead to duplicate aggregator identifiers for eth1 and eth3:
+
+create bond0
+change bond0 mode to 802.3ad
+enslave eth0 to bond0 //eth0 gets agg id 1
+enslave eth1 to bond0 //eth1 gets agg id 2
+create bond1
+change bond1 mode to 802.3ad
+enslave eth2 to bond1 //aggregator_identifier is reset to 0
+ //eth2 gets agg id 1
+enslave eth3 to bond0 //eth3 gets agg id 2
+
+Fix this by making aggregator_identifier private to the bond.
+
+Signed-off-by: Jiri Bohac <jbohac@suse.cz>
+Acked-by: Veaceslav Falico <vfalico@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/bonding/bond_3ad.c | 6 ++----
+ drivers/net/bonding/bond_3ad.h | 1 +
+ 2 files changed, 3 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/bonding/bond_3ad.c
++++ b/drivers/net/bonding/bond_3ad.c
+@@ -1854,8 +1854,6 @@ void bond_3ad_initiate_agg_selection(str
+ BOND_AD_INFO(bond).agg_select_timer = timeout;
+ }
+
+-static u16 aggregator_identifier;
+-
+ /**
+ * bond_3ad_initialize - initialize a bond's 802.3ad parameters and structures
+ * @bond: bonding struct to work on
+@@ -1869,7 +1867,7 @@ void bond_3ad_initialize(struct bonding
+ if (MAC_ADDRESS_COMPARE(&(BOND_AD_INFO(bond).system.sys_mac_addr),
+ bond->dev->dev_addr)) {
+
+- aggregator_identifier = 0;
++ BOND_AD_INFO(bond).aggregator_identifier = 0;
+
+ BOND_AD_INFO(bond).system.sys_priority = 0xFFFF;
+ BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->dev->dev_addr);
+@@ -1941,7 +1939,7 @@ int bond_3ad_bind_slave(struct slave *sl
+ ad_initialize_agg(aggregator);
+
+ aggregator->aggregator_mac_address = *((struct mac_addr *)bond->dev->dev_addr);
+- aggregator->aggregator_identifier = (++aggregator_identifier);
++ aggregator->aggregator_identifier = ++BOND_AD_INFO(bond).aggregator_identifier;
+ aggregator->slave = slave;
+ aggregator->is_active = 0;
+ aggregator->num_of_ports = 0;
+--- a/drivers/net/bonding/bond_3ad.h
++++ b/drivers/net/bonding/bond_3ad.h
+@@ -253,6 +253,7 @@ struct ad_system {
+ struct ad_bond_info {
+ struct ad_system system; /* 802.3ad system structure */
+ u32 agg_select_timer; // Timer to select aggregator after all adapter's hand shakes
++ u16 aggregator_identifier;
+ };
+
+ struct ad_slave_info {
--- /dev/null
+From foo@baz Wed Feb 26 20:38:29 PST 2014
+From: Florian Westphal <fw@strlen.de>
+Date: Sat, 22 Feb 2014 10:33:25 +0100
+Subject: net: add and use skb_gso_transport_seglen()
+
+From: Florian Westphal <fw@strlen.de>
+
+commit de960aa9ab4decc3304959f69533eef64d05d8e8 upstream.
+
+[ no skb_gso_seglen helper in 3.4, leave tbf alone ]
+
+This moves part of Eric Dumazets skb_gso_seglen helper from tbf sched to
+skbuff core so it may be reused by upcoming ip forwarding path patch.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Acked-by: Eric Dumazet <edumazet@google.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/skbuff.h | 2 ++
+ net/core/skbuff.c | 25 +++++++++++++++++++++++++
+ 2 files changed, 27 insertions(+)
+
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -2159,6 +2159,8 @@ extern int skb_shift(struct sk_bu
+ extern struct sk_buff *skb_segment(struct sk_buff *skb,
+ netdev_features_t features);
+
++unsigned int skb_gso_transport_seglen(const struct sk_buff *skb);
++
+ static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
+ int len, void *buffer)
+ {
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -45,6 +45,8 @@
+ #include <linux/in.h>
+ #include <linux/inet.h>
+ #include <linux/slab.h>
++#include <linux/tcp.h>
++#include <linux/udp.h>
+ #include <linux/netdevice.h>
+ #ifdef CONFIG_NET_CLS_ACT
+ #include <net/pkt_sched.h>
+@@ -3281,3 +3283,26 @@ void __skb_warn_lro_forwarding(const str
+ " while LRO is enabled\n", skb->dev->name);
+ }
+ EXPORT_SYMBOL(__skb_warn_lro_forwarding);
++
++/**
++ * skb_gso_transport_seglen - Return length of individual segments of a gso packet
++ *
++ * @skb: GSO skb
++ *
++ * skb_gso_transport_seglen is used to determine the real size of the
++ * individual segments, including Layer4 headers (TCP/UDP).
++ *
++ * The MAC/L2 or network (IP, IPv6) headers are not accounted for.
++ */
++unsigned int skb_gso_transport_seglen(const struct sk_buff *skb)
++{
++ const struct skb_shared_info *shinfo = skb_shinfo(skb);
++ unsigned int hdr_len;
++
++ if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))
++ hdr_len = tcp_hdrlen(skb);
++ else
++ hdr_len = sizeof(struct udphdr);
++ return hdr_len + shinfo->gso_size;
++}
++EXPORT_SYMBOL_GPL(skb_gso_transport_seglen);
--- /dev/null
+From foo@baz Wed Feb 26 20:38:29 PST 2014
+From: Maciej Żenczykowski <maze@google.com>
+Date: Fri, 7 Feb 2014 16:23:48 -0800
+Subject: net: fix 'ip rule' iif/oif device rename
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Maciej Żenczykowski <maze@google.com>
+
+[ Upstream commit 946c032e5a53992ea45e062ecb08670ba39b99e3 ]
+
+ip rules with iif/oif references do not update:
+(detach/attach) across interface renames.
+
+Signed-off-by: Maciej Żenczykowski <maze@google.com>
+CC: Willem de Bruijn <willemb@google.com>
+CC: Eric Dumazet <edumazet@google.com>
+CC: Chris Davis <chrismd@google.com>
+CC: Carlo Contavalli <ccontavalli@google.com>
+Google-Bug-Id: 12936021
+Acked-by: Eric Dumazet <edumazet@google.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/core/fib_rules.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/net/core/fib_rules.c
++++ b/net/core/fib_rules.c
+@@ -718,6 +718,13 @@ static int fib_rules_event(struct notifi
+ attach_rules(&ops->rules_list, dev);
+ break;
+
++ case NETDEV_CHANGENAME:
++ list_for_each_entry(ops, &net->rules_ops, list) {
++ detach_rules(&ops->rules_list, dev);
++ attach_rules(&ops->rules_list, dev);
++ }
++ break;
++
+ case NETDEV_UNREGISTER:
+ list_for_each_entry(ops, &net->rules_ops, list)
+ detach_rules(&ops->rules_list, dev);
--- /dev/null
+From foo@baz Wed Feb 26 20:38:29 PST 2014
+From: Florian Westphal <fw@strlen.de>
+Date: Sat, 22 Feb 2014 10:33:26 +0100
+Subject: net: ip, ipv6: handle gso skbs in forwarding path
+
+From: Florian Westphal <fw@strlen.de>
+
+commit fe6cc55f3a9a053482a76f5a6b2257cee51b4663 upstream.
+
+[ use zero netdev_feature mask to avoid backport of
+ netif_skb_dev_features function ]
+
+Marcelo Ricardo Leitner reported problems when the forwarding link path
+has a lower mtu than the incoming one if the inbound interface supports GRO.
+
+Given:
+Host <mtu1500> R1 <mtu1200> R2
+
+Host sends tcp stream which is routed via R1 and R2. R1 performs GRO.
+
+In this case, the kernel will fail to send ICMP fragmentation needed
+messages (or pkt too big for ipv6), as GSO packets currently bypass dstmtu
+checks in forward path. Instead, Linux tries to send out packets exceeding
+the mtu.
+
+When locking route MTU on Host (i.e., no ipv4 DF bit set), R1 does
+not fragment the packets when forwarding, and again tries to send out
+packets exceeding R1-R2 link mtu.
+
+This alters the forwarding dstmtu checks to take the individual gso
+segment lengths into account.
+
+For ipv6, we send out pkt too big error for gso if the individual
+segments are too big.
+
+For ipv4, we either send icmp fragmentation needed, or, if the DF bit
+is not set, perform software segmentation and let the output path
+create fragments when the packet is leaving the machine.
+It is not 100% correct as the error message will contain the headers of
+the GRO skb instead of the original/segmented one, but it seems to
+work fine in my (limited) tests.
+
+Eric Dumazet suggested to simply shrink mss via ->gso_size to avoid
+sofware segmentation.
+
+However it turns out that skb_segment() assumes skb nr_frags is related
+to mss size so we would BUG there. I don't want to mess with it considering
+Herbert and Eric disagree on what the correct behavior should be.
+
+Hannes Frederic Sowa notes that when we would shrink gso_size
+skb_segment would then also need to deal with the case where
+SKB_MAX_FRAGS would be exceeded.
+
+This uses sofware segmentation in the forward path when we hit ipv4
+non-DF packets and the outgoing link mtu is too small. Its not perfect,
+but given the lack of bug reports wrt. GRO fwd being broken this is a
+rare case anyway. Also its not like this could not be improved later
+once the dust settles.
+
+Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
+Reported-by: Marcelo Ricardo Leitner <mleitner@redhat.com>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/skbuff.h | 17 ++++++++++++
+ net/ipv4/ip_forward.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++--
+ net/ipv6/ip6_output.c | 13 ++++++++-
+ 3 files changed, 95 insertions(+), 3 deletions(-)
+
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -2582,5 +2582,22 @@ static inline bool skb_is_recycleable(co
+
+ return true;
+ }
++
++/**
++ * skb_gso_network_seglen - Return length of individual segments of a gso packet
++ *
++ * @skb: GSO skb
++ *
++ * skb_gso_network_seglen is used to determine the real size of the
++ * individual segments, including Layer3 (IP, IPv6) and L4 headers (TCP/UDP).
++ *
++ * The MAC/L2 header is not accounted for.
++ */
++static inline unsigned int skb_gso_network_seglen(const struct sk_buff *skb)
++{
++ unsigned int hdr_len = skb_transport_header(skb) -
++ skb_network_header(skb);
++ return hdr_len + skb_gso_transport_seglen(skb);
++}
+ #endif /* __KERNEL__ */
+ #endif /* _LINUX_SKBUFF_H */
+--- a/net/ipv4/ip_forward.c
++++ b/net/ipv4/ip_forward.c
+@@ -39,6 +39,68 @@
+ #include <net/route.h>
+ #include <net/xfrm.h>
+
++static bool ip_may_fragment(const struct sk_buff *skb)
++{
++ return unlikely((ip_hdr(skb)->frag_off & htons(IP_DF)) == 0) ||
++ !skb->local_df;
++}
++
++static bool ip_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu)
++{
++ if (skb->len <= mtu || skb->local_df)
++ return false;
++
++ if (skb_is_gso(skb) && skb_gso_network_seglen(skb) <= mtu)
++ return false;
++
++ return true;
++}
++
++static bool ip_gso_exceeds_dst_mtu(const struct sk_buff *skb)
++{
++ unsigned int mtu;
++
++ if (skb->local_df || !skb_is_gso(skb))
++ return false;
++
++ mtu = dst_mtu(skb_dst(skb));
++
++ /* if seglen > mtu, do software segmentation for IP fragmentation on
++ * output. DF bit cannot be set since ip_forward would have sent
++ * icmp error.
++ */
++ return skb_gso_network_seglen(skb) > mtu;
++}
++
++/* called if GSO skb needs to be fragmented on forward */
++static int ip_forward_finish_gso(struct sk_buff *skb)
++{
++ struct sk_buff *segs;
++ int ret = 0;
++
++ segs = skb_gso_segment(skb, 0);
++ if (IS_ERR(segs)) {
++ kfree_skb(skb);
++ return -ENOMEM;
++ }
++
++ consume_skb(skb);
++
++ do {
++ struct sk_buff *nskb = segs->next;
++ int err;
++
++ segs->next = NULL;
++ err = dst_output(segs);
++
++ if (err && ret == 0)
++ ret = err;
++ segs = nskb;
++ } while (segs);
++
++ return ret;
++}
++
+ static int ip_forward_finish(struct sk_buff *skb)
+ {
+ struct ip_options * opt = &(IPCB(skb)->opt);
+@@ -48,6 +110,9 @@ static int ip_forward_finish(struct sk_b
+ if (unlikely(opt->optlen))
+ ip_forward_options(skb);
+
++ if (ip_gso_exceeds_dst_mtu(skb))
++ return ip_forward_finish_gso(skb);
++
+ return dst_output(skb);
+ }
+
+@@ -87,8 +152,7 @@ int ip_forward(struct sk_buff *skb)
+ if (opt->is_strictroute && opt->nexthop != rt->rt_gateway)
+ goto sr_failed;
+
+- if (unlikely(skb->len > dst_mtu(&rt->dst) && !skb_is_gso(skb) &&
+- (ip_hdr(skb)->frag_off & htons(IP_DF))) && !skb->local_df) {
++ if (!ip_may_fragment(skb) && ip_exceeds_mtu(skb, dst_mtu(&rt->dst))) {
+ IP_INC_STATS(dev_net(rt->dst.dev), IPSTATS_MIB_FRAGFAILS);
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
+ htonl(dst_mtu(&rt->dst)));
+--- a/net/ipv6/ip6_output.c
++++ b/net/ipv6/ip6_output.c
+@@ -382,6 +382,17 @@ static inline int ip6_forward_finish(str
+ return dst_output(skb);
+ }
+
++static bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu)
++{
++ if (skb->len <= mtu || skb->local_df)
++ return false;
++
++ if (skb_is_gso(skb) && skb_gso_network_seglen(skb) <= mtu)
++ return false;
++
++ return true;
++}
++
+ int ip6_forward(struct sk_buff *skb)
+ {
+ struct dst_entry *dst = skb_dst(skb);
+@@ -503,7 +514,7 @@ int ip6_forward(struct sk_buff *skb)
+ if (mtu < IPV6_MIN_MTU)
+ mtu = IPV6_MIN_MTU;
+
+- if (skb->len > mtu && !skb_is_gso(skb)) {
++ if (ip6_pkt_too_big(skb, mtu)) {
+ /* Again, force OUTPUT device used as source address */
+ skb->dev = dst->dev;
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
--- /dev/null
+From foo@baz Wed Feb 26 20:38:29 PST 2014
+From: Daniel Borkmann <dborkman@redhat.com>
+Date: Mon, 17 Feb 2014 12:11:11 +0100
+Subject: net: sctp: fix sctp_connectx abi for ia32 emulation/compat mode
+
+From: Daniel Borkmann <dborkman@redhat.com>
+
+[ Upstream commit ffd5939381c609056b33b7585fb05a77b4c695f3 ]
+
+SCTP's sctp_connectx() abi breaks for 64bit kernels compiled with 32bit
+emulation (e.g. ia32 emulation or x86_x32). Due to internal usage of
+'struct sctp_getaddrs_old' which includes a struct sockaddr pointer,
+sizeof(param) check will always fail in kernel as the structure in
+64bit kernel space is 4bytes larger than for user binaries compiled
+in 32bit mode. Thus, applications making use of sctp_connectx() won't
+be able to run under such circumstances.
+
+Introduce a compat interface in the kernel to deal with such
+situations by using a 'struct compat_sctp_getaddrs_old' structure
+where user data is copied into it, and then sucessively transformed
+into a 'struct sctp_getaddrs_old' structure with the help of
+compat_ptr(). That fixes sctp_connectx() abi without any changes
+needed in user space, and lets the SCTP test suite pass when compiled
+in 32bit and run on 64bit kernels.
+
+Fixes: f9c67811ebc0 ("sctp: Fix regression introduced by new sctp_connectx api")
+Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
+Acked-by: Neil Horman <nhorman@tuxdriver.com>
+Acked-by: Vlad Yasevich <vyasevich@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/sctp/socket.c | 41 ++++++++++++++++++++++++++++++++---------
+ 1 file changed, 32 insertions(+), 9 deletions(-)
+
+--- a/net/sctp/socket.c
++++ b/net/sctp/socket.c
+@@ -70,6 +70,7 @@
+ #include <linux/init.h>
+ #include <linux/crypto.h>
+ #include <linux/slab.h>
++#include <linux/compat.h>
+
+ #include <net/ip.h>
+ #include <net/icmp.h>
+@@ -1376,11 +1377,19 @@ SCTP_STATIC int sctp_setsockopt_connectx
+ /*
+ * New (hopefully final) interface for the API.
+ * We use the sctp_getaddrs_old structure so that use-space library
+- * can avoid any unnecessary allocations. The only defferent part
++ * can avoid any unnecessary allocations. The only different part
+ * is that we store the actual length of the address buffer into the
+- * addrs_num structure member. That way we can re-use the existing
++ * addrs_num structure member. That way we can re-use the existing
+ * code.
+ */
++#ifdef CONFIG_COMPAT
++struct compat_sctp_getaddrs_old {
++ sctp_assoc_t assoc_id;
++ s32 addr_num;
++ compat_uptr_t addrs; /* struct sockaddr * */
++};
++#endif
++
+ SCTP_STATIC int sctp_getsockopt_connectx3(struct sock* sk, int len,
+ char __user *optval,
+ int __user *optlen)
+@@ -1389,16 +1398,30 @@ SCTP_STATIC int sctp_getsockopt_connectx
+ sctp_assoc_t assoc_id = 0;
+ int err = 0;
+
+- if (len < sizeof(param))
+- return -EINVAL;
++#ifdef CONFIG_COMPAT
++ if (is_compat_task()) {
++ struct compat_sctp_getaddrs_old param32;
+
+- if (copy_from_user(¶m, optval, sizeof(param)))
+- return -EFAULT;
++ if (len < sizeof(param32))
++ return -EINVAL;
++ if (copy_from_user(¶m32, optval, sizeof(param32)))
++ return -EFAULT;
+
+- err = __sctp_setsockopt_connectx(sk,
+- (struct sockaddr __user *)param.addrs,
+- param.addr_num, &assoc_id);
++ param.assoc_id = param32.assoc_id;
++ param.addr_num = param32.addr_num;
++ param.addrs = compat_ptr(param32.addrs);
++ } else
++#endif
++ {
++ if (len < sizeof(param))
++ return -EINVAL;
++ if (copy_from_user(¶m, optval, sizeof(param)))
++ return -EFAULT;
++ }
+
++ err = __sctp_setsockopt_connectx(sk, (struct sockaddr __user *)
++ param.addrs, param.addr_num,
++ &assoc_id);
+ if (err == 0 || err == -EINPROGRESS) {
+ if (copy_to_user(optval, &assoc_id, sizeof(assoc_id)))
+ return -EFAULT;
rtl8187-fix-regression-on-mips-without-coherent-dma.patch
rtlwifi-fix-incorrect-return-from-rtl_ps_enable_nic.patch
rtlwifi-rtl8192ce-fix-too-long-disable-of-irqs.patch
+net-fix-ip-rule-iif-oif-device-rename.patch
+tg3-fix-deadlock-in-tg3_change_mtu.patch
+bonding-802.3ad-make-aggregator_identifier-bond-private.patch
+usbnet-remove-generic-hard_header_len-check.patch
+net-sctp-fix-sctp_connectx-abi-for-ia32-emulation-compat-mode.patch
+net-add-and-use-skb_gso_transport_seglen.patch
+net-ip-ipv6-handle-gso-skbs-in-forwarding-path.patch
--- /dev/null
+From foo@baz Wed Feb 26 20:38:29 PST 2014
+From: Nithin Sujir <nsujir@broadcom.com>
+Date: Thu, 6 Feb 2014 14:13:05 -0800
+Subject: tg3: Fix deadlock in tg3_change_mtu()
+
+From: Nithin Sujir <nsujir@broadcom.com>
+
+[ Upstream commit c6993dfd7db9b0c6b7ca7503a56fda9236a4710f ]
+
+Quoting David Vrabel -
+"5780 cards cannot have jumbo frames and TSO enabled together. When
+jumbo frames are enabled by setting the MTU, the TSO feature must be
+cleared. This is done indirectly by calling netdev_update_features()
+which will call tg3_fix_features() to actually clear the flags.
+
+netdev_update_features() will also trigger a new netlink message for the
+feature change event which will result in a call to tg3_get_stats64()
+which deadlocks on the tg3 lock."
+
+tg3_set_mtu() does not need to be under the tg3 lock since converting
+the flags to use set_bit(). Move it out to after tg3_netif_stop().
+
+Reported-by: David Vrabel <david.vrabel@citrix.com>
+Tested-by: David Vrabel <david.vrabel@citrix.com>
+Signed-off-by: Michael Chan <mchan@broadcom.com>
+Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/broadcom/tg3.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/tg3.c
++++ b/drivers/net/ethernet/broadcom/tg3.c
+@@ -12343,12 +12343,12 @@ static int tg3_change_mtu(struct net_dev
+
+ tg3_netif_stop(tp);
+
++ tg3_set_mtu(dev, tp, new_mtu);
++
+ tg3_full_lock(tp, 1);
+
+ tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
+
+- tg3_set_mtu(dev, tp, new_mtu);
+-
+ /* Reset PHY, otherwise the read DMA engine will be in a mode that
+ * breaks all requests to 256 bytes.
+ */
--- /dev/null
+From foo@baz Wed Feb 26 20:38:29 PST 2014
+From: Emil Goode <emilgoode@gmail.com>
+Date: Thu, 13 Feb 2014 17:50:19 +0100
+Subject: usbnet: remove generic hard_header_len check
+
+From: Emil Goode <emilgoode@gmail.com>
+
+[ Upstream commit eb85569fe2d06c2fbf4de7b66c263ca095b397aa ]
+
+This patch removes a generic hard_header_len check from the usbnet
+module that is causing dropped packages under certain circumstances
+for devices that send rx packets that cross urb boundaries.
+
+One example is the AX88772B which occasionally send rx packets that
+cross urb boundaries where 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.
+
+With AX88772B 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 the following changes:
+- Removes the generic hard_header_len check in the rx_complete
+ function in the usbnet module.
+- Introduces a ETH_HLEN check for skbs that are not cloned from
+ within a rx_fixup callback.
+- For safety a hard_header_len check is added to each rx_fixup
+ callback function that could be affected by this change.
+ These extra checks could possibly be removed by someone
+ who has the hardware to test.
+- Removes a call to dev_kfree_skb_any() and instead utilizes the
+ dev->done list to queue skbs for cleanup.
+
+The changes place full responsibility on the rx_fixup callback
+functions that clone skbs to only pass valid skbs to the
+usbnet_skb_return function.
+
+Signed-off-by: Emil Goode <emilgoode@gmail.com>
+Reported-by: Igor Gnatenko <i.gnatenko.brain@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/usb/gl620a.c | 4 ++++
+ drivers/net/usb/mcs7830.c | 5 +++--
+ drivers/net/usb/net1080.c | 4 ++++
+ drivers/net/usb/qmi_wwan.c | 8 ++++----
+ drivers/net/usb/rndis_host.c | 4 ++++
+ drivers/net/usb/smsc75xx.c | 4 ++++
+ drivers/net/usb/smsc95xx.c | 4 ++++
+ drivers/net/usb/usbnet.c | 25 ++++++++++---------------
+ 8 files changed, 37 insertions(+), 21 deletions(-)
+
+--- a/drivers/net/usb/gl620a.c
++++ b/drivers/net/usb/gl620a.c
+@@ -86,6 +86,10 @@ static int genelink_rx_fixup(struct usbn
+ u32 size;
+ u32 count;
+
++ /* This check is no longer done by usbnet */
++ if (skb->len < dev->net->hard_header_len)
++ return 0;
++
+ header = (struct gl_header *) skb->data;
+
+ // get the packet count of the received skb
+--- a/drivers/net/usb/mcs7830.c
++++ b/drivers/net/usb/mcs7830.c
+@@ -601,8 +601,9 @@ static int mcs7830_rx_fixup(struct usbne
+ {
+ u8 status;
+
+- if (skb->len == 0) {
+- dev_err(&dev->udev->dev, "unexpected empty rx frame\n");
++ /* This check is no longer done by usbnet */
++ if (skb->len < dev->net->hard_header_len) {
++ dev_err(&dev->udev->dev, "unexpected tiny rx frame\n");
+ return 0;
+ }
+
+--- a/drivers/net/usb/net1080.c
++++ b/drivers/net/usb/net1080.c
+@@ -419,6 +419,10 @@ static int net1080_rx_fixup(struct usbne
+ struct nc_trailer *trailer;
+ u16 hdr_len, packet_len;
+
++ /* This check is no longer done by usbnet */
++ if (skb->len < dev->net->hard_header_len)
++ return 0;
++
+ if (!(skb->len & 0x01)) {
+ #ifdef DEBUG
+ struct net_device *net = dev->net;
+--- a/drivers/net/usb/qmi_wwan.c
++++ b/drivers/net/usb/qmi_wwan.c
+@@ -202,10 +202,10 @@ static int qmi_wwan_rx_fixup(struct usbn
+ {
+ __be16 proto;
+
+- /* usbnet rx_complete guarantees that skb->len is at least
+- * hard_header_len, so we can inspect the dest address without
+- * checking skb->len
+- */
++ /* This check is no longer done by usbnet */
++ if (skb->len < dev->net->hard_header_len)
++ return 0;
++
+ switch (skb->data[0] & 0xf0) {
+ case 0x40:
+ proto = htons(ETH_P_IP);
+--- a/drivers/net/usb/rndis_host.c
++++ b/drivers/net/usb/rndis_host.c
+@@ -490,6 +490,10 @@ EXPORT_SYMBOL_GPL(rndis_unbind);
+ */
+ int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+ {
++ /* This check is no longer done by usbnet */
++ if (skb->len < dev->net->hard_header_len)
++ return 0;
++
+ /* peripheral may have batched packets to us... */
+ while (likely(skb->len)) {
+ struct rndis_data_hdr *hdr = (void *)skb->data;
+--- a/drivers/net/usb/smsc75xx.c
++++ b/drivers/net/usb/smsc75xx.c
+@@ -1093,6 +1093,10 @@ static void smsc75xx_rx_csum_offload(str
+
+ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+ {
++ /* This check is no longer done by usbnet */
++ if (skb->len < dev->net->hard_header_len)
++ return 0;
++
+ while (skb->len > 0) {
+ u32 rx_cmd_a, rx_cmd_b, align_count, size;
+ struct sk_buff *ax_skb;
+--- a/drivers/net/usb/smsc95xx.c
++++ b/drivers/net/usb/smsc95xx.c
+@@ -1041,6 +1041,10 @@ static void smsc95xx_rx_csum_offload(str
+
+ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+ {
++ /* This check is no longer done by usbnet */
++ if (skb->len < dev->net->hard_header_len)
++ return 0;
++
+ while (skb->len > 0) {
+ u32 header, align_count;
+ struct sk_buff *ax_skb;
+--- a/drivers/net/usb/usbnet.c
++++ b/drivers/net/usb/usbnet.c
+@@ -415,17 +415,19 @@ static inline void rx_process (struct us
+ }
+ // else network stack removes extra byte if we forced a short packet
+
+- if (skb->len) {
+- /* all data was already cloned from skb inside the driver */
+- if (dev->driver_info->flags & FLAG_MULTI_PACKET)
+- dev_kfree_skb_any(skb);
+- else
+- usbnet_skb_return(dev, skb);
++ /* all data was already cloned from skb inside the driver */
++ if (dev->driver_info->flags & FLAG_MULTI_PACKET)
++ goto done;
++
++ if (skb->len < ETH_HLEN) {
++ dev->net->stats.rx_errors++;
++ dev->net->stats.rx_length_errors++;
++ netif_dbg(dev, rx_err, dev->net, "rx length %d\n", skb->len);
++ } else {
++ usbnet_skb_return(dev, skb);
+ return;
+ }
+
+- netif_dbg(dev, rx_err, dev->net, "drop\n");
+- dev->net->stats.rx_errors++;
+ done:
+ skb_queue_tail(&dev->done, skb);
+ }
+@@ -447,13 +449,6 @@ static void rx_complete (struct urb *urb
+ switch (urb_status) {
+ /* success */
+ case 0:
+- if (skb->len < dev->net->hard_header_len) {
+- state = rx_cleanup;
+- dev->net->stats.rx_errors++;
+- dev->net->stats.rx_length_errors++;
+- netif_dbg(dev, rx_err, dev->net,
+- "rx length %d\n", skb->len);
+- }
+ break;
+
+ /* stalls need manual reset. this is rare ... except that