From 521ac8d5b6789509eb77d0ed6a1f1956493d93dc Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 26 Feb 2014 21:12:27 -0800 Subject: [PATCH] 3.4-stable patches added patches: bonding-802.3ad-make-aggregator_identifier-bond-private.patch net-add-and-use-skb_gso_transport_seglen.patch net-fix-ip-rule-iif-oif-device-rename.patch net-ip-ipv6-handle-gso-skbs-in-forwarding-path.patch net-sctp-fix-sctp_connectx-abi-for-ia32-emulation-compat-mode.patch tg3-fix-deadlock-in-tg3_change_mtu.patch usbnet-remove-generic-hard_header_len-check.patch --- ...e-aggregator_identifier-bond-private.patch | 77 +++++++ ...add-and-use-skb_gso_transport_seglen.patch | 72 ++++++ ...et-fix-ip-rule-iif-oif-device-rename.patch | 44 ++++ ...6-handle-gso-skbs-in-forwarding-path.patch | 215 ++++++++++++++++++ ...x-abi-for-ia32-emulation-compat-mode.patch | 105 +++++++++ queue-3.4/series | 7 + .../tg3-fix-deadlock-in-tg3_change_mtu.patch | 49 ++++ ...remove-generic-hard_header_len-check.patch | 197 ++++++++++++++++ 8 files changed, 766 insertions(+) create mode 100644 queue-3.4/bonding-802.3ad-make-aggregator_identifier-bond-private.patch create mode 100644 queue-3.4/net-add-and-use-skb_gso_transport_seglen.patch create mode 100644 queue-3.4/net-fix-ip-rule-iif-oif-device-rename.patch create mode 100644 queue-3.4/net-ip-ipv6-handle-gso-skbs-in-forwarding-path.patch create mode 100644 queue-3.4/net-sctp-fix-sctp_connectx-abi-for-ia32-emulation-compat-mode.patch create mode 100644 queue-3.4/tg3-fix-deadlock-in-tg3_change_mtu.patch create mode 100644 queue-3.4/usbnet-remove-generic-hard_header_len-check.patch diff --git a/queue-3.4/bonding-802.3ad-make-aggregator_identifier-bond-private.patch b/queue-3.4/bonding-802.3ad-make-aggregator_identifier-bond-private.patch new file mode 100644 index 00000000000..6c6f1374669 --- /dev/null +++ b/queue-3.4/bonding-802.3ad-make-aggregator_identifier-bond-private.patch @@ -0,0 +1,77 @@ +From foo@baz Wed Feb 26 20:38:29 PST 2014 +From: Jiri Bohac +Date: Fri, 14 Feb 2014 18:13:50 +0100 +Subject: bonding: 802.3ad: make aggregator_identifier bond-private + +From: Jiri Bohac + +[ 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 +Acked-by: Veaceslav Falico +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + 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 { diff --git a/queue-3.4/net-add-and-use-skb_gso_transport_seglen.patch b/queue-3.4/net-add-and-use-skb_gso_transport_seglen.patch new file mode 100644 index 00000000000..a370dd38dd7 --- /dev/null +++ b/queue-3.4/net-add-and-use-skb_gso_transport_seglen.patch @@ -0,0 +1,72 @@ +From foo@baz Wed Feb 26 20:38:29 PST 2014 +From: Florian Westphal +Date: Sat, 22 Feb 2014 10:33:25 +0100 +Subject: net: add and use skb_gso_transport_seglen() + +From: Florian Westphal + +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 +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include + #include ++#include ++#include + #include + #ifdef CONFIG_NET_CLS_ACT + #include +@@ -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); diff --git a/queue-3.4/net-fix-ip-rule-iif-oif-device-rename.patch b/queue-3.4/net-fix-ip-rule-iif-oif-device-rename.patch new file mode 100644 index 00000000000..7c82370162e --- /dev/null +++ b/queue-3.4/net-fix-ip-rule-iif-oif-device-rename.patch @@ -0,0 +1,44 @@ +From foo@baz Wed Feb 26 20:38:29 PST 2014 +From: Maciej Å»enczykowski +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 + +[ Upstream commit 946c032e5a53992ea45e062ecb08670ba39b99e3 ] + +ip rules with iif/oif references do not update: +(detach/attach) across interface renames. + +Signed-off-by: Maciej Å»enczykowski +CC: Willem de Bruijn +CC: Eric Dumazet +CC: Chris Davis +CC: Carlo Contavalli +Google-Bug-Id: 12936021 +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + 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); diff --git a/queue-3.4/net-ip-ipv6-handle-gso-skbs-in-forwarding-path.patch b/queue-3.4/net-ip-ipv6-handle-gso-skbs-in-forwarding-path.patch new file mode 100644 index 00000000000..5e408bcf4e0 --- /dev/null +++ b/queue-3.4/net-ip-ipv6-handle-gso-skbs-in-forwarding-path.patch @@ -0,0 +1,215 @@ +From foo@baz Wed Feb 26 20:38:29 PST 2014 +From: Florian Westphal +Date: Sat, 22 Feb 2014 10:33:26 +0100 +Subject: net: ip, ipv6: handle gso skbs in forwarding path + +From: Florian Westphal + +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 R1 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 +Reported-by: Marcelo Ricardo Leitner +Signed-off-by: Florian Westphal +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include + ++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); diff --git a/queue-3.4/net-sctp-fix-sctp_connectx-abi-for-ia32-emulation-compat-mode.patch b/queue-3.4/net-sctp-fix-sctp_connectx-abi-for-ia32-emulation-compat-mode.patch new file mode 100644 index 00000000000..7b40a950088 --- /dev/null +++ b/queue-3.4/net-sctp-fix-sctp_connectx-abi-for-ia32-emulation-compat-mode.patch @@ -0,0 +1,105 @@ +From foo@baz Wed Feb 26 20:38:29 PST 2014 +From: Daniel Borkmann +Date: Mon, 17 Feb 2014 12:11:11 +0100 +Subject: net: sctp: fix sctp_connectx abi for ia32 emulation/compat mode + +From: Daniel Borkmann + +[ 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 +Acked-by: Neil Horman +Acked-by: Vlad Yasevich +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include + #include ++#include + + #include + #include +@@ -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; diff --git a/queue-3.4/series b/queue-3.4/series index 489d05e2600..68d4dc12577 100644 --- a/queue-3.4/series +++ b/queue-3.4/series @@ -9,3 +9,10 @@ cifs-ensure-that-uncached-writes-handle-unmapped-areas-correctly.patch 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 diff --git a/queue-3.4/tg3-fix-deadlock-in-tg3_change_mtu.patch b/queue-3.4/tg3-fix-deadlock-in-tg3_change_mtu.patch new file mode 100644 index 00000000000..bda26d98f9b --- /dev/null +++ b/queue-3.4/tg3-fix-deadlock-in-tg3_change_mtu.patch @@ -0,0 +1,49 @@ +From foo@baz Wed Feb 26 20:38:29 PST 2014 +From: Nithin Sujir +Date: Thu, 6 Feb 2014 14:13:05 -0800 +Subject: tg3: Fix deadlock in tg3_change_mtu() + +From: Nithin Sujir + +[ 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 +Tested-by: David Vrabel +Signed-off-by: Michael Chan +Signed-off-by: Nithin Nayak Sujir +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + 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. + */ diff --git a/queue-3.4/usbnet-remove-generic-hard_header_len-check.patch b/queue-3.4/usbnet-remove-generic-hard_header_len-check.patch new file mode 100644 index 00000000000..7f7a6d410cc --- /dev/null +++ b/queue-3.4/usbnet-remove-generic-hard_header_len-check.patch @@ -0,0 +1,197 @@ +From foo@baz Wed Feb 26 20:38:29 PST 2014 +From: Emil Goode +Date: Thu, 13 Feb 2014 17:50:19 +0100 +Subject: usbnet: remove generic hard_header_len check + +From: Emil Goode + +[ 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 +Reported-by: Igor Gnatenko +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + 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 -- 2.47.3