]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/ipv4/tcp.c
Merge branch 'next' of git://git.infradead.org/users/vkoul/slave-dma
[karo-tx-linux.git] / net / ipv4 / tcp.c
index db0856ad70cb86c431d02768d799f6f7f94109c1..47e854fcae24dd8c108e93a2b5a22801a68d7232 100644 (file)
@@ -400,6 +400,8 @@ void tcp_init_sock(struct sock *sk)
        tcp_enable_early_retrans(tp);
        icsk->icsk_ca_ops = &tcp_init_congestion_ops;
 
+       tp->tsoffset = 0;
+
        sk->sk_state = TCP_CLOSE;
 
        sk->sk_write_space = sk_stream_write_space;
@@ -895,6 +897,7 @@ new_segment:
                        get_page(page);
                        skb_fill_page_desc(skb, i, page, offset, copy);
                }
+               skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
 
                skb->len += copy;
                skb->data_len += copy;
@@ -1428,12 +1431,12 @@ static void tcp_service_net_dma(struct sock *sk, bool wait)
 }
 #endif
 
-static inline struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off)
+static struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off)
 {
        struct sk_buff *skb;
        u32 offset;
 
-       skb_queue_walk(&sk->sk_receive_queue, skb) {
+       while ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) {
                offset = seq - TCP_SKB_CB(skb)->seq;
                if (tcp_hdr(skb)->syn)
                        offset--;
@@ -1441,6 +1444,11 @@ static inline struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off)
                        *off = offset;
                        return skb;
                }
+               /* This looks weird, but this can happen if TCP collapsing
+                * splitted a fat GRO packet, while we released socket lock
+                * in skb_splice_bits()
+                */
+               sk_eat_skb(sk, skb, false);
        }
        return NULL;
 }
@@ -1482,7 +1490,7 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
                                        break;
                        }
                        used = recv_actor(desc, skb, offset, len);
-                       if (used < 0) {
+                       if (used <= 0) {
                                if (!copied)
                                        copied = used;
                                break;
@@ -1520,8 +1528,10 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
        tcp_rcv_space_adjust(sk);
 
        /* Clean up data we have read: This will do ACK frames. */
-       if (copied > 0)
+       if (copied > 0) {
+               tcp_recv_skb(sk, seq, &offset);
                tcp_cleanup_rbuf(sk, copied);
+       }
        return copied;
 }
 EXPORT_SYMBOL(tcp_read_sock);
@@ -2280,7 +2290,6 @@ int tcp_disconnect(struct sock *sk, int flags)
        tp->packets_out = 0;
        tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
        tp->snd_cwnd_cnt = 0;
-       tp->bytes_acked = 0;
        tp->window_clamp = 0;
        tcp_set_ca_state(sk, TCP_CA_Open);
        tcp_clear_retrans(tp);
@@ -2704,6 +2713,12 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
                else
                        err = -EINVAL;
                break;
+       case TCP_TIMESTAMP:
+               if (!tp->repair)
+                       err = -EPERM;
+               else
+                       tp->tsoffset = val - tcp_time_stamp;
+               break;
        default:
                err = -ENOPROTOOPT;
                break;
@@ -2952,6 +2967,9 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
        case TCP_USER_TIMEOUT:
                val = jiffies_to_msecs(icsk->icsk_user_timeout);
                break;
+       case TCP_TIMESTAMP:
+               val = tcp_time_stamp + tp->tsoffset;
+               break;
        default:
                return -ENOPROTOOPT;
        }
@@ -3025,6 +3043,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb,
                               SKB_GSO_DODGY |
                               SKB_GSO_TCP_ECN |
                               SKB_GSO_TCPV6 |
+                              SKB_GSO_GRE |
                               0) ||
                             !(type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))))
                        goto out;
@@ -3236,7 +3255,7 @@ __tcp_alloc_md5sig_pool(struct sock *sk)
                struct crypto_hash *hash;
 
                hash = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
-               if (!hash || IS_ERR(hash))
+               if (IS_ERR_OR_NULL(hash))
                        goto out_free;
 
                per_cpu_ptr(pool, cpu)->md5_desc.tfm = hash;