Merge remote-tracking branch 'stable/linux-3.0.y' into develop-3.0
[firefly-linux-kernel-4.4.55.git] / net / ipv4 / tcp.c
index d99fd5c91903ed9ff5f36a85c07ff201a3e9182d..4a2d6f50be8592b4634b0612775a11829c132aeb 100644 (file)
 #include <net/xfrm.h>
 #include <net/ip.h>
 #include <net/ip6_route.h>
+#include <net/ipv6.h>
+#include <net/transp_v6.h>
 #include <net/netdma.h>
 #include <net/sock.h>
 
@@ -741,7 +743,9 @@ static unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now,
                           old_size_goal + mss_now > xmit_size_goal)) {
                        xmit_size_goal = old_size_goal;
                } else {
-                       tp->xmit_size_goal_segs = xmit_size_goal / mss_now;
+                       tp->xmit_size_goal_segs =
+                               min_t(u16, xmit_size_goal / mss_now,
+                                     sk->sk_gso_max_segs);
                        xmit_size_goal = tp->xmit_size_goal_segs * mss_now;
                }
        }
@@ -852,8 +856,7 @@ new_segment:
 wait_for_sndbuf:
                set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
 wait_for_memory:
-               if (copied)
-                       tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
+               tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
 
                if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
                        goto do_error;
@@ -862,7 +865,7 @@ wait_for_memory:
        }
 
 out:
-       if (copied)
+       if (copied && !(flags & MSG_SENDPAGE_NOTLAST))
                tcp_push(sk, flags, mss_now, tp->nonagle);
        return copied;
 
@@ -2408,7 +2411,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
                /* Cap the max timeout in ms TCP will retry/retrans
                 * before giving up and aborting (ETIMEDOUT) a connection.
                 */
-               icsk->icsk_user_timeout = msecs_to_jiffies(val);
+               if (val < 0)
+                       err = -EINVAL;
+               else
+                       icsk->icsk_user_timeout = msecs_to_jiffies(val);
                break;
        default:
                err = -ENOPROTOOPT;
@@ -3233,8 +3239,8 @@ __setup("thash_entries=", set_thash_entries);
 void __init tcp_init(void)
 {
        struct sk_buff *skb = NULL;
-       unsigned long nr_pages, limit;
-       int i, max_share, cnt;
+       unsigned long limit;
+       int i, max_rshare, max_wshare, cnt;
        unsigned long jiffy = jiffies;
 
        BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > sizeof(skb->cb));
@@ -3290,13 +3296,7 @@ void __init tcp_init(void)
        sysctl_tcp_max_orphans = cnt / 2;
        sysctl_max_syn_backlog = max(128, cnt / 256);
 
-       /* Set the pressure threshold to be a fraction of global memory that
-        * is up to 1/2 at 256 MB, decreasing toward zero with the amount of
-        * memory, with a floor of 128 pages.
-        */
-       nr_pages = totalram_pages - totalhigh_pages;
-       limit = min(nr_pages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT);
-       limit = (limit * (nr_pages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11);
+       limit = nr_free_buffer_pages() / 8;
        limit = max(limit, 128UL);
        sysctl_tcp_mem[0] = limit / 4 * 3;
        sysctl_tcp_mem[1] = limit;
@@ -3304,15 +3304,16 @@ void __init tcp_init(void)
 
        /* Set per-socket limits to no more than 1/128 the pressure threshold */
        limit = ((unsigned long)sysctl_tcp_mem[1]) << (PAGE_SHIFT - 7);
-       max_share = min(4UL*1024*1024, limit);
+       max_wshare = min(4UL*1024*1024, limit);
+       max_rshare = min(6UL*1024*1024, limit);
 
        sysctl_tcp_wmem[0] = SK_MEM_QUANTUM;
        sysctl_tcp_wmem[1] = 16*1024;
-       sysctl_tcp_wmem[2] = max(64*1024, max_share);
+       sysctl_tcp_wmem[2] = max(64*1024, max_wshare);
 
        sysctl_tcp_rmem[0] = SK_MEM_QUANTUM;
        sysctl_tcp_rmem[1] = 87380;
-       sysctl_tcp_rmem[2] = max(87380, max_share);
+       sysctl_tcp_rmem[2] = max(87380, max_rshare);
 
        printk(KERN_INFO "TCP: Hash tables configured "
               "(established %u bind %u)\n",
@@ -3334,7 +3335,7 @@ static int tcp_is_local(struct net *net, __be32 addr) {
        struct rtable *rt;
        struct flowi4 fl4 = { .daddr = addr };
        rt = ip_route_output_key(net, &fl4);
-       if (!rt)
+       if (IS_ERR_OR_NULL(rt))
                return 0;
        return rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK);
 }
@@ -3380,8 +3381,16 @@ restart:
                sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[bucket].chain) {
                        struct inet_sock *inet = inet_sk(sk);
 
+                       if (sysctl_ip_dynaddr && sk->sk_state == TCP_SYN_SENT)
+                               continue;
+                       if (sock_flag(sk, SOCK_DEAD))
+                               continue;
+
                        if (family == AF_INET) {
                                __be32 s4 = inet->inet_rcv_saddr;
+                               if (s4 == LOOPBACK4_IPV6)
+                                       continue;
+
                                if (in->s_addr != s4 &&
                                    !(in->s_addr == INADDR_ANY &&
                                      !tcp_is_local(net, s4)))
@@ -3393,7 +3402,11 @@ restart:
                                struct in6_addr *s6;
                                if (!inet->pinet6)
                                        continue;
+
                                s6 = &inet->pinet6->rcv_saddr;
+                               if (ipv6_addr_type(s6) == IPV6_ADDR_MAPPED)
+                                       continue;
+
                                if (!ipv6_addr_equal(in6, s6) &&
                                    !(ipv6_addr_equal(in6, &in6addr_any) &&
                                      !tcp_is_local6(net, s6)))
@@ -3401,11 +3414,6 @@ restart:
                        }
 #endif
 
-                       if (sysctl_ip_dynaddr && sk->sk_state == TCP_SYN_SENT)
-                               continue;
-                       if (sock_flag(sk, SOCK_DEAD))
-                               continue;
-
                        sock_hold(sk);
                        spin_unlock_bh(lock);