diff options
Diffstat (limited to 'net/ipv4/tcp_output.c')
-rw-r--r-- | net/ipv4/tcp_output.c | 25 |
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 | */ | ||
365 | static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, | 376 | static 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 | } |