]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 3 Jun 2012 12:08:17 +0000 (05:08 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 3 Jun 2012 12:08:17 +0000 (05:08 -0700)
added patches:
asix-allow-full-size-8021q-frames-to-be-received.patch
ipv4-fix-the-rcu-race-between-free_fib_info-and-ip_route_output_slow.patch
ipv6-fix-incorrect-ipsec-fragment.patch
l2tp-fix-oops-in-l2tp-ip-sockets-for-connect-af_unspec-case.patch
skb-avoid-unnecessary-reallocations-in-__skb_cow.patch
xfrm-take-net-hdr-len-into-account-for-esp-payload-size-calculation.patch

queue-3.4/asix-allow-full-size-8021q-frames-to-be-received.patch [new file with mode: 0644]
queue-3.4/ipv4-fix-the-rcu-race-between-free_fib_info-and-ip_route_output_slow.patch [new file with mode: 0644]
queue-3.4/ipv6-fix-incorrect-ipsec-fragment.patch [new file with mode: 0644]
queue-3.4/l2tp-fix-oops-in-l2tp-ip-sockets-for-connect-af_unspec-case.patch [new file with mode: 0644]
queue-3.4/series
queue-3.4/skb-avoid-unnecessary-reallocations-in-__skb_cow.patch [new file with mode: 0644]
queue-3.4/xfrm-take-net-hdr-len-into-account-for-esp-payload-size-calculation.patch [new file with mode: 0644]

diff --git a/queue-3.4/asix-allow-full-size-8021q-frames-to-be-received.patch b/queue-3.4/asix-allow-full-size-8021q-frames-to-be-received.patch
new file mode 100644 (file)
index 0000000..4d81a1e
--- /dev/null
@@ -0,0 +1,46 @@
+From 79fb330c51db3b91f5e4cfbd4a305e4a481785a2 Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <edumazet@google.com>
+Date: Mon, 28 May 2012 22:31:41 +0000
+Subject: asix: allow full size 8021Q frames to be received
+
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 9dae31009b1a00d926c6fe032d5a88099620adc3 ]
+
+asix driver drops 8021Q full size frames because it doesn't take into
+account VLAN header size.
+
+Tested on AX88772 adapter.
+
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+CC: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+CC: Allan Chou <allan@asix.com.tw>
+CC: Trond Wuellner <trond@chromium.org>
+CC: Grant Grundler <grundler@chromium.org>
+CC: Paul Stewart <pstew@chromium.org>
+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
+@@ -35,6 +35,7 @@
+ #include <linux/crc32.h>
+ #include <linux/usb/usbnet.h>
+ #include <linux/slab.h>
++#include <linux/if_vlan.h>
+ #define DRIVER_VERSION "22-Dec-2011"
+ #define DRIVER_NAME "asix"
+@@ -321,7 +322,7 @@ static int asix_rx_fixup(struct usbnet *
+                       return 0;
+               }
+-              if ((size > dev->net->mtu + ETH_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);
diff --git a/queue-3.4/ipv4-fix-the-rcu-race-between-free_fib_info-and-ip_route_output_slow.patch b/queue-3.4/ipv4-fix-the-rcu-race-between-free_fib_info-and-ip_route_output_slow.patch
new file mode 100644 (file)
index 0000000..4a17c54
--- /dev/null
@@ -0,0 +1,89 @@
+From cbb5c7c2b1bd52c8929e78b2b0b532e03e6c4e5d Mon Sep 17 00:00:00 2001
+From: Yanmin Zhang <yanmin_zhang@linux.intel.com>
+Date: Wed, 23 May 2012 15:39:45 +0000
+Subject: ipv4: fix the rcu race between free_fib_info and ip_route_output_slow
+
+
+From: Yanmin Zhang <yanmin_zhang@linux.intel.com>
+
+[ Upstream commit e49cc0da7283088c5e03d475ffe2fdcb24a6d5b1 ]
+
+We hit a kernel OOPS.
+
+<3>[23898.789643] BUG: sleeping function called from invalid context at
+/data/buildbot/workdir/ics/hardware/intel/linux-2.6/arch/x86/mm/fault.c:1103
+<3>[23898.862215] in_atomic(): 0, irqs_disabled(): 0, pid: 10526, name:
+Thread-6683
+<4>[23898.967805] HSU serial 0000:00:05.1: 0000:00:05.2:HSU serial prevented me
+to suspend...
+<4>[23899.258526] Pid: 10526, comm: Thread-6683 Tainted: G        W
+3.0.8-137685-ge7742f9 #1
+<4>[23899.357404] HSU serial 0000:00:05.1: 0000:00:05.2:HSU serial prevented me
+to suspend...
+<4>[23899.904225] Call Trace:
+<4>[23899.989209]  [<c1227f50>] ? pgtable_bad+0x130/0x130
+<4>[23900.000416]  [<c1238c2a>] __might_sleep+0x10a/0x110
+<4>[23900.007357]  [<c1228021>] do_page_fault+0xd1/0x3c0
+<4>[23900.013764]  [<c18e9ba9>] ? restore_all+0xf/0xf
+<4>[23900.024024]  [<c17c007b>] ? napi_complete+0x8b/0x690
+<4>[23900.029297]  [<c1227f50>] ? pgtable_bad+0x130/0x130
+<4>[23900.123739]  [<c1227f50>] ? pgtable_bad+0x130/0x130
+<4>[23900.128955]  [<c18ea0c3>] error_code+0x5f/0x64
+<4>[23900.133466]  [<c1227f50>] ? pgtable_bad+0x130/0x130
+<4>[23900.138450]  [<c17f6298>] ? __ip_route_output_key+0x698/0x7c0
+<4>[23900.144312]  [<c17f5f8d>] ? __ip_route_output_key+0x38d/0x7c0
+<4>[23900.150730]  [<c17f63df>] ip_route_output_flow+0x1f/0x60
+<4>[23900.156261]  [<c181de58>] ip4_datagram_connect+0x188/0x2b0
+<4>[23900.161960]  [<c18e981f>] ? _raw_spin_unlock_bh+0x1f/0x30
+<4>[23900.167834]  [<c18298d6>] inet_dgram_connect+0x36/0x80
+<4>[23900.173224]  [<c14f9e88>] ? _copy_from_user+0x48/0x140
+<4>[23900.178817]  [<c17ab9da>] sys_connect+0x9a/0xd0
+<4>[23900.183538]  [<c132e93c>] ? alloc_file+0xdc/0x240
+<4>[23900.189111]  [<c123925d>] ? sub_preempt_count+0x3d/0x50
+
+Function free_fib_info resets nexthop_nh->nh_dev to NULL before releasing
+fi. Other cpu might be accessing fi. Fixing it by delaying the releasing.
+
+With the patch, we ran MTBF testing on Android mobile for 12 hours
+and didn't trigger the issue.
+
+Thank Eric for very detailed review/checking the issue.
+
+Signed-off-by: Yanmin Zhang <yanmin_zhang@linux.intel.com>
+Signed-off-by: Kun Jiang <kunx.jiang@intel.com>
+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/ipv4/fib_semantics.c |   12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/net/ipv4/fib_semantics.c
++++ b/net/ipv4/fib_semantics.c
+@@ -145,6 +145,12 @@ static void free_fib_info_rcu(struct rcu
+ {
+       struct fib_info *fi = container_of(head, struct fib_info, rcu);
++      change_nexthops(fi) {
++              if (nexthop_nh->nh_dev)
++                      dev_put(nexthop_nh->nh_dev);
++      } endfor_nexthops(fi);
++
++      release_net(fi->fib_net);
+       if (fi->fib_metrics != (u32 *) dst_default_metrics)
+               kfree(fi->fib_metrics);
+       kfree(fi);
+@@ -156,13 +162,7 @@ void free_fib_info(struct fib_info *fi)
+               pr_warn("Freeing alive fib_info %p\n", fi);
+               return;
+       }
+-      change_nexthops(fi) {
+-              if (nexthop_nh->nh_dev)
+-                      dev_put(nexthop_nh->nh_dev);
+-              nexthop_nh->nh_dev = NULL;
+-      } endfor_nexthops(fi);
+       fib_info_cnt--;
+-      release_net(fi->fib_net);
+       call_rcu(&fi->rcu, free_fib_info_rcu);
+ }
diff --git a/queue-3.4/ipv6-fix-incorrect-ipsec-fragment.patch b/queue-3.4/ipv6-fix-incorrect-ipsec-fragment.patch
new file mode 100644 (file)
index 0000000..4e99533
--- /dev/null
@@ -0,0 +1,175 @@
+From f5d52863e05bbd77c59a7c0736a5d7f7bf3ff24c Mon Sep 17 00:00:00 2001
+From: Gao feng <gaofeng@cn.fujitsu.com>
+Date: Sat, 26 May 2012 01:30:53 +0000
+Subject: ipv6: fix incorrect ipsec fragment
+
+
+From: Gao feng <gaofeng@cn.fujitsu.com>
+
+[ Upstream commit 0c1833797a5a6ec23ea9261d979aa18078720b74 ]
+
+Since commit ad0081e43a
+"ipv6: Fragment locally generated tunnel-mode IPSec6 packets as needed"
+the fragment of packets is incorrect.
+because tunnel mode needs IPsec headers and trailer for all fragments,
+while on transport mode it is sufficient to add the headers to the
+first fragment and the trailer to the last.
+
+so modify mtu and maxfraglen base on ipsec mode and if fragment is first
+or last.
+
+with my test,it work well(every fragment's size is the mtu)
+and does not trigger slow fragment path.
+
+Changes from v1:
+       though optimization, mtu_prev and maxfraglen_prev can be delete.
+       replace xfrm mode codes with dst_entry's new frag DST_XFRM_TUNNEL.
+       add fuction ip6_append_data_mtu to make codes clearer.
+
+Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/dst.h      |    1 
+ net/ipv6/ip6_output.c  |   68 ++++++++++++++++++++++++++++++++++++-------------
+ net/xfrm/xfrm_policy.c |    3 ++
+ 3 files changed, 54 insertions(+), 18 deletions(-)
+
+--- a/include/net/dst.h
++++ b/include/net/dst.h
+@@ -60,6 +60,7 @@ struct dst_entry {
+ #define DST_NOCOUNT           0x0020
+ #define DST_NOPEER            0x0040
+ #define DST_FAKE_RTABLE               0x0080
++#define DST_XFRM_TUNNEL               0x0100
+       short                   error;
+       short                   obsolete;
+--- a/net/ipv6/ip6_output.c
++++ b/net/ipv6/ip6_output.c
+@@ -1181,6 +1181,29 @@ static inline struct ipv6_rt_hdr *ip6_rt
+       return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL;
+ }
++static void ip6_append_data_mtu(int *mtu,
++                              int *maxfraglen,
++                              unsigned int fragheaderlen,
++                              struct sk_buff *skb,
++                              struct rt6_info *rt)
++{
++      if (!(rt->dst.flags & DST_XFRM_TUNNEL)) {
++              if (skb == NULL) {
++                      /* first fragment, reserve header_len */
++                      *mtu = *mtu - rt->dst.header_len;
++
++              } else {
++                      /*
++                       * this fragment is not first, the headers
++                       * space is regarded as data space.
++                       */
++                      *mtu = dst_mtu(rt->dst.path);
++              }
++              *maxfraglen = ((*mtu - fragheaderlen) & ~7)
++                            + fragheaderlen - sizeof(struct frag_hdr);
++      }
++}
++
+ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
+       int offset, int len, int odd, struct sk_buff *skb),
+       void *from, int length, int transhdrlen,
+@@ -1190,7 +1213,7 @@ int ip6_append_data(struct sock *sk, int
+       struct inet_sock *inet = inet_sk(sk);
+       struct ipv6_pinfo *np = inet6_sk(sk);
+       struct inet_cork *cork;
+-      struct sk_buff *skb;
++      struct sk_buff *skb, *skb_prev = NULL;
+       unsigned int maxfraglen, fragheaderlen;
+       int exthdrlen;
+       int dst_exthdrlen;
+@@ -1248,8 +1271,12 @@ int ip6_append_data(struct sock *sk, int
+               inet->cork.fl.u.ip6 = *fl6;
+               np->cork.hop_limit = hlimit;
+               np->cork.tclass = tclass;
+-              mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ?
+-                    rt->dst.dev->mtu : dst_mtu(&rt->dst);
++              if (rt->dst.flags & DST_XFRM_TUNNEL)
++                      mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ?
++                            rt->dst.dev->mtu : dst_mtu(&rt->dst);
++              else
++                      mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ?
++                            rt->dst.dev->mtu : dst_mtu(rt->dst.path);
+               if (np->frag_size < mtu) {
+                       if (np->frag_size)
+                               mtu = np->frag_size;
+@@ -1345,25 +1372,27 @@ int ip6_append_data(struct sock *sk, int
+                       unsigned int fraglen;
+                       unsigned int fraggap;
+                       unsigned int alloclen;
+-                      struct sk_buff *skb_prev;
+ alloc_new_skb:
+-                      skb_prev = skb;
+-
+                       /* There's no room in the current skb */
+-                      if (skb_prev)
+-                              fraggap = skb_prev->len - maxfraglen;
++                      if (skb)
++                              fraggap = skb->len - maxfraglen;
+                       else
+                               fraggap = 0;
++                      /* update mtu and maxfraglen if necessary */
++                      if (skb == NULL || skb_prev == NULL)
++                              ip6_append_data_mtu(&mtu, &maxfraglen,
++                                                  fragheaderlen, skb, rt);
++
++                      skb_prev = skb;
+                       /*
+                        * If remaining data exceeds the mtu,
+                        * we know we need more fragment(s).
+                        */
+                       datalen = length + fraggap;
+-                      if (datalen > (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen)
+-                              datalen = maxfraglen - fragheaderlen;
+-                      fraglen = datalen + fragheaderlen;
++                      if (datalen > (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen)
++                              datalen = maxfraglen - fragheaderlen - rt->dst.trailer_len;
+                       if ((flags & MSG_MORE) &&
+                           !(rt->dst.dev->features&NETIF_F_SG))
+                               alloclen = mtu;
+@@ -1372,13 +1401,16 @@ alloc_new_skb:
+                       alloclen += dst_exthdrlen;
+-                      /*
+-                       * The last fragment gets additional space at tail.
+-                       * Note: we overallocate on fragments with MSG_MODE
+-                       * because we have no idea if we're the last one.
+-                       */
+-                      if (datalen == length + fraggap)
+-                              alloclen += rt->dst.trailer_len;
++                      if (datalen != length + fraggap) {
++                              /*
++                               * this is not the last fragment, the trailer
++                               * space is regarded as data space.
++                               */
++                              datalen += rt->dst.trailer_len;
++                      }
++
++                      alloclen += rt->dst.trailer_len;
++                      fraglen = datalen + fragheaderlen;
+                       /*
+                        * We just reserve space for fragment header.
+--- a/net/xfrm/xfrm_policy.c
++++ b/net/xfrm/xfrm_policy.c
+@@ -1919,6 +1919,9 @@ no_transform:
+       }
+ ok:
+       xfrm_pols_put(pols, drop_pols);
++      if (dst && dst->xfrm &&
++          dst->xfrm->props.mode == XFRM_MODE_TUNNEL)
++              dst->flags |= DST_XFRM_TUNNEL;
+       return dst;
+ nopol:
diff --git a/queue-3.4/l2tp-fix-oops-in-l2tp-ip-sockets-for-connect-af_unspec-case.patch b/queue-3.4/l2tp-fix-oops-in-l2tp-ip-sockets-for-connect-af_unspec-case.patch
new file mode 100644 (file)
index 0000000..79bb121
--- /dev/null
@@ -0,0 +1,111 @@
+From 2f456e48e2ebd7455a5deb6cad8cc7da917dc028 Mon Sep 17 00:00:00 2001
+From: James Chapman <jchapman@katalix.com>
+Date: Tue, 29 May 2012 23:13:23 +0000
+Subject: l2tp: fix oops in L2TP IP sockets for connect() AF_UNSPEC case
+
+
+From: James Chapman <jchapman@katalix.com>
+
+[ Upstream commit c51ce49735c183ef2592db70f918ee698716276b ]
+
+An application may call connect() to disconnect a socket using an
+address with family AF_UNSPEC. The L2TP IP sockets were not handling
+this case when the socket is not bound and an attempt to connect()
+using AF_UNSPEC in such cases would result in an oops. This patch
+addresses the problem by protecting the sk_prot->disconnect() call
+against trying to unhash the socket before it is bound.
+
+The patch also adds more checks that the sockaddr supplied to bind()
+and connect() calls is valid.
+
+ RIP: 0010:[<ffffffff82e133b0>]  [<ffffffff82e133b0>] inet_unhash+0x50/0xd0
+ RSP: 0018:ffff88001989be28  EFLAGS: 00010293
+ Stack:
+  ffff8800407a8000 0000000000000000 ffff88001989be78 ffffffff82e3a249
+  ffffffff82e3a050 ffff88001989bec8 ffff88001989be88 ffff8800407a8000
+  0000000000000010 ffff88001989bec8 ffff88001989bea8 ffffffff82e42639
+ Call Trace:
+ [<ffffffff82e3a249>] udp_disconnect+0x1f9/0x290
+ [<ffffffff82e42639>] inet_dgram_connect+0x29/0x80
+ [<ffffffff82d012fc>] sys_connect+0x9c/0x100
+
+Reported-by: Sasha Levin <levinsasha928@gmail.com>
+Signed-off-by: James Chapman <jchapman@katalix.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_ip.c |   30 ++++++++++++++++++++++++------
+ 1 file changed, 24 insertions(+), 6 deletions(-)
+
+--- a/net/l2tp/l2tp_ip.c
++++ b/net/l2tp/l2tp_ip.c
+@@ -251,9 +251,16 @@ static int l2tp_ip_bind(struct sock *sk,
+ {
+       struct inet_sock *inet = inet_sk(sk);
+       struct sockaddr_l2tpip *addr = (struct sockaddr_l2tpip *) uaddr;
+-      int ret = -EINVAL;
++      int ret;
+       int chk_addr_ret;
++      if (!sock_flag(sk, SOCK_ZAPPED))
++              return -EINVAL;
++      if (addr_len < sizeof(struct sockaddr_l2tpip))
++              return -EINVAL;
++      if (addr->l2tp_family != AF_INET)
++              return -EINVAL;
++
+       ret = -EADDRINUSE;
+       read_lock_bh(&l2tp_ip_lock);
+       if (__l2tp_ip_bind_lookup(&init_net, addr->l2tp_addr.s_addr, sk->sk_bound_dev_if, addr->l2tp_conn_id))
+@@ -284,6 +291,8 @@ static int l2tp_ip_bind(struct sock *sk,
+       sk_del_node_init(sk);
+       write_unlock_bh(&l2tp_ip_lock);
+       ret = 0;
++      sock_reset_flag(sk, SOCK_ZAPPED);
++
+ out:
+       release_sock(sk);
+@@ -304,13 +313,14 @@ static int l2tp_ip_connect(struct sock *
+       __be32 saddr;
+       int oif, rc;
+-      rc = -EINVAL;
++      if (sock_flag(sk, SOCK_ZAPPED)) /* Must bind first - autobinding does not work */
++              return -EINVAL;
++
+       if (addr_len < sizeof(*lsa))
+-              goto out;
++              return -EINVAL;
+-      rc = -EAFNOSUPPORT;
+       if (lsa->l2tp_family != AF_INET)
+-              goto out;
++              return -EAFNOSUPPORT;
+       lock_sock(sk);
+@@ -364,6 +374,14 @@ out:
+       return rc;
+ }
++static int l2tp_ip_disconnect(struct sock *sk, int flags)
++{
++      if (sock_flag(sk, SOCK_ZAPPED))
++              return 0;
++
++      return udp_disconnect(sk, flags);
++}
++
+ static int l2tp_ip_getname(struct socket *sock, struct sockaddr *uaddr,
+                          int *uaddr_len, int peer)
+ {
+@@ -599,7 +617,7 @@ static struct proto l2tp_ip_prot = {
+       .close             = l2tp_ip_close,
+       .bind              = l2tp_ip_bind,
+       .connect           = l2tp_ip_connect,
+-      .disconnect        = udp_disconnect,
++      .disconnect        = l2tp_ip_disconnect,
+       .ioctl             = udp_ioctl,
+       .destroy           = l2tp_ip_destroy_sock,
+       .setsockopt        = ip_setsockopt,
index 6d92593e7ab9e3b47b7ec0d0d08b09c461e499db..56f12c68ce1bf37b6f4970ba7a3afdb69c03e10e 100644 (file)
@@ -50,3 +50,9 @@ drm-radeon-properly-program-gart-on-rv740-juniper-cypress-barts-hemlock.patch
 drm-radeon-fix-hd6790-hd6570-backend-programming.patch
 drm-ttm-fix-spinlock-imbalance.patch
 drm-vmwgfx-fix-nasty-write-past-alloced-memory-area.patch
+asix-allow-full-size-8021q-frames-to-be-received.patch
+ipv4-fix-the-rcu-race-between-free_fib_info-and-ip_route_output_slow.patch
+ipv6-fix-incorrect-ipsec-fragment.patch
+l2tp-fix-oops-in-l2tp-ip-sockets-for-connect-af_unspec-case.patch
+skb-avoid-unnecessary-reallocations-in-__skb_cow.patch
+xfrm-take-net-hdr-len-into-account-for-esp-payload-size-calculation.patch
diff --git a/queue-3.4/skb-avoid-unnecessary-reallocations-in-__skb_cow.patch b/queue-3.4/skb-avoid-unnecessary-reallocations-in-__skb_cow.patch
new file mode 100644 (file)
index 0000000..f1fefc2
--- /dev/null
@@ -0,0 +1,40 @@
+From 64305df8b10a0ea32cbef6a880c0b8911cca6cb8 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Tue, 29 May 2012 03:35:08 +0000
+Subject: skb: avoid unnecessary reallocations in __skb_cow
+
+
+From: Felix Fietkau <nbd@openwrt.org>
+
+[ Upstream commit 617c8c11236716dcbda877e764b7bf37c6fd8063 ]
+
+At the beginning of __skb_cow, headroom gets set to a minimum of
+NET_SKB_PAD. This causes unnecessary reallocations if the buffer was not
+cloned and the headroom is just below NET_SKB_PAD, but still more than the
+amount requested by the caller.
+This was showing up frequently in my tests on VLAN tx, where
+vlan_insert_tag calls skb_cow_head(skb, VLAN_HLEN).
+
+Locally generated packets should have enough headroom, and for forward
+paths, we already have NET_SKB_PAD bytes of headroom, so we don't need to
+add any extra space here.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+Signed-off-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 --
+ 1 file changed, 2 deletions(-)
+
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -1881,8 +1881,6 @@ static inline int __skb_cow(struct sk_bu
+ {
+       int delta = 0;
+-      if (headroom < NET_SKB_PAD)
+-              headroom = NET_SKB_PAD;
+       if (headroom > skb_headroom(skb))
+               delta = headroom - skb_headroom(skb);
diff --git a/queue-3.4/xfrm-take-net-hdr-len-into-account-for-esp-payload-size-calculation.patch b/queue-3.4/xfrm-take-net-hdr-len-into-account-for-esp-payload-size-calculation.patch
new file mode 100644 (file)
index 0000000..e990c15
--- /dev/null
@@ -0,0 +1,95 @@
+From 23e1aa6f7e9515763ea416c4aa6acb9eb138936d Mon Sep 17 00:00:00 2001
+From: Benjamin Poirier <bpoirier@suse.de>
+Date: Thu, 24 May 2012 11:32:38 +0000
+Subject: xfrm: take net hdr len into account for esp payload size calculation
+
+
+From: Benjamin Poirier <bpoirier@suse.de>
+
+[ Upstream commit 91657eafb64b4cb53ec3a2fbc4afc3497f735788 ]
+
+Corrects the function that determines the esp payload size. The calculations
+done in esp{4,6}_get_mtu() lead to overlength frames in transport mode for
+certain mtu values and suboptimal frames for others.
+
+According to what is done, mainly in esp{,6}_output() and tcp_mtu_to_mss(),
+net_header_len must be taken into account before doing the alignment
+calculation.
+
+Signed-off-by: Benjamin Poirier <bpoirier@suse.de>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ipv4/esp4.c |   24 +++++++++---------------
+ net/ipv6/esp6.c |   18 +++++++-----------
+ 2 files changed, 16 insertions(+), 26 deletions(-)
+
+--- a/net/ipv4/esp4.c
++++ b/net/ipv4/esp4.c
+@@ -459,28 +459,22 @@ static u32 esp4_get_mtu(struct xfrm_stat
+       struct esp_data *esp = x->data;
+       u32 blksize = ALIGN(crypto_aead_blocksize(esp->aead), 4);
+       u32 align = max_t(u32, blksize, esp->padlen);
+-      u32 rem;
+-
+-      mtu -= x->props.header_len + crypto_aead_authsize(esp->aead);
+-      rem = mtu & (align - 1);
+-      mtu &= ~(align - 1);
++      unsigned int net_adj;
+       switch (x->props.mode) {
+-      case XFRM_MODE_TUNNEL:
+-              break;
+-      default:
+       case XFRM_MODE_TRANSPORT:
+-              /* The worst case */
+-              mtu -= blksize - 4;
+-              mtu += min_t(u32, blksize - 4, rem);
+-              break;
+       case XFRM_MODE_BEET:
+-              /* The worst case. */
+-              mtu += min_t(u32, IPV4_BEET_PHMAXLEN, rem);
++              net_adj = sizeof(struct iphdr);
++              break;
++      case XFRM_MODE_TUNNEL:
++              net_adj = 0;
+               break;
++      default:
++              BUG();
+       }
+-      return mtu - 2;
++      return ((mtu - x->props.header_len - crypto_aead_authsize(esp->aead) -
++               net_adj) & ~(align - 1)) + (net_adj - 2);
+ }
+ static void esp4_err(struct sk_buff *skb, u32 info)
+--- a/net/ipv6/esp6.c
++++ b/net/ipv6/esp6.c
+@@ -411,19 +411,15 @@ static u32 esp6_get_mtu(struct xfrm_stat
+       struct esp_data *esp = x->data;
+       u32 blksize = ALIGN(crypto_aead_blocksize(esp->aead), 4);
+       u32 align = max_t(u32, blksize, esp->padlen);
+-      u32 rem;
++      unsigned int net_adj;
+-      mtu -= x->props.header_len + crypto_aead_authsize(esp->aead);
+-      rem = mtu & (align - 1);
+-      mtu &= ~(align - 1);
++      if (x->props.mode != XFRM_MODE_TUNNEL)
++              net_adj = sizeof(struct ipv6hdr);
++      else
++              net_adj = 0;
+-      if (x->props.mode != XFRM_MODE_TUNNEL) {
+-              u32 padsize = ((blksize - 1) & 7) + 1;
+-              mtu -= blksize - padsize;
+-              mtu += min_t(u32, blksize - padsize, rem);
+-      }
+-
+-      return mtu - 2;
++      return ((mtu - x->props.header_len - crypto_aead_authsize(esp->aead) -
++               net_adj) & ~(align - 1)) + (net_adj - 2);
+ }
+ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,