OSDN Git Service

tcp: restore fastopen with no data in SYN packet
authorEric Dumazet <edumazet@google.com>
Wed, 16 Dec 2015 21:53:10 +0000 (13:53 -0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 17 Dec 2015 20:37:39 +0000 (15:37 -0500)
Yuchung tracked a regression caused by commit 57be5bdad759 ("ip: convert
tcp_sendmsg() to iov_iter primitives") for TCP Fast Open.

Some Fast Open users do not actually add any data in the SYN packet.

Fixes: 57be5bdad759 ("ip: convert tcp_sendmsg() to iov_iter primitives")
Reported-by: Yuchung Cheng <ycheng@google.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Acked-by: Yuchung Cheng <ycheng@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/tcp_output.c

index cb7ca56..9bfc39f 100644 (file)
@@ -3150,7 +3150,7 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct tcp_fastopen_request *fo = tp->fastopen_req;
-       int syn_loss = 0, space, err = 0, copied;
+       int syn_loss = 0, space, err = 0;
        unsigned long last_syn_loss = 0;
        struct sk_buff *syn_data;
 
@@ -3188,17 +3188,18 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn)
                goto fallback;
        syn_data->ip_summed = CHECKSUM_PARTIAL;
        memcpy(syn_data->cb, syn->cb, sizeof(syn->cb));
-       copied = copy_from_iter(skb_put(syn_data, space), space,
-                               &fo->data->msg_iter);
-       if (unlikely(!copied)) {
-               kfree_skb(syn_data);
-               goto fallback;
-       }
-       if (copied != space) {
-               skb_trim(syn_data, copied);
-               space = copied;
+       if (space) {
+               int copied = copy_from_iter(skb_put(syn_data, space), space,
+                                           &fo->data->msg_iter);
+               if (unlikely(!copied)) {
+                       kfree_skb(syn_data);
+                       goto fallback;
+               }
+               if (copied != space) {
+                       skb_trim(syn_data, copied);
+                       space = copied;
+               }
        }
-
        /* No more data pending in inet_wait_for_connect() */
        if (space == fo->size)
                fo->data = NULL;