diff options
author | Lachlan Andrew <lachlan.andrew@gmail.com> | 2008-04-30 04:04:03 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-04-30 04:04:03 -0400 |
commit | 159131149c2f56c1da5ae5e23ab9d5acef4916d1 (patch) | |
tree | 7ad3fc498c27fd8dfdf4a1fcf506b1220919f715 /net/ipv4/tcp_vegas.c | |
parent | be9164e769d57aa10b2bbe15d103edc041b9e7de (diff) |
tcp: Overflow bug in Vegas
From: Lachlan Andrew <lachlan.andrew@gmail.com>
There is an overflow bug in net/ipv4/tcp_vegas.c for large BDPs
(e.g. 400Mbit/s, 400ms). The multiplication (old_wnd *
vegas->baseRTT) << V_PARAM_SHIFT overflows a u32.
[ Fix tcp_veno.c too, it has similar calculations. -DaveM ]
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_vegas.c')
-rw-r--r-- | net/ipv4/tcp_vegas.c | 10 |
1 files changed, 6 insertions, 4 deletions
diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c index be24d6ee34bd..0e1a8c91f78e 100644 --- a/net/ipv4/tcp_vegas.c +++ b/net/ipv4/tcp_vegas.c | |||
@@ -229,7 +229,8 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) | |||
229 | */ | 229 | */ |
230 | tcp_reno_cong_avoid(sk, ack, in_flight); | 230 | tcp_reno_cong_avoid(sk, ack, in_flight); |
231 | } else { | 231 | } else { |
232 | u32 rtt, target_cwnd, diff; | 232 | u32 rtt, diff; |
233 | u64 target_cwnd; | ||
233 | 234 | ||
234 | /* We have enough RTT samples, so, using the Vegas | 235 | /* We have enough RTT samples, so, using the Vegas |
235 | * algorithm, we determine if we should increase or | 236 | * algorithm, we determine if we should increase or |
@@ -252,8 +253,9 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) | |||
252 | * We keep it as a fixed point number with | 253 | * We keep it as a fixed point number with |
253 | * V_PARAM_SHIFT bits to the right of the binary point. | 254 | * V_PARAM_SHIFT bits to the right of the binary point. |
254 | */ | 255 | */ |
255 | target_cwnd = ((old_wnd * vegas->baseRTT) | 256 | target_cwnd = ((u64)old_wnd * vegas->baseRTT); |
256 | << V_PARAM_SHIFT) / rtt; | 257 | target_cwnd <<= V_PARAM_SHIFT; |
258 | do_div(target_cwnd, rtt); | ||
257 | 259 | ||
258 | /* Calculate the difference between the window we had, | 260 | /* Calculate the difference between the window we had, |
259 | * and the window we would like to have. This quantity | 261 | * and the window we would like to have. This quantity |
@@ -279,7 +281,7 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) | |||
279 | * utilization. | 281 | * utilization. |
280 | */ | 282 | */ |
281 | tp->snd_cwnd = min(tp->snd_cwnd, | 283 | tp->snd_cwnd = min(tp->snd_cwnd, |
282 | (target_cwnd >> | 284 | ((u32)target_cwnd >> |
283 | V_PARAM_SHIFT)+1); | 285 | V_PARAM_SHIFT)+1); |
284 | 286 | ||
285 | } else if (tp->snd_cwnd <= tp->snd_ssthresh) { | 287 | } else if (tp->snd_cwnd <= tp->snd_ssthresh) { |