]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/ipv4/tcp.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[karo-tx-linux.git] / net / ipv4 / tcp.c
index aba6ea76338e35e36124580dcab3c80e3c638659..d44a6989e76d69aa44e2a26d37b4204376c94966 100644 (file)
@@ -420,9 +420,7 @@ void tcp_init_sock(struct sock *sk)
        sk->sk_sndbuf = sysctl_tcp_wmem[1];
        sk->sk_rcvbuf = sysctl_tcp_rmem[1];
 
-       local_bh_disable();
        sk_sockets_allocated_inc(sk);
-       local_bh_enable();
 }
 EXPORT_SYMBOL(tcp_init_sock);
 
@@ -535,6 +533,12 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
 
                if (tp->urg_data & TCP_URG_VALID)
                        mask |= POLLPRI;
+       } else if (sk->sk_state == TCP_SYN_SENT && inet_sk(sk)->defer_connect) {
+               /* Active TCP fastopen socket with defer_connect
+                * Return POLLOUT so application can call write()
+                * in order for kernel to generate SYN+data
+                */
+               mask |= POLLOUT | POLLWRNORM;
        }
        /* This barrier is coupled with smp_wmb() in tcp_reset() */
        smp_rmb();
@@ -769,6 +773,12 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos,
                                ret = -EAGAIN;
                                break;
                        }
+                       /* if __tcp_splice_read() got nothing while we have
+                        * an skb in receive queue, we do not want to loop.
+                        * This might happen with URG data.
+                        */
+                       if (!skb_queue_empty(&sk->sk_receive_queue))
+                               break;
                        sk_wait_data(sk, &timeo, NULL);
                        if (signal_pending(current)) {
                                ret = sock_intr_errno(timeo);
@@ -1073,6 +1083,7 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg,
                                int *copied, size_t size)
 {
        struct tcp_sock *tp = tcp_sk(sk);
+       struct inet_sock *inet = inet_sk(sk);
        int err, flags;
 
        if (!(sysctl_tcp_fastopen & TFO_CLIENT_ENABLE))
@@ -1087,9 +1098,19 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg,
        tp->fastopen_req->data = msg;
        tp->fastopen_req->size = size;
 
+       if (inet->defer_connect) {
+               err = tcp_connect(sk);
+               /* Same failure procedure as in tcp_v4/6_connect */
+               if (err) {
+                       tcp_set_state(sk, TCP_CLOSE);
+                       inet->inet_dport = 0;
+                       sk->sk_route_caps = 0;
+               }
+       }
        flags = (msg->msg_flags & MSG_DONTWAIT) ? O_NONBLOCK : 0;
        err = __inet_stream_connect(sk->sk_socket, msg->msg_name,
-                                   msg->msg_namelen, flags);
+                                   msg->msg_namelen, flags, 1);
+       inet->defer_connect = 0;
        *copied = tp->fastopen_req->copied;
        tcp_free_fastopen_req(tp);
        return err;
@@ -1109,7 +1130,7 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
        lock_sock(sk);
 
        flags = msg->msg_flags;
-       if (flags & MSG_FASTOPEN) {
+       if (unlikely(flags & MSG_FASTOPEN || inet_sk(sk)->defer_connect)) {
                err = tcp_sendmsg_fastopen(sk, msg, &copied_syn, size);
                if (err == -EINPROGRESS && copied_syn > 0)
                        goto out;
@@ -2658,6 +2679,18 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
                        err = -EINVAL;
                }
                break;
+       case TCP_FASTOPEN_CONNECT:
+               if (val > 1 || val < 0) {
+                       err = -EINVAL;
+               } else if (sysctl_tcp_fastopen & TFO_CLIENT_ENABLE) {
+                       if (sk->sk_state == TCP_CLOSE)
+                               tp->fastopen_connect = val;
+                       else
+                               err = -EINVAL;
+               } else {
+                       err = -EOPNOTSUPP;
+               }
+               break;
        case TCP_TIMESTAMP:
                if (!tp->repair)
                        err = -EPERM;
@@ -2843,7 +2876,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk)
        struct sk_buff *stats;
        struct tcp_info info;
 
-       stats = alloc_skb(3 * nla_total_size_64bit(sizeof(u64)), GFP_ATOMIC);
+       stats = alloc_skb(5 * nla_total_size_64bit(sizeof(u64)), GFP_ATOMIC);
        if (!stats)
                return NULL;
 
@@ -2854,6 +2887,10 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk)
                          info.tcpi_rwnd_limited, TCP_NLA_PAD);
        nla_put_u64_64bit(stats, TCP_NLA_SNDBUF_LIMITED,
                          info.tcpi_sndbuf_limited, TCP_NLA_PAD);
+       nla_put_u64_64bit(stats, TCP_NLA_DATA_SEGS_OUT,
+                         tp->data_segs_out, TCP_NLA_PAD);
+       nla_put_u64_64bit(stats, TCP_NLA_TOTAL_RETRANS,
+                         tp->total_retrans, TCP_NLA_PAD);
        return stats;
 }
 
@@ -3018,6 +3055,10 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
                val = icsk->icsk_accept_queue.fastopenq.max_qlen;
                break;
 
+       case TCP_FASTOPEN_CONNECT:
+               val = tp->fastopen_connect;
+               break;
+
        case TCP_TIMESTAMP:
                val = tcp_time_stamp + tp->tsoffset;
                break;