aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_output.c
diff options
context:
space:
mode:
authorIlpo Järvinen <ilpo.jarvinen@helsinki.fi>2008-10-23 17:06:35 -0400
committerDavid S. Miller <davem@davemloft.net>2008-10-23 17:06:35 -0400
commitfd6149d332973bafa50f03ddb0ea9513e67f4517 (patch)
tree6f15537b56e2d565bbff797d5c96a98e5cda87ec /net/ipv4/tcp_output.c
parentb63365a2d60268a3988285d6c3c6003d7066f93a (diff)
tcp: Restore ordering of TCP options for the sake of inter-operability
This is not our bug! Sadly some devices cannot cope with the change of TCP option ordering which was a result of the recent rewrite of the option code (not that there was some particular reason steming from the rewrite for the reordering) though any ordering of TCP options is perfectly legal. Thus we restore the original ordering to allow interoperability with/through such broken devices and add some warning about this trap. Since the reordering just happened without any particular reason, this change shouldn't cost us anything. There are already couple of known failure reports (within close proximity of the last release), so the problem might be more wide-spread than a single device. And other reports which may be due to the same problem though the symptoms were less obvious. Analysis of one of the case revealed (with very high probability) that sack capability cannot be negotiated as the first option (SYN never got a response). Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> Reported-by: Aldo Maggi <sentiniate@tiscali.it> Tested-by: Aldo Maggi <sentiniate@tiscali.it> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_output.c')
-rw-r--r--net/ipv4/tcp_output.c23
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 */
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) |