]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/ipv4/tcp_output.c
tcp: TCP connection times out if ICMP frag needed is delayed
[net-next-2.6.git] / net / ipv4 / tcp_output.c
index cbfef8b1f5e83c4153cb4e52286c7d0c007345a9..e399bde7813a9057bcd4b764120854aa558d5df7 100644 (file)
@@ -255,7 +255,7 @@ static u16 tcp_select_window(struct sock *sk)
                 *
                 * Relax Will Robinson.
                 */
-               new_win = cur_win;
+               new_win = ALIGN(cur_win, 1 << tp->rx_opt.rcv_wscale);
        }
        tp->rcv_wnd = new_win;
        tp->rcv_wup = tp->rcv_nxt;
@@ -998,7 +998,7 @@ unsigned int tcp_current_mss(struct sock *sk, int large_allowed)
        xmit_size_goal = mss_now;
 
        if (doing_tso) {
-               xmit_size_goal = (65535 -
+               xmit_size_goal = ((sk->sk_gso_max_size - 1) -
                                  inet_csk(sk)->icsk_af_ops->net_header_len -
                                  inet_csk(sk)->icsk_ext_hdr_len -
                                  tp->tcp_header_len);
@@ -1035,6 +1035,13 @@ static void tcp_cwnd_validate(struct sock *sk)
  * introducing MSS oddities to segment boundaries. In rare cases where
  * mss_now != mss_cache, we will request caller to create a small skb
  * per input skb which could be mostly avoided here (if desired).
+ *
+ * We explicitly want to create a request for splitting write queue tail
+ * to a small skb for Nagle purposes while avoiding unnecessary modulos,
+ * thus all the complexity (cwnd_len is always MSS multiple which we
+ * return whenever allowed by the other factors). Basically we need the
+ * modulo only when the receiver window alone is the limiting factor or
+ * when we would be allowed to send the split-due-to-Nagle skb fully.
  */
 static unsigned int tcp_mss_split_point(struct sock *sk, struct sk_buff *skb,
                                        unsigned int mss_now, unsigned int cwnd)
@@ -1048,10 +1055,11 @@ static unsigned int tcp_mss_split_point(struct sock *sk, struct sk_buff *skb,
        if (likely(cwnd_len <= window && skb != tcp_write_queue_tail(sk)))
                return cwnd_len;
 
-       if (skb == tcp_write_queue_tail(sk) && cwnd_len <= skb->len)
+       needed = min(skb->len, window);
+
+       if (cwnd_len <= needed)
                return cwnd_len;
 
-       needed = min(skb->len, window);
        return needed - needed % mss_now;
 }
 
@@ -1274,7 +1282,7 @@ static int tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb)
        limit = min(send_win, cong_win);
 
        /* If a full-sized TSO skb can be sent, do it. */
-       if (limit >= 65536)
+       if (limit >= sk->sk_gso_max_size)
                goto send_now;
 
        if (sysctl_tcp_tso_win_divisor) {
@@ -1800,6 +1808,9 @@ void tcp_simple_retransmit(struct sock *sk)
        if (!lost)
                return;
 
+       if (tcp_is_reno(tp))
+               tcp_limit_reno_sacked(tp);
+
        tcp_verify_left_out(tp);
 
        /* Don't muck with the congestion window here.
@@ -1825,7 +1836,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct inet_connection_sock *icsk = inet_csk(sk);
-       unsigned int cur_mss = tcp_current_mss(sk, 0);
+       unsigned int cur_mss;
        int err;
 
        /* Inconslusive MTU probe */
@@ -1847,6 +1858,11 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
                        return -ENOMEM;
        }
 
+       if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk))
+               return -EHOSTUNREACH; /* Routing failure or similar. */
+
+       cur_mss = tcp_current_mss(sk, 0);
+
        /* If receiver has shrunk his window, and skb is out of
         * new window, do not retransmit it. The exception is the
         * case, when window is shrunk to zero. In this case
@@ -1873,9 +1889,6 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
            (sysctl_tcp_retrans_collapse != 0))
                tcp_retrans_try_collapse(sk, skb, cur_mss);
 
-       if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk))
-               return -EHOSTUNREACH; /* Routing failure or similar. */
-
        /* Some Solaris stacks overoptimize and ignore the FIN on a
         * retransmit when old data is attached.  So strip it off
         * since it is cheap to do so and saves bytes on the network.
@@ -2225,7 +2238,11 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
 
        /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */
        th->window = htons(min(req->rcv_wnd, 65535U));
-
+#ifdef CONFIG_SYN_COOKIES
+       if (unlikely(req->cookie_ts))
+               TCP_SKB_CB(skb)->when = cookie_init_timestamp(req);
+       else
+#endif
        TCP_SKB_CB(skb)->when = tcp_time_stamp;
        tcp_syn_build_options((__be32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok,
                              ireq->sack_ok, ireq->wscale_ok, ireq->rcv_wscale,