diff -uprN linux-2.6.20-a/include/net/tcp.h linux-2.6.20-c/include/net/tcp.h --- linux-2.6.20-a/include/net/tcp.h 2007-02-04 19:44:54.000000000 +0100 +++ linux-2.6.20-c/include/net/tcp.h 2007-02-19 10:54:10.000000000 +0100 @@ -669,6 +669,7 @@ extern void tcp_get_allowed_congestion_c extern int tcp_set_allowed_congestion_control(char *allowed); extern int tcp_set_congestion_control(struct sock *sk, const char *name); extern void tcp_slow_start(struct tcp_sock *tp); +extern void tcp_limited_slow_start(struct tcp_sock *tp); extern struct tcp_congestion_ops tcp_init_congestion_ops; extern u32 tcp_reno_ssthresh(struct sock *sk); diff -uprN linux-2.6.20-a/net/ipv4/tcp_cong.c linux-2.6.20-c/net/ipv4/tcp_cong.c --- linux-2.6.20-a/net/ipv4/tcp_cong.c 2007-02-04 19:44:54.000000000 +0100 +++ linux-2.6.20-c/net/ipv4/tcp_cong.c 2007-02-19 10:54:10.000000000 +0100 @@ -297,6 +297,29 @@ void tcp_slow_start(struct tcp_sock *tp) } EXPORT_SYMBOL_GPL(tcp_slow_start); +void tcp_limited_slow_start(struct tcp_sock *tp) +{ + /* RFC3742: limited slow start + * the window is increased by 1/K MSS for each arriving ACK, + * for K = int(cwnd/(0.5 max_ssthresh)) + */ + + const int max_ssthresh = 100; + + if (max_ssthresh > 0 && tp->snd_cwnd > max_ssthresh) { + u32 k = max(tp->snd_cwnd / (max_ssthresh >> 1), 1U); + if (++tp->snd_cwnd_cnt >= k) { + if (tp->snd_cwnd < tp->snd_cwnd_clamp) + tp->snd_cwnd++; + tp->snd_cwnd_cnt = 0; + } + } else { + if (tp->snd_cwnd < tp->snd_cwnd_clamp) + tp->snd_cwnd++; + } +} +EXPORT_SYMBOL_GPL(tcp_limited_slow_start); + /* * TCP Reno congestion control * This is special case used for fallback as well.