]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - net/ipv4/tcp.c
net/tcp-fastopen: Add new API support
[mirror_ubuntu-bionic-kernel.git] / net / ipv4 / tcp.c
index c43eb1a831d7a0a36b447421908a149b1808590b..d9735b76d0730600e35259e824ada9c1396a6ab3 100644 (file)
@@ -533,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();
@@ -1071,6 +1077,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))
@@ -1085,9 +1092,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);
+       inet->defer_connect = 0;
        *copied = tp->fastopen_req->copied;
        tcp_free_fastopen_req(tp);
        return err;
@@ -1107,7 +1124,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;
@@ -2656,6 +2673,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;
@@ -3016,6 +3045,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;