tcp: limit payload size of sacked skbs
[pandora-kernel.git] / net / ipv4 / tcp_input.c
index 3877e16..7db2297 100644 (file)
@@ -87,7 +87,7 @@ int sysctl_tcp_adv_win_scale __read_mostly = 1;
 EXPORT_SYMBOL(sysctl_tcp_adv_win_scale);
 
 /* rfc5961 challenge ack rate limiting */
-int sysctl_tcp_challenge_ack_limit = 100;
+int sysctl_tcp_challenge_ack_limit = 1000;
 
 int sysctl_tcp_stdurg __read_mostly;
 int sysctl_tcp_rfc1337 __read_mostly;
@@ -1303,13 +1303,14 @@ static int tcp_match_skb_to_sack(struct sock *sk, struct sk_buff *skb,
                 */
                if (pkt_len > mss) {
                        unsigned int new_len = (pkt_len / mss) * mss;
-                       if (!in_sack && new_len < pkt_len) {
+                       if (!in_sack && new_len < pkt_len)
                                new_len += mss;
-                               if (new_len >= skb->len)
-                                       return 0;
-                       }
                        pkt_len = new_len;
                }
+
+               if (pkt_len >= skb->len && !in_sack)
+                       return 0;
+
                err = tcp_fragment(sk, skb, pkt_len, mss);
                if (err < 0)
                        return err;
@@ -1430,7 +1431,7 @@ static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,
        TCP_SKB_CB(skb)->seq += shifted;
 
        skb_shinfo(prev)->gso_segs += pcount;
-       BUG_ON(skb_shinfo(skb)->gso_segs < pcount);
+       WARN_ON_ONCE(tcp_skb_pcount(skb) < pcount);
        skb_shinfo(skb)->gso_segs -= pcount;
 
        /* When we're adding to gso_segs == 1, gso_size will be zero,
@@ -1498,6 +1499,21 @@ static int skb_can_shift(const struct sk_buff *skb)
        return !skb_headlen(skb) && skb_is_nonlinear(skb);
 }
 
+int tcp_skb_shift(struct sk_buff *to, struct sk_buff *from,
+                 int pcount, int shiftlen)
+{
+       /* TCP min gso_size is 8 bytes (TCP_MIN_GSO_SIZE)
+        * Since TCP_SKB_CB(skb)->tcp_gso_segs is 16 bits, we need
+        * to make sure not storing more than 65535 * 8 bytes per skb,
+        * even if current MSS is bigger.
+        */
+       if (unlikely(to->len + shiftlen >= 65535 * TCP_MIN_GSO_SIZE))
+               return 0;
+       if (unlikely(tcp_skb_pcount(to) + pcount > 65535))
+               return 0;
+       return skb_shift(to, from, shiftlen);
+}
+
 /* Try collapsing SACK blocks spanning across multiple skbs to a single
  * skb.
  */
@@ -1509,6 +1525,7 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb,
        struct tcp_sock *tp = tcp_sk(sk);
        struct sk_buff *prev;
        int mss;
+       int next_pcount;
        int pcount = 0;
        int len;
        int in_sack;
@@ -1603,7 +1620,7 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb,
        if (!after(TCP_SKB_CB(skb)->seq + len, tp->snd_una))
                goto fallback;
 
-       if (!skb_shift(prev, skb, len))
+       if (!tcp_skb_shift(prev, skb, pcount, len))
                goto fallback;
        if (!tcp_shifted_skb(sk, skb, state, pcount, len, mss, dup_sack))
                goto out;
@@ -1622,9 +1639,10 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb,
                goto out;
 
        len = skb->len;
-       if (skb_shift(prev, skb, len)) {
-               pcount += tcp_skb_pcount(skb);
-               tcp_shifted_skb(sk, skb, state, tcp_skb_pcount(skb), len, mss, 0);
+       next_pcount = tcp_skb_pcount(skb);
+       if (tcp_skb_shift(prev, skb, next_pcount, len)) {
+               pcount += next_pcount;
+               tcp_shifted_skb(sk, skb, state, next_pcount, len, mss, 0);
        }
 
 out:
@@ -3424,7 +3442,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
                        int delta;
 
                        /* Non-retransmitted hole got filled? That's reordering */
-                       if (reord < prior_fackets)
+                       if (reord < prior_fackets && reord <= tp->fackets_out)
                                tcp_update_reordering(sk, tp->fackets_out - reord, 0);
 
                        delta = tcp_is_fack(tp) ? pkts_acked :
@@ -3715,13 +3733,20 @@ static void tcp_send_challenge_ack(struct sock *sk)
        /* unprotected vars, we dont care of overwrites */
        static u32 challenge_timestamp;
        static unsigned int challenge_count;
-       u32 now = jiffies / HZ;
+       u32 count, now = jiffies / HZ;
 
        if (now != challenge_timestamp) {
+               u32 half = (sysctl_tcp_challenge_ack_limit + 1) >> 1;
+
                challenge_timestamp = now;
-               challenge_count = 0;
-       }
-       if (++challenge_count <= sysctl_tcp_challenge_ack_limit) {
+               ACCESS_ONCE(challenge_count) =
+                       half + (u32)(
+                       ((u64) random32() * sysctl_tcp_challenge_ack_limit)
+                       >> 32);
+       }
+       count = ACCESS_ONCE(challenge_count);
+       if (count > 0) {
+               ACCESS_ONCE(challenge_count) = count - 1;
                NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPCHALLENGEACK);
                tcp_send_ack(sk);
        }
@@ -5198,7 +5223,7 @@ static int tcp_copy_to_iovec(struct sock *sk, struct sk_buff *skb, int hlen)
                err = skb_copy_datagram_iovec(skb, hlen, tp->ucopy.iov, chunk);
        else
                err = skb_copy_and_csum_datagram_iovec(skb, hlen,
-                                                      tp->ucopy.iov, chunk);
+                                                      tp->ucopy.iov);
 
        if (!err) {
                tp->ucopy.len -= chunk;