Merge tag 'v3.10.95' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / net / ipv4 / tcp_ipv4.c
index fb244f4a38b523b4939d1a3cd4e69ae59cc69cbb..be8f79c0879b09b67b81ee5c5b302c30abda9bcc 100644 (file)
@@ -268,7 +268,7 @@ EXPORT_SYMBOL(tcp_v4_connect);
  * It can be called through tcp_release_cb() if socket was owned by user
  * at the time tcp_v4_err() was called to handle ICMP message.
  */
-static void tcp_v4_mtu_reduced(struct sock *sk)
+void tcp_v4_mtu_reduced(struct sock *sk)
 {
        struct dst_entry *dst;
        struct inet_sock *inet = inet_sk(sk);
@@ -298,6 +298,7 @@ static void tcp_v4_mtu_reduced(struct sock *sk)
                tcp_simple_retransmit(sk);
        } /* else let the usual retransmit timer handle it */
 }
+EXPORT_SYMBOL(tcp_v4_mtu_reduced);
 
 static void do_redirect(struct sk_buff *skb, struct sock *sk)
 {
@@ -706,7 +707,8 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
 
        net = dev_net(skb_dst(skb)->dev);
        arg.tos = ip_hdr(skb)->tos;
-       ip_send_unicast_reply(net, skb, ip_hdr(skb)->saddr,
+       ip_send_unicast_reply(*this_cpu_ptr(net->ipv4.tcp_sk),
+                             skb, ip_hdr(skb)->saddr,
                              ip_hdr(skb)->daddr, &arg, arg.iov[0].iov_len);
 
        TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
@@ -789,7 +791,8 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
        if (oif)
                arg.bound_dev_if = oif;
        arg.tos = tos;
-       ip_send_unicast_reply(net, skb, ip_hdr(skb)->saddr,
+       ip_send_unicast_reply(*this_cpu_ptr(net->ipv4.tcp_sk),
+                             skb, ip_hdr(skb)->saddr,
                              ip_hdr(skb)->daddr, &arg, arg.iov[0].iov_len);
 
        TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
@@ -1012,7 +1015,8 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,
        }
 
        md5sig = rcu_dereference_protected(tp->md5sig_info,
-                                          sock_owned_by_user(sk));
+                                          sock_owned_by_user(sk) ||
+                                          lockdep_is_held(&sk->sk_lock.slock));
        if (!md5sig) {
                md5sig = kmalloc(sizeof(*md5sig), gfp);
                if (!md5sig)
@@ -1899,7 +1903,7 @@ void tcp_v4_early_demux(struct sk_buff *skb)
                skb->sk = sk;
                skb->destructor = sock_edemux;
                if (sk->sk_state != TCP_TIME_WAIT) {
-                       struct dst_entry *dst = sk->sk_rx_dst;
+                       struct dst_entry *dst = ACCESS_ONCE(sk->sk_rx_dst);
 
                        if (dst)
                                dst = dst_check(dst, 0);
@@ -2143,6 +2147,7 @@ const struct inet_connection_sock_af_ops ipv4_specific = {
        .compat_setsockopt = compat_ip_setsockopt,
        .compat_getsockopt = compat_ip_getsockopt,
 #endif
+       .mtu_reduced       = tcp_v4_mtu_reduced,
 };
 EXPORT_SYMBOL(ipv4_specific);
 
@@ -2978,7 +2983,6 @@ struct proto tcp_prot = {
        .sendpage               = tcp_sendpage,
        .backlog_rcv            = tcp_v4_do_rcv,
        .release_cb             = tcp_release_cb,
-       .mtu_reduced            = tcp_v4_mtu_reduced,
        .hash                   = inet_hash,
        .unhash                 = inet_unhash,
        .get_port               = inet_csk_get_port,
@@ -3008,14 +3012,39 @@ struct proto tcp_prot = {
 };
 EXPORT_SYMBOL(tcp_prot);
 
+static void __net_exit tcp_sk_exit(struct net *net)
+{
+       int cpu;
+
+       for_each_possible_cpu(cpu)
+               inet_ctl_sock_destroy(*per_cpu_ptr(net->ipv4.tcp_sk, cpu));
+       free_percpu(net->ipv4.tcp_sk);
+}
+
 static int __net_init tcp_sk_init(struct net *net)
 {
+       int res, cpu;
+
+       net->ipv4.tcp_sk = alloc_percpu(struct sock *);
+       if (!net->ipv4.tcp_sk)
+               return -ENOMEM;
+
+       for_each_possible_cpu(cpu) {
+               struct sock *sk;
+
+               res = inet_ctl_sock_create(&sk, PF_INET, SOCK_RAW,
+                                          IPPROTO_TCP, net);
+               if (res)
+                       goto fail;
+               *per_cpu_ptr(net->ipv4.tcp_sk, cpu) = sk;
+       }
        net->ipv4.sysctl_tcp_ecn = 2;
        return 0;
-}
 
-static void __net_exit tcp_sk_exit(struct net *net)
-{
+fail:
+       tcp_sk_exit(net);
+
+       return res;
 }
 
 static void __net_exit tcp_sk_exit_batch(struct list_head *net_exit_list)