]> err.no Git - linux-2.6/blobdiff - net/ipv4/tcp_input.c
Merge branch 'release' of git://lm-sensors.org/kernel/mhoffman/hwmon-2.6
[linux-2.6] / net / ipv4 / tcp_input.c
index 74683d81c3f18f8c3450b3100ff89373179ea101..fec8a7a4dbaffa3781685fe9203b4c998482dc8d 100644 (file)
@@ -953,7 +953,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
        int prior_fackets;
        u32 lost_retrans = 0;
        int flag = 0;
-       int dup_sack = 0;
+       int found_dup_sack = 0;
        int cached_fack_count;
        int i;
        int first_sack_index;
@@ -964,20 +964,20 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
 
        /* Check for D-SACK. */
        if (before(ntohl(sp[0].start_seq), TCP_SKB_CB(ack_skb)->ack_seq)) {
-               dup_sack = 1;
+               found_dup_sack = 1;
                tp->rx_opt.sack_ok |= 4;
                NET_INC_STATS_BH(LINUX_MIB_TCPDSACKRECV);
        } else if (num_sacks > 1 &&
                        !after(ntohl(sp[0].end_seq), ntohl(sp[1].end_seq)) &&
                        !before(ntohl(sp[0].start_seq), ntohl(sp[1].start_seq))) {
-               dup_sack = 1;
+               found_dup_sack = 1;
                tp->rx_opt.sack_ok |= 4;
                NET_INC_STATS_BH(LINUX_MIB_TCPDSACKOFORECV);
        }
 
        /* D-SACK for already forgotten data...
         * Do dumb counting. */
-       if (dup_sack &&
+       if (found_dup_sack &&
                        !after(ntohl(sp[0].end_seq), prior_snd_una) &&
                        after(ntohl(sp[0].end_seq), tp->undo_marker))
                tp->undo_retrans--;
@@ -1058,6 +1058,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
                __u32 start_seq = ntohl(sp->start_seq);
                __u32 end_seq = ntohl(sp->end_seq);
                int fack_count;
+               int dup_sack = (found_dup_sack && (i == first_sack_index));
 
                skb = cached_skb;
                fack_count = cached_fack_count;
@@ -1397,7 +1398,9 @@ static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag)
                 * waiting for the first ACK and did not get it)...
                 */
                if ((tp->frto_counter == 1) && !(flag&FLAG_DATA_ACKED)) {
-                       tp->retrans_out += tcp_skb_pcount(skb);
+                       /* For some reason this R-bit might get cleared? */
+                       if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)
+                               tp->retrans_out += tcp_skb_pcount(skb);
                        /* ...enter this if branch just for the first segment */
                        flag |= FLAG_DATA_ACKED;
                } else {
@@ -2037,7 +2040,7 @@ static void tcp_try_to_open(struct sock *sk, int flag)
 {
        struct tcp_sock *tp = tcp_sk(sk);
 
-       tp->left_out = tp->sacked_out;
+       tcp_sync_left_out(tp);
 
        if (tp->retrans_out == 0)
                tp->retrans_stamp = 0;
@@ -2320,11 +2323,11 @@ static inline void tcp_ack_update_rtt(struct sock *sk, const int flag,
                tcp_ack_no_tstamp(sk, seq_rtt, flag);
 }
 
-static void tcp_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
+static void tcp_cong_avoid(struct sock *sk, u32 ack,
                           u32 in_flight, int good)
 {
        const struct inet_connection_sock *icsk = inet_csk(sk);
-       icsk->icsk_ca_ops->cong_avoid(sk, ack, rtt, in_flight, good);
+       icsk->icsk_ca_ops->cong_avoid(sk, ack, in_flight, good);
        tcp_sk(sk)->snd_cwnd_stamp = tcp_time_stamp;
 }
 
@@ -2409,7 +2412,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p)
        int acked = 0;
        int prior_packets = tp->packets_out;
        __s32 seq_rtt = -1;
-       ktime_t last_ackt = ktime_set(0,0);
+       ktime_t last_ackt = net_invalid_timestamp();
 
        while ((skb = tcp_write_queue_head(sk)) &&
               skb != tcp_send_head(sk)) {
@@ -2487,6 +2490,10 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p)
                tcp_ack_update_rtt(sk, acked, seq_rtt);
                tcp_ack_packets_out(sk);
 
+               /* Is the ACK triggering packet unambiguous? */
+               if (acked & FLAG_RETRANS_DATA_ACKED)
+                       last_ackt = net_invalid_timestamp();
+
                if (ca_ops->pkts_acked)
                        ca_ops->pkts_acked(sk, pkts_acked, last_ackt);
        }
@@ -2819,11 +2826,11 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
                /* Advance CWND, if state allows this. */
                if ((flag & FLAG_DATA_ACKED) && !frto_cwnd &&
                    tcp_may_raise_cwnd(sk, flag))
-                       tcp_cong_avoid(sk, ack,  seq_rtt, prior_in_flight, 0);
+                       tcp_cong_avoid(sk, ack, prior_in_flight, 0);
                tcp_fastretrans_alert(sk, prior_snd_una, prior_packets, flag);
        } else {
                if ((flag & FLAG_DATA_ACKED) && !frto_cwnd)
-                       tcp_cong_avoid(sk, ack, seq_rtt, prior_in_flight, 1);
+                       tcp_cong_avoid(sk, ack, prior_in_flight, 1);
        }
 
        if ((flag & FLAG_FORWARD_PROGRESS) || !(flag&FLAG_NOT_DUP))
@@ -2932,6 +2939,7 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx,
                                           opt_rx->sack_ok) {
                                                TCP_SKB_CB(skb)->sacked = (ptr - 2) - (unsigned char *)th;
                                        }
+                                       break;
 #ifdef CONFIG_TCP_MD5SIG
                                case TCPOPT_MD5SIG:
                                        /*