diff options
| -rw-r--r-- | net/ipv4/tcp_output.c | 23 |
1 files changed, 17 insertions, 6 deletions
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index de54f02f10a9..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) | |
