aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/tcp_output.c')
-rw-r--r--net/ipv4/tcp_output.c25
1 files changed, 18 insertions, 7 deletions
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 990a58493235..e4c5ac9fe89b 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -362,6 +362,17 @@ struct tcp_out_options {
362 __u32 tsval, tsecr; /* need to include OPTION_TS */ 362 __u32 tsval, tsecr; /* need to include OPTION_TS */
363}; 363};
364 364
365/* Beware: Something in the Internet is very sensitive to the ordering of
366 * TCP options, we learned this through the hard way, so be careful here.
367 * Luckily we can at least blame others for their non-compliance but from
368 * inter-operatibility perspective it seems that we're somewhat stuck with
369 * the ordering which we have been using if we want to keep working with
370 * those broken things (not that it currently hurts anybody as there isn't
371 * particular reason why the ordering would need to be changed).
372 *
373 * At least SACK_PERM as the first option is known to lead to a disaster
374 * (but it may well be that other scenarios fail similarly).
375 */
365static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, 376static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
366 const struct tcp_out_options *opts, 377 const struct tcp_out_options *opts,
367 __u8 **md5_hash) { 378 __u8 **md5_hash) {
@@ -376,6 +387,12 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
376 *md5_hash = NULL; 387 *md5_hash = NULL;
377 } 388 }
378 389
390 if (unlikely(opts->mss)) {
391 *ptr++ = htonl((TCPOPT_MSS << 24) |
392 (TCPOLEN_MSS << 16) |
393 opts->mss);
394 }
395
379 if (likely(OPTION_TS & opts->options)) { 396 if (likely(OPTION_TS & opts->options)) {
380 if (unlikely(OPTION_SACK_ADVERTISE & opts->options)) { 397 if (unlikely(OPTION_SACK_ADVERTISE & opts->options)) {
381 *ptr++ = htonl((TCPOPT_SACK_PERM << 24) | 398 *ptr++ = htonl((TCPOPT_SACK_PERM << 24) |
@@ -392,12 +409,6 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
392 *ptr++ = htonl(opts->tsecr); 409 *ptr++ = htonl(opts->tsecr);
393 } 410 }
394 411
395 if (unlikely(opts->mss)) {
396 *ptr++ = htonl((TCPOPT_MSS << 24) |
397 (TCPOLEN_MSS << 16) |
398 opts->mss);
399 }
400
401 if (unlikely(OPTION_SACK_ADVERTISE & opts->options && 412 if (unlikely(OPTION_SACK_ADVERTISE & opts->options &&
402 !(OPTION_TS & opts->options))) { 413 !(OPTION_TS & opts->options))) {
403 *ptr++ = htonl((TCPOPT_NOP << 24) | 414 *ptr++ = htonl((TCPOPT_NOP << 24) |
@@ -432,7 +443,7 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
432 443
433 if (tp->rx_opt.dsack) { 444 if (tp->rx_opt.dsack) {
434 tp->rx_opt.dsack = 0; 445 tp->rx_opt.dsack = 0;
435 tp->rx_opt.eff_sacks--; 446 tp->rx_opt.eff_sacks = tp->rx_opt.num_sacks;
436 } 447 }
437 } 448 }
438} 449}