tcp: combine timestamp and sack_permitted options when possible
any ordering is legal, but some devices don't cope with what we do. thus we reorder sack_permitted before timestamp, this doesn't cost us anything. noticed by Sikk: https://dev.haiku-os.org/ticket/13681#comment:11 Change-Id: Ic2e1589945dd74e3034a653427a2ff45626b3a76 Reviewed-on: https://review.haiku-os.org/c/haiku/+/4598 Tested-by: Commit checker robot <[email protected]> Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
eb1d596ff6
commit
f0a567c451
@@ -96,6 +96,9 @@ bump_option(tcp_option *&option, size_t &length)
|
|||||||
static inline size_t
|
static inline size_t
|
||||||
add_options(tcp_segment_header &segment, uint8 *buffer, size_t bufferSize)
|
add_options(tcp_segment_header &segment, uint8 *buffer, size_t bufferSize)
|
||||||
{
|
{
|
||||||
|
// Some network devices can be very sensitive to the ordering of TCP options
|
||||||
|
// https://github.com/torvalds/linux/blob/9e9fb7655ed585da8f468e29221f0ba194a5f613/net/ipv4/tcp_output.c#L598
|
||||||
|
|
||||||
tcp_option *option = (tcp_option *)buffer;
|
tcp_option *option = (tcp_option *)buffer;
|
||||||
size_t length = 0;
|
size_t length = 0;
|
||||||
|
|
||||||
@@ -108,21 +111,38 @@ add_options(tcp_segment_header &segment, uint8 *buffer, size_t bufferSize)
|
|||||||
|
|
||||||
if ((segment.options & TCP_HAS_TIMESTAMPS) != 0
|
if ((segment.options & TCP_HAS_TIMESTAMPS) != 0
|
||||||
&& length + 12 <= bufferSize) {
|
&& length + 12 <= bufferSize) {
|
||||||
// two NOPs so the timestamps get aligned to a 4 byte boundary
|
if ((segment.options & TCP_SACK_PERMITTED) != 0) {
|
||||||
option->kind = TCP_OPTION_NOP;
|
// combine with timestamp
|
||||||
bump_option(option, length);
|
option->kind = TCP_OPTION_SACK_PERMITTED;
|
||||||
option->kind = TCP_OPTION_NOP;
|
option->length = 2;
|
||||||
bump_option(option, length);
|
bump_option(option, length);
|
||||||
|
} else {
|
||||||
|
// two NOPs so the timestamps get aligned to a 4 byte boundary
|
||||||
|
option->kind = TCP_OPTION_NOP;
|
||||||
|
bump_option(option, length);
|
||||||
|
option->kind = TCP_OPTION_NOP;
|
||||||
|
bump_option(option, length);
|
||||||
|
}
|
||||||
option->kind = TCP_OPTION_TIMESTAMP;
|
option->kind = TCP_OPTION_TIMESTAMP;
|
||||||
option->length = 10;
|
option->length = 10;
|
||||||
option->timestamp.value = htonl(segment.timestamp_value);
|
option->timestamp.value = htonl(segment.timestamp_value);
|
||||||
option->timestamp.reply = htonl(segment.timestamp_reply);
|
option->timestamp.reply = htonl(segment.timestamp_reply);
|
||||||
bump_option(option, length);
|
bump_option(option, length);
|
||||||
|
} else if ((segment.options & TCP_SACK_PERMITTED) != 0
|
||||||
|
&& length + 4 <= bufferSize) {
|
||||||
|
// two NOPs so that the subsequent data is aligned on a 4 byte boundary
|
||||||
|
option->kind = TCP_OPTION_NOP;
|
||||||
|
bump_option(option, length);
|
||||||
|
option->kind = TCP_OPTION_NOP;
|
||||||
|
bump_option(option, length);
|
||||||
|
option->kind = TCP_OPTION_SACK_PERMITTED;
|
||||||
|
option->length = 2;
|
||||||
|
bump_option(option, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((segment.options & TCP_HAS_WINDOW_SCALE) != 0
|
if ((segment.options & TCP_HAS_WINDOW_SCALE) != 0
|
||||||
&& length + 4 <= bufferSize) {
|
&& length + 4 <= bufferSize) {
|
||||||
// insert one NOP so that the subsequent data is aligned on a 4 byte boundary
|
// one NOP so that the subsequent data is aligned on a 4 byte boundary
|
||||||
option->kind = TCP_OPTION_NOP;
|
option->kind = TCP_OPTION_NOP;
|
||||||
bump_option(option, length);
|
bump_option(option, length);
|
||||||
|
|
||||||
@@ -132,13 +152,6 @@ add_options(tcp_segment_header &segment, uint8 *buffer, size_t bufferSize)
|
|||||||
bump_option(option, length);
|
bump_option(option, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((segment.options & TCP_SACK_PERMITTED) != 0
|
|
||||||
&& length + 2 <= bufferSize) {
|
|
||||||
option->kind = TCP_OPTION_SACK_PERMITTED;
|
|
||||||
option->length = 2;
|
|
||||||
bump_option(option, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (segment.sackCount > 0) {
|
if (segment.sackCount > 0) {
|
||||||
int sackCount = ((int)(bufferSize - length) - 4) / sizeof(tcp_sack);
|
int sackCount = ((int)(bufferSize - length) - 4) / sizeof(tcp_sack);
|
||||||
if (sackCount > segment.sackCount)
|
if (sackCount > segment.sackCount)
|
||||||
@@ -435,14 +448,13 @@ tcp_options_length(tcp_segment_header& segment)
|
|||||||
if (segment.max_segment_size > 0)
|
if (segment.max_segment_size > 0)
|
||||||
length += 4;
|
length += 4;
|
||||||
|
|
||||||
if (segment.options & TCP_HAS_TIMESTAMPS)
|
if ((segment.options & TCP_HAS_TIMESTAMPS) != 0)
|
||||||
length += 12;
|
length += 12;
|
||||||
|
else if ((segment.options & TCP_SACK_PERMITTED) != 0)
|
||||||
if (segment.options & TCP_HAS_WINDOW_SCALE)
|
|
||||||
length += 4;
|
length += 4;
|
||||||
|
|
||||||
if (segment.options & TCP_SACK_PERMITTED)
|
if ((segment.options & TCP_HAS_WINDOW_SCALE) != 0)
|
||||||
length += 2;
|
length += 4;
|
||||||
|
|
||||||
if (segment.sackCount > 0) {
|
if (segment.sackCount > 0) {
|
||||||
int sackCount = min_c((int)((kMaxOptionSize - length - 4)
|
int sackCount = min_c((int)((kMaxOptionSize - length - 4)
|
||||||
|
|||||||
Reference in New Issue
Block a user