[haiku-commits] haiku: hrev51385 - src/add-ons/kernel/network/protocols/tcp

  • From: jessica.l.hamilton@xxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sun, 27 Aug 2017 23:05:42 +0200 (CEST)

hrev51385 adds 8 changesets to branch 'master'
old head: e9300454b6a8a7e33b018bc760daed8ac1e1dda5
new head: 5c31f5a67a0aa37c8f2a1464252b2c5b0a959f33
overview: 
http://cgit.haiku-os.org/haiku/log/?qt=range&q=5c31f5a67a0a+%5Ee9300454b6a8

----------------------------------------------------------------------------

05743f6a1331: tcp: slow start@rfc5681 : updated rules for congestion window
  
  Signed-off-by: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>

ec63a32913ad: tcp: rfc 5681: implemented fast retransmit and recovery
  
  Signed-off-by: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>

39bba929ac3f: tcp: rfc 3042: implemented limited transmit
  
  Signed-off-by: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>

aaa7cebc24f0: tcp: rfc 7323: added PAWS timestamp check on Receive
  
  Signed-off-by: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>

30982ed7b94d: tcp: rfc 6298 & 7323: updated rto calculations and semantics
  
  Signed-off-by: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>

15c58f0cb7a0: tcp: rfc 5681: implemented ideal timer
  
  Signed-off-by: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>

515cda7241ba: tcp: rfc 6582: implemented NewReno modification
  
  Signed-off-by: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>

5c31f5a67a0a: tcp: rfc 2018: implemented SACK option
  
  Signed-off-by: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>

                                  [ A-star-ayush <myselfthebest@xxxxxxxxx> ]

----------------------------------------------------------------------------

6 files changed, 283 insertions(+), 80 deletions(-)
.../kernel/network/protocols/tcp/BufferQueue.cpp |  35 +++
.../kernel/network/protocols/tcp/BufferQueue.h   |   1 +
.../kernel/network/protocols/tcp/TCPEndpoint.cpp | 281 ++++++++++++++-----
.../kernel/network/protocols/tcp/TCPEndpoint.h   |  11 +-
src/add-ons/kernel/network/protocols/tcp/tcp.cpp |  28 +-
src/add-ons/kernel/network/protocols/tcp/tcp.h   |   7 +-

############################################################################

Commit:      05743f6a13319a9dc332603eb5d98ba4c5374b25
URL:         http://cgit.haiku-os.org/haiku/commit/?id=05743f6a1331
Author:      A-star-ayush <myselfthebest@xxxxxxxxx>
Date:        Mon Aug 14 19:41:58 2017 UTC
Committer:   Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>
Commit-Date: Mon Aug 28 08:52:19 2017 UTC

tcp: slow start@rfc5681 : updated rules for congestion window

Signed-off-by: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp 
b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
index eb8ed47..1cbe262 100644
--- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
+++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
@@ -18,6 +18,7 @@
 #include <signal.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdint.h>
 
 #include <KernelExport.h>
 #include <Select.h>
@@ -427,6 +428,7 @@ TCPEndpoint::TCPEndpoint(net_socket* socket)
        fSendWindow(0),
        fSendMaxWindow(0),
        fSendMaxSegmentSize(TCP_DEFAULT_MAX_SEGMENT_SIZE),
+       fSendMaxSegments(0),
        fSendQueue(socket->send.buffer_size),
        fInitialSendSequence(0),
        fDuplicateAcknowledgeCount(0),
@@ -1392,7 +1394,14 @@ TCPEndpoint::_PrepareReceivePath(tcp_segment_header& 
segment)
                        fFlags &= ~FLAG_OPTION_TIMESTAMP;
        }
 
-       fCongestionWindow = 2 * fSendMaxSegmentSize;
+       if (fSendMaxSegmentSize > 2190)
+               fCongestionWindow = 2 * fSendMaxSegmentSize;
+       else if (fSendMaxSegmentSize > 1095)
+               fCongestionWindow = 3 * fSendMaxSegmentSize;
+       else
+               fCongestionWindow = 4 * fSendMaxSegmentSize;
+
+       fSendMaxSegments = fCongestionWindow / fSendMaxSegmentSize;
        fSlowStartThreshold = (uint32)segment.advertised_window << 
fSendWindowShift;
 }
 
@@ -1897,6 +1906,9 @@ inline bool
 TCPEndpoint::_ShouldSendSegment(tcp_segment_header& segment, uint32 length,
        uint32 segmentMaxSize, uint32 flightSize)
 {
+       if (fState == ESTABLISHED && fSendMaxSegments == 0)
+               return false;
+
        if (length > 0) {
                // Avoid the silly window syndrome - we only send a segment in 
case:
                // - we have a full segment to send, or
@@ -2114,6 +2126,9 @@ TCPEndpoint::_SendQueued(bool force, uint32 sendWindow)
                fReceiveMaxAdvertised = fReceiveNext
                        + ((uint32)segment.advertised_window << 
fReceiveWindowShift);
 
+               if (segmentLength != 0 && fState == ESTABLISHED)
+                       --fSendMaxSegments;
+
                status = next->module->send_routed_data(next, fRoute, buffer);
                if (status < B_OK) {
                        gBufferModule->free(buffer);
@@ -2207,6 +2222,26 @@ TCPEndpoint::_Acknowledged(tcp_segment_header& segment)
 
        if (fSendUnacknowledged < segment.acknowledge) {
                fSendQueue.RemoveUntil(segment.acknowledge);
+
+               // the acknowledgment of the SYN/ACK MUST NOT increase the size 
of the congestion window
+               if (fSendUnacknowledged != fInitialSendSequence) {
+                       if (fCongestionWindow < fSlowStartThreshold)
+                               fCongestionWindow += min_c(segment.acknowledge 
- fSendUnacknowledged.Number(),
+                                       fSendMaxSegmentSize);
+                       else {
+                               uint32 increment = fSendMaxSegmentSize * 
fSendMaxSegmentSize;
+
+                               if (increment < fCongestionWindow)
+                                       increment = 1;
+                               else
+                                       increment /= fCongestionWindow;
+
+                               fCongestionWindow += increment;
+                       }
+
+                       fSendMaxSegments = UINT32_MAX;
+               }
+
                fSendUnacknowledged = segment.acknowledge;
                if (fSendNext < fSendUnacknowledged)
                        fSendNext = fSendUnacknowledged;
@@ -2236,20 +2271,6 @@ TCPEndpoint::_Acknowledged(tcp_segment_header& segment)
                        fSendCondition.NotifyAll();
                        gSocketModule->notify(socket, B_SELECT_WRITE, 
fSendQueue.Free());
                }
-
-               if (fCongestionWindow < fSlowStartThreshold)
-                       fCongestionWindow += fSendMaxSegmentSize;
-       }
-
-       if (fCongestionWindow >= fSlowStartThreshold) {
-               uint32 increment = fSendMaxSegmentSize * fSendMaxSegmentSize;
-
-               if (increment < fCongestionWindow)
-                       increment = 1;
-               else
-                       increment /= fCongestionWindow;
-
-               fCongestionWindow += increment;
        }
 
        // if there is data left to be sent, send it now
@@ -2261,16 +2282,21 @@ TCPEndpoint::_Acknowledged(tcp_segment_header& segment)
 void
 TCPEndpoint::_Retransmit()
 {
-       TRACE("Retransmit()");
+       if (fState < ESTABLISHED) {
+               fRetransmitTimeout = TCP_SYN_RETRANSMIT_TIMEOUT;
+               fCongestionWindow = fSendMaxSegmentSize;
+       } else {
+               _ResetSlowStart();
 
-       _ResetSlowStart();
-       fSendNext = fSendUnacknowledged;
+               // Do exponential back off of the retransmit timeout
+               fRetransmitTimeout *= 2;
+               if (fRetransmitTimeout > TCP_MAX_RETRANSMIT_TIMEOUT)
+                       fRetransmitTimeout = TCP_MAX_RETRANSMIT_TIMEOUT;
+       }
 
-       // Do exponential back off of the retransmit timeout
-       fRetransmitTimeout *= 2;
-       if (fRetransmitTimeout > TCP_MAX_RETRANSMIT_TIMEOUT)
-               fRetransmitTimeout = TCP_MAX_RETRANSMIT_TIMEOUT;
+       TRACE("Retransmit()");
 
+       fSendNext = fSendUnacknowledged;
        _SendQueued();
 }
 
diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h 
b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h
index 1ff167b..f0bd4e4 100644
--- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h
+++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h
@@ -145,6 +145,7 @@ private:
        uint32                  fSendWindow;
        uint32                  fSendMaxWindow;
        uint32                  fSendMaxSegmentSize;
+       uint32                  fSendMaxSegments;
        BufferQueue             fSendQueue;
        tcp_sequence    fLastAcknowledgeSent;
        tcp_sequence    fInitialSendSequence;
diff --git a/src/add-ons/kernel/network/protocols/tcp/tcp.h 
b/src/add-ons/kernel/network/protocols/tcp/tcp.h
index 6f30ec2..24890a3 100644
--- a/src/add-ons/kernel/network/protocols/tcp/tcp.h
+++ b/src/add-ons/kernel/network/protocols/tcp/tcp.h
@@ -193,6 +193,8 @@ operator==(tcp_sequence a, tcp_sequence b)
 #define TCP_MIN_RETRANSMIT_TIMEOUT             200000          // 200 msecs
 // Maximum retransmit timeout (per RFC6298)
 #define TCP_MAX_RETRANSMIT_TIMEOUT             60000000        // 60 secs
+// New value for timeout in case of lost SYN (RFC 6298)
+#define TCP_SYN_RETRANSMIT_TIMEOUT             3000000         // 3 secs
 
 struct tcp_sack {
        uint32 left_edge;

############################################################################

Commit:      ec63a32913addc83f55cb293a4a1a308adfc73cc
URL:         http://cgit.haiku-os.org/haiku/commit/?id=ec63a32913ad
Author:      A-star-ayush <myselfthebest@xxxxxxxxx>
Date:        Mon Aug 14 19:46:31 2017 UTC
Committer:   Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>
Commit-Date: Mon Aug 28 08:52:19 2017 UTC

tcp: rfc 5681: implemented fast retransmit and recovery

Signed-off-by: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp 
b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
index 1cbe262..4ddec8f 100644
--- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
+++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
@@ -432,6 +432,7 @@ TCPEndpoint::TCPEndpoint(net_socket* socket)
        fSendQueue(socket->send.buffer_size),
        fInitialSendSequence(0),
        fDuplicateAcknowledgeCount(0),
+       fPreviousFlightSize(0),
        fRoute(NULL),
        fReceiveNext(0),
        fReceiveMaxAdvertised(0),
@@ -1277,17 +1278,28 @@ TCPEndpoint::_HandleReset(status_t error)
 void
 TCPEndpoint::_DuplicateAcknowledge(tcp_segment_header &segment)
 {
+       if (fDuplicateAcknowledgeCount == 0)
+               fPreviousFlightSize = (fSendMax - fSendUnacknowledged).Number();
+
        if (++fDuplicateAcknowledgeCount < 3)
                return;
 
        if (fDuplicateAcknowledgeCount == 3) {
-               _ResetSlowStart();
+               fSlowStartThreshold = max_c(fPreviousFlightSize / 2, 2 * 
fSendMaxSegmentSize);
                fCongestionWindow = fSlowStartThreshold + 3 * 
fSendMaxSegmentSize;
                fSendNext = segment.acknowledge;
-       } else if (fDuplicateAcknowledgeCount > 3)
-               fCongestionWindow += fSendMaxSegmentSize;
-
-       _SendQueued();
+               _SendQueued();
+               TRACE("_DuplicateAcknowledge(): packet sent under fast 
restransmit on the receipt of 3rd dup ack");
+
+       } else if (fDuplicateAcknowledgeCount > 3) {
+               uint32 flightSize = (fSendMax - fSendUnacknowledged).Number();
+               if ((fDuplicateAcknowledgeCount - 3) * fSendMaxSegmentSize <= 
flightSize)
+                       fCongestionWindow += fSendMaxSegmentSize;
+               if (fSendQueue.Available(fSendMax) != 0) {
+                       fSendNext = fSendMax;
+                       _SendQueued();
+               }
+       }
 }
 
 
@@ -1641,6 +1653,10 @@ TCPEndpoint::_Receive(tcp_segment_header& segment, 
net_buffer* buffer)
 
        int32 action = KEEP;
 
+       // immediately acknowledge out-of-order segment to trigger 
fast-retransmit at the sender
+       if (drop != 0)
+               action |= IMMEDIATE_ACKNOWLEDGE;
+
        drop = (int32)(segment.sequence + buffer->size
                - (fReceiveNext + fReceiveWindow)).Number();
        if (drop > 0) {
@@ -1685,14 +1701,13 @@ TCPEndpoint::_Receive(tcp_segment_header& segment, 
net_buffer* buffer)
                if (fSendMax < segment.acknowledge)
                        return DROP | IMMEDIATE_ACKNOWLEDGE;
 
-               if (segment.acknowledge < fSendUnacknowledged) {
+               if (segment.acknowledge == fSendUnacknowledged) {
                        if (buffer->size == 0 && advertisedWindow == fSendWindow
-                               && (segment.flags & TCP_FLAG_FINISH) == 0) {
+                               && (segment.flags & TCP_FLAG_FINISH) == 0 && 
fSendUnacknowledged != fSendMax) {
                                TRACE("Receive(): duplicate ack!");
-
                                _DuplicateAcknowledge(segment);
                        }
-
+               } else if (segment.acknowledge < fSendUnacknowledged) {
                        return DROP;
                } else {
                        // this segment acknowledges in flight data
@@ -1702,8 +1717,6 @@ TCPEndpoint::_Receive(tcp_segment_header& segment, 
net_buffer* buffer)
                                fCongestionWindow = fSlowStartThreshold;
                        }
 
-                       fDuplicateAcknowledgeCount = 0;
-
                        if (fSendMax == segment.acknowledge)
                                TRACE("Receive(): all inflight data ack'd!");
 
@@ -2044,6 +2057,11 @@ TCPEndpoint::_SendQueued(bool force, uint32 sendWindow)
        bool shouldStartRetransmitTimer = fSendNext == fSendUnacknowledged;
        bool retransmit = fSendNext < fSendMax;
 
+       if (fDuplicateAcknowledgeCount != 0) {
+               // send at most 1 SMSS of data when under limited transmit, 
fast transmit/recovery
+               length = min_c(length, fSendMaxSegmentSize);
+       }
+
        do {
                uint32 segmentMaxSize = fSendMaxSegmentSize
                        - tcp_options_length(segment);
@@ -2221,6 +2239,7 @@ TCPEndpoint::_Acknowledged(tcp_segment_header& segment)
        ASSERT(fSendUnacknowledged <= segment.acknowledge);
 
        if (fSendUnacknowledged < segment.acknowledge) {
+               fDuplicateAcknowledgeCount = 0;
                fSendQueue.RemoveUntil(segment.acknowledge);
 
                // the acknowledgment of the SYN/ACK MUST NOT increase the size 
of the congestion window
@@ -2287,7 +2306,7 @@ TCPEndpoint::_Retransmit()
                fCongestionWindow = fSendMaxSegmentSize;
        } else {
                _ResetSlowStart();
-
+               fDuplicateAcknowledgeCount = 0;
                // Do exponential back off of the retransmit timeout
                fRetransmitTimeout *= 2;
                if (fRetransmitTimeout > TCP_MAX_RETRANSMIT_TIMEOUT)
diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h 
b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h
index f0bd4e4..fd59c46 100644
--- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h
+++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h
@@ -150,6 +150,7 @@ private:
        tcp_sequence    fLastAcknowledgeSent;
        tcp_sequence    fInitialSendSequence;
        uint32                  fDuplicateAcknowledgeCount;
+       uint32                  fPreviousFlightSize;
 
        net_route               *fRoute;
                // TODO: don't use a net_route, but a net_route_info!!!

############################################################################

Commit:      39bba929ac3ff2fa697f1d260eb5686522539d6f
URL:         http://cgit.haiku-os.org/haiku/commit/?id=39bba929ac3f
Author:      A-star-ayush <myselfthebest@xxxxxxxxx>
Date:        Mon Aug 14 19:55:04 2017 UTC
Committer:   Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>
Commit-Date: Mon Aug 28 08:52:19 2017 UTC

tcp: rfc 3042: implemented limited transmit

Signed-off-by: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp 
b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
index 4ddec8f..1cbe610 100644
--- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
+++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
@@ -1281,8 +1281,15 @@ TCPEndpoint::_DuplicateAcknowledge(tcp_segment_header 
&segment)
        if (fDuplicateAcknowledgeCount == 0)
                fPreviousFlightSize = (fSendMax - fSendUnacknowledged).Number();
 
-       if (++fDuplicateAcknowledgeCount < 3)
-               return;
+       if (++fDuplicateAcknowledgeCount < 3) {
+               if (fSendQueue.Available(fSendMax) != 0  && fSendWindow != 0) {
+                       fSendNext = fSendMax;
+                       fCongestionWindow += fDuplicateAcknowledgeCount * 
fSendMaxSegmentSize;
+                       _SendQueued();
+                       TRACE("_DuplicateAcknowledge(): packet sent under 
limited transmit on receipt of dup ack");
+                       fCongestionWindow -= fDuplicateAcknowledgeCount * 
fSendMaxSegmentSize;
+               }
+       }
 
        if (fDuplicateAcknowledgeCount == 3) {
                fSlowStartThreshold = max_c(fPreviousFlightSize / 2, 2 * 
fSendMaxSegmentSize);

############################################################################

Commit:      aaa7cebc24f067fe26d3ba9ae805158f8c5b75b1
URL:         http://cgit.haiku-os.org/haiku/commit/?id=aaa7cebc24f0
Author:      A-star-ayush <myselfthebest@xxxxxxxxx>
Date:        Thu Aug 17 06:59:56 2017 UTC
Committer:   Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>
Commit-Date: Mon Aug 28 08:52:19 2017 UTC

tcp: rfc 7323: added PAWS timestamp check on Receive

Signed-off-by: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp 
b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
index 1cbe610..ec98efa 100644
--- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
+++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
@@ -1551,6 +1551,15 @@ TCPEndpoint::_SynchronizeSentReceive(tcp_segment_header 
&segment,
 int32
 TCPEndpoint::_Receive(tcp_segment_header& segment, net_buffer* buffer)
 {
+       // PAWS processing takes precedence over regular TCP acceptability check
+       if ((fFlags & FLAG_OPTION_TIMESTAMP) != 0 && (segment.flags & 
TCP_FLAG_RESET) == 0) {
+               if ((segment.options & TCP_HAS_TIMESTAMPS) == 0)
+                       return DROP;
+               if ((int32)(fReceivedTimestamp - segment.timestamp_value) > 0
+                       && (fReceivedTimestamp - segment.timestamp_value) <= 
INT32_MAX)
+                       return DROP | IMMEDIATE_ACKNOWLEDGE;
+       }
+
        uint32 advertisedWindow = (uint32)segment.advertised_window
                << fSendWindowShift;
        size_t segmentLength = buffer->size;
diff --git a/src/add-ons/kernel/network/protocols/tcp/tcp.cpp 
b/src/add-ons/kernel/network/protocols/tcp/tcp.cpp
index 7c1dbb4..b14f662 100644
--- a/src/add-ons/kernel/network/protocols/tcp/tcp.cpp
+++ b/src/add-ons/kernel/network/protocols/tcp/tcp.cpp
@@ -117,8 +117,7 @@ add_options(tcp_segment_header &segment, uint8 *buffer, 
size_t bufferSize)
                option->kind = TCP_OPTION_TIMESTAMP;
                option->length = 10;
                option->timestamp.value = htonl(segment.timestamp_value);
-               // TSecr is opaque to us, we send it as we received it.
-               option->timestamp.reply = segment.timestamp_reply;
+               option->timestamp.reply = htonl(segment.timestamp_reply);
                bump_option(option, length);
        }
 
@@ -210,7 +209,7 @@ process_options(tcp_segment_header &segment, net_buffer 
*buffer, size_t size)
                        case TCP_OPTION_TIMESTAMP:
                                if (option->length == 10 && size >= 10) {
                                        segment.options |= TCP_HAS_TIMESTAMPS;
-                                       segment.timestamp_value = 
option->timestamp.value;
+                                       segment.timestamp_value = 
ntohl(option->timestamp.value);
                                        segment.timestamp_reply =
                                                ntohl(option->timestamp.reply);
                                }

############################################################################

Commit:      30982ed7b94d61be02c704fe12a8519f18741db2
URL:         http://cgit.haiku-os.org/haiku/commit/?id=30982ed7b94d
Author:      A-star-ayush <myselfthebest@xxxxxxxxx>
Date:        Sat Jul 29 16:49:47 2017 UTC
Committer:   Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>
Commit-Date: Mon Aug 28 08:52:19 2017 UTC

tcp: rfc 6298 & 7323: updated rto calculations and semantics

Signed-off-by: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp 
b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
index ec98efa..11b512d 100644
--- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
+++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
@@ -439,8 +439,9 @@ TCPEndpoint::TCPEndpoint(net_socket* socket)
        fReceiveWindow(socket->receive.buffer_size),
        fReceiveMaxSegmentSize(TCP_DEFAULT_MAX_SEGMENT_SIZE),
        fReceiveQueue(socket->receive.buffer_size),
-       fRoundTripTime(TCP_INITIAL_RTT / kTimestampFactor),
-       fRoundTripDeviation(TCP_INITIAL_RTT / kTimestampFactor),
+       fSmoothedRoundTripTime(0),
+       fRoundTripVariation(0),
+       fSendTime(0),
        fRetransmitTimeout(TCP_INITIAL_RTT),
        fReceivedTimestamp(0),
        fCongestionWindow(0),
@@ -2173,6 +2174,9 @@ TCPEndpoint::_SendQueued(bool force, uint32 sendWindow)
                        return status;
                }
 
+               if (fSendTime == 0 && (segmentLength != 0 || (segment.flags & 
TCP_FLAG_SYNCHRONIZE ) == 1))
+                       fSendTime = tcp_now();
+
                if (shouldStartRetransmitTimer && size > 0) {
                        TRACE("starting initial retransmit timer of: %" 
B_PRIdBIGTIME,
                                fRetransmitTimeout);
@@ -2281,19 +2285,23 @@ TCPEndpoint::_Acknowledged(tcp_segment_header& segment)
                if (fSendNext < fSendUnacknowledged)
                        fSendNext = fSendUnacknowledged;
 
-               if (segment.options & TCP_HAS_TIMESTAMPS)
-                       
_UpdateRoundTripTime(tcp_diff_timestamp(segment.timestamp_reply));
-               else {
-                       // TODO: Fallback to RFC 793 type estimation; This just 
resets
-                       // any potential exponential back off that happened due 
to
-                       // retransmits.
-                       fRetransmitTimeout = TCP_INITIAL_RTT;
+               if (fFlags & FLAG_OPTION_TIMESTAMP) {
+                       uint32 flightSize = (fSendMax - 
fSendUnacknowledged).Number();
+                       
_UpdateRoundTripTime(tcp_diff_timestamp(segment.timestamp_reply),
+                               1 + ((flightSize - 1) / (fSendMaxSegmentSize << 
1)));
+               }
+
+               // Karn's algorithm: RTT measurement must not be made using 
segments that were retransmitted
+               else if (fSendTime > 1 && fSendNext == fSendMax) {
+                       _UpdateRoundTripTime(tcp_diff_timestamp(fSendTime), 1);
+                       fSendTime = 1;
                }
 
                if (fSendUnacknowledged == fSendMax) {
                        TRACE("all acknowledged, cancelling retransmission 
timer");
                        gStackModule->cancel_timer(&fRetransmitTimer);
                        T(TimerSet(this, "retransmit", -1));
+                       fSendTime = 0;
                } else {
                        TRACE("data acknowledged, resetting retransmission 
timer to: %"
                                B_PRIdBIGTIME, fRetransmitTimeout);
@@ -2337,20 +2345,23 @@ TCPEndpoint::_Retransmit()
 
 
 void
-TCPEndpoint::_UpdateRoundTripTime(int32 roundTripTime)
+TCPEndpoint::_UpdateRoundTripTime(int32 roundTripTime, uint32 expectedSamples)
 {
-       int32 rtt = roundTripTime;
-
-       // "smooth" round trip time as per Van Jacobson
-       rtt -= fRoundTripTime / 8;
-       fRoundTripTime += rtt;
-       if (rtt < 0)
-               rtt = -rtt;
-       rtt -= fRoundTripDeviation / 4;
-       fRoundTripDeviation += rtt;
+       if(fSmoothedRoundTripTime == 0) {
+               fSmoothedRoundTripTime = roundTripTime;
+               fRoundTripVariation = roundTripTime >> 1;
+               fRetransmitTimeout = (fSmoothedRoundTripTime + max_c(100, 
fRoundTripVariation << 2))
+                               * kTimestampFactor;
+       } else {
+               int32 delta = fSmoothedRoundTripTime - roundTripTime;
+               if (delta < 0)
+                       delta = -delta;
+               fRoundTripVariation += ((delta - fRoundTripVariation) >> 2) / 
expectedSamples;
+               fSmoothedRoundTripTime += ((roundTripTime - 
fSmoothedRoundTripTime) >> 3) / expectedSamples;
+               fRetransmitTimeout = (fSmoothedRoundTripTime + max_c(100, 
fRoundTripVariation << 2))
+                       * kTimestampFactor;
+       }
 
-       fRetransmitTimeout = ((fRoundTripTime / 4 + fRoundTripDeviation) / 2)
-               * kTimestampFactor;
        if (fRetransmitTimeout < TCP_MIN_RETRANSMIT_TIMEOUT)
                fRetransmitTimeout = TCP_MIN_RETRANSMIT_TIMEOUT;
 
@@ -2378,7 +2389,7 @@ TCPEndpoint::_RetransmitTimer(net_timer* timer, void* 
_endpoint)
        T(TimerTriggered(endpoint, "retransmit"));
 
        MutexLocker locker(endpoint->fLock);
-       if (!locker.IsLocked())
+       if (!locker.IsLocked() || gStackModule->is_timer_active(timer))
                return;
 
        endpoint->_Retransmit();
@@ -2506,8 +2517,8 @@ TCPEndpoint::Dump() const
                fInitialReceiveSequence.Number());
        kprintf("    duplicate acknowledge count: %" B_PRIu32 "\n",
                fDuplicateAcknowledgeCount);
-       kprintf("  round trip time: %" B_PRId32 " (deviation %" B_PRId32 ")\n",
-               fRoundTripTime, fRoundTripDeviation);
+       kprintf("  smoothed round trip time: %" B_PRId32 " (deviation %" 
B_PRId32 ")\n",
+               fSmoothedRoundTripTime, fRoundTripVariation);
        kprintf("  retransmit timeout: %" B_PRId64 "\n", fRetransmitTimeout);
        kprintf("  congestion window: %" B_PRIu32 "\n", fCongestionWindow);
        kprintf("  slow start threshold: %" B_PRIu32 "\n", fSlowStartThreshold);
diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h 
b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h
index fd59c46..ff6739e 100644
--- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h
+++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h
@@ -106,7 +106,7 @@ private:
                        status_t        _PrepareSendPath(const sockaddr* peer);
                        void            _Acknowledged(tcp_segment_header& 
segment);
                        void            _Retransmit();
-                       void            _UpdateRoundTripTime(int32 
roundTripTime);
+                       void            _UpdateRoundTripTime(int32 
roundTripTime, uint32 expectedSamples);
                        void            _ResetSlowStart();
                        void            
_DuplicateAcknowledge(tcp_segment_header& segment);
 
@@ -166,8 +166,9 @@ private:
        tcp_sequence    fInitialReceiveSequence;
 
        // round trip time and retransmit timeout computation
-       int32                   fRoundTripTime;
-       int32                   fRoundTripDeviation;
+       int32                   fSmoothedRoundTripTime;
+       int32                   fRoundTripVariation;
+       uint32                  fSendTime;
        bigtime_t               fRetransmitTimeout;
 
        uint32                  fReceivedTimestamp;

############################################################################

Commit:      15c58f0cb7a0afb7361945e4596f83f7b6212cf8
URL:         http://cgit.haiku-os.org/haiku/commit/?id=15c58f0cb7a0
Author:      A-star-ayush <myselfthebest@xxxxxxxxx>
Date:        Sat Jul 29 16:55:11 2017 UTC
Committer:   Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>
Commit-Date: Mon Aug 28 08:52:19 2017 UTC

tcp: rfc 5681: implemented ideal timer

Signed-off-by: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp 
b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
index 11b512d..daba44e 100644
--- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
+++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
@@ -1379,6 +1379,13 @@ TCPEndpoint::_AddData(tcp_segment_header& segment, 
net_buffer* buffer)
        if ((segment.flags & TCP_FLAG_PUSH) != 0)
                fReceiveQueue.SetPushPointer();
 
+       if (fSendUnacknowledged == fSendMax) {
+               TRACE("data received, resetting ideal timer to: %"
+                               B_PRIdBIGTIME, fRetransmitTimeout);
+               gStackModule->set_timer(&fRetransmitTimer, fRetransmitTimeout);
+               T(TimerSet(this, "ideal", fRetransmitTimeout));
+       }
+
        return fReceiveQueue.Available() > 0;
 }
 
@@ -2298,9 +2305,10 @@ TCPEndpoint::_Acknowledged(tcp_segment_header& segment)
                }
 
                if (fSendUnacknowledged == fSendMax) {
-                       TRACE("all acknowledged, cancelling retransmission 
timer");
-                       gStackModule->cancel_timer(&fRetransmitTimer);
-                       T(TimerSet(this, "retransmit", -1));
+                       TRACE("all acknowledged, cancelling retransmission 
timer. Using it as ideal timer for: %"
+                               B_PRIdBIGTIME, fRetransmitTimeout);
+                       gStackModule->set_timer(&fRetransmitTimer, 
fRetransmitTimeout);
+                       T(TimerSet(this, "ideal", fRetransmitTimeout));
                        fSendTime = 0;
                } else {
                        TRACE("data acknowledged, resetting retransmission 
timer to: %"
@@ -2328,6 +2336,21 @@ TCPEndpoint::_Retransmit()
        if (fState < ESTABLISHED) {
                fRetransmitTimeout = TCP_SYN_RETRANSMIT_TIMEOUT;
                fCongestionWindow = fSendMaxSegmentSize;
+       } else if (fSendUnacknowledged == fSendMax) {
+               TRACE("Ideal timeout");
+               // idle period time out - did not receive any segment for a 
time equal
+               // to the retransmission timeout
+
+               uint32 initialWindow;
+               if (fSendMaxSegmentSize > 2190)
+                       initialWindow = 2 * fSendMaxSegmentSize;
+               else if (fSendMaxSegmentSize > 1095)
+                       initialWindow = 3 * fSendMaxSegmentSize;
+               else
+                       initialWindow = 4 * fSendMaxSegmentSize;
+
+               fCongestionWindow = min_c(initialWindow, fCongestionWindow);
+               return;
        } else {
                _ResetSlowStart();
                fDuplicateAcknowledgeCount = 0;

############################################################################

Commit:      515cda7241baf3b40d6e3f340f73958a2d40b2d0
URL:         http://cgit.haiku-os.org/haiku/commit/?id=515cda7241ba
Author:      A-star-ayush <myselfthebest@xxxxxxxxx>
Date:        Fri Aug 18 20:45:51 2017 UTC
Committer:   Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>
Commit-Date: Mon Aug 28 08:52:19 2017 UTC

tcp: rfc 6582: implemented NewReno modification

Signed-off-by: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp 
b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
index daba44e..91b4b91 100644
--- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
+++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
@@ -318,7 +318,8 @@ enum {
        FLAG_NO_RECEIVE                         = 0x04,
        FLAG_CLOSED                                     = 0x08,
        FLAG_DELETE_ON_CLOSE            = 0x10,
-       FLAG_LOCAL                                      = 0x20
+       FLAG_LOCAL                                      = 0x20,
+       FLAG_RECOVERY                           = 0x40
 };
 
 
@@ -431,8 +432,10 @@ TCPEndpoint::TCPEndpoint(net_socket* socket)
        fSendMaxSegments(0),
        fSendQueue(socket->send.buffer_size),
        fInitialSendSequence(0),
+       fPreviousHighestAcknowledge(0),
        fDuplicateAcknowledgeCount(0),
        fPreviousFlightSize(0),
+       fRecover(0),
        fRoute(NULL),
        fReceiveNext(0),
        fReceiveMaxAdvertised(0),
@@ -1293,12 +1296,16 @@ TCPEndpoint::_DuplicateAcknowledge(tcp_segment_header 
&segment)
        }
 
        if (fDuplicateAcknowledgeCount == 3) {
-               fSlowStartThreshold = max_c(fPreviousFlightSize / 2, 2 * 
fSendMaxSegmentSize);
-               fCongestionWindow = fSlowStartThreshold + 3 * 
fSendMaxSegmentSize;
-               fSendNext = segment.acknowledge;
-               _SendQueued();
-               TRACE("_DuplicateAcknowledge(): packet sent under fast 
restransmit on the receipt of 3rd dup ack");
-
+               if ((segment.acknowledge - 1) > fRecover || (fCongestionWindow 

fSendMaxSegmentSize &&
+                       (fSendUnacknowledged - fPreviousHighestAcknowledge) <= 
4 * fSendMaxSegmentSize)) {
+                       fFlags |= FLAG_RECOVERY;
+                       fRecover = fSendMax.Number() - 1;
+                       fSlowStartThreshold = max_c(fPreviousFlightSize / 2, 2 
* fSendMaxSegmentSize);
+                       fCongestionWindow = fSlowStartThreshold + 3 * 
fSendMaxSegmentSize;
+                       fSendNext = segment.acknowledge;
+                       _SendQueued();
+                       TRACE("_DuplicateAcknowledge(): packet sent under fast 
restransmit on the receipt of 3rd dup ack");
+               }
        } else if (fDuplicateAcknowledgeCount > 3) {
                uint32 flightSize = (fSendMax - fSendUnacknowledged).Number();
                if ((fDuplicateAcknowledgeCount - 3) * fSendMaxSegmentSize <= 
flightSize)
@@ -1738,7 +1745,12 @@ TCPEndpoint::_Receive(tcp_segment_header& segment, 
net_buffer* buffer)
 
                        if (fDuplicateAcknowledgeCount >= 3) {
                                // deflate the window.
-                               fCongestionWindow = fSlowStartThreshold;
+                               if (segment.acknowledge > fRecover) {
+                                       uint32 flightSize = (fSendMax - 
fSendUnacknowledged).Number();
+                                       fCongestionWindow = 
min_c(fSlowStartThreshold,
+                                               max_c(flightSize, 
fSendMaxSegmentSize) + fSendMaxSegmentSize);
+                                       fFlags &= ~FLAG_RECOVERY;
+                               }
                        }
 
                        if (fSendMax == segment.acknowledge)
@@ -2238,6 +2250,7 @@ TCPEndpoint::_PrepareSendPath(const sockaddr* peer)
        fSendUnacknowledged = fInitialSendSequence;
        fSendMax = fInitialSendSequence;
        fSendUrgentOffset = fInitialSendSequence;
+       fRecover = fInitialSendSequence.Number();
 
        // we are counting the SYN here
        fSendQueue.SetInitialSequence(fSendNext + 1);
@@ -2266,14 +2279,20 @@ TCPEndpoint::_Acknowledged(tcp_segment_header& segment)
        ASSERT(fSendUnacknowledged <= segment.acknowledge);
 
        if (fSendUnacknowledged < segment.acknowledge) {
-               fDuplicateAcknowledgeCount = 0;
                fSendQueue.RemoveUntil(segment.acknowledge);
+               uint32 bytesAcknowledged = segment.acknowledge - 
fSendUnacknowledged.Number();
+               fPreviousHighestAcknowledge = fSendUnacknowledged;
+               fSendUnacknowledged = segment.acknowledge;
+
+               if (fPreviousHighestAcknowledge > fSendUnacknowledged) {
+                       // need to update the recover variable upon a sequence 
wraparound
+                       fRecover = segment.acknowledge - 1;
+               }
 
                // the acknowledgment of the SYN/ACK MUST NOT increase the size 
of the congestion window
                if (fSendUnacknowledged != fInitialSendSequence) {
                        if (fCongestionWindow < fSlowStartThreshold)
-                               fCongestionWindow += min_c(segment.acknowledge 
- fSendUnacknowledged.Number(),
-                                       fSendMaxSegmentSize);
+                               fCongestionWindow += min_c(bytesAcknowledged, 
fSendMaxSegmentSize);
                        else {
                                uint32 increment = fSendMaxSegmentSize * 
fSendMaxSegmentSize;
 
@@ -2288,7 +2307,18 @@ TCPEndpoint::_Acknowledged(tcp_segment_header& segment)
                        fSendMaxSegments = UINT32_MAX;
                }
 
-               fSendUnacknowledged = segment.acknowledge;
+               if ((fFlags & FLAG_RECOVERY) != 0) {
+                       fSendNext = fSendUnacknowledged;
+                       _SendQueued();
+                       fCongestionWindow -= bytesAcknowledged;
+
+                       if (bytesAcknowledged > fSendMaxSegmentSize)
+                               fCongestionWindow += fSendMaxSegmentSize;
+
+                       fSendNext = fSendMax;
+               } else
+                       fDuplicateAcknowledgeCount = 0;
+
                if (fSendNext < fSendUnacknowledged)
                        fSendNext = fSendUnacknowledged;
 
@@ -2364,6 +2394,10 @@ TCPEndpoint::_Retransmit()
 
        fSendNext = fSendUnacknowledged;
        _SendQueued();
+
+       fRecover = fSendNext.Number() - 1;
+       if ((fFlags & FLAG_RECOVERY) != 0)
+               fFlags &= ~FLAG_RECOVERY;
 }
 
 
diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h 
b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h
index ff6739e..6a62e07 100644
--- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h
+++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h
@@ -149,8 +149,10 @@ private:
        BufferQueue             fSendQueue;
        tcp_sequence    fLastAcknowledgeSent;
        tcp_sequence    fInitialSendSequence;
+       tcp_sequence    fPreviousHighestAcknowledge;
        uint32                  fDuplicateAcknowledgeCount;
        uint32                  fPreviousFlightSize;
+       uint32                  fRecover;
 
        net_route               *fRoute;
                // TODO: don't use a net_route, but a net_route_info!!!

############################################################################

Revision:    hrev51385
Commit:      5c31f5a67a0aa37c8f2a1464252b2c5b0a959f33
URL:         http://cgit.haiku-os.org/haiku/commit/?id=5c31f5a67a0a
Author:      A-star-ayush <myselfthebest@xxxxxxxxx>
Date:        Fri Aug 25 08:44:35 2017 UTC
Committer:   Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>
Commit-Date: Mon Aug 28 08:52:19 2017 UTC

tcp: rfc 2018: implemented SACK option

Signed-off-by: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/network/protocols/tcp/BufferQueue.cpp 
b/src/add-ons/kernel/network/protocols/tcp/BufferQueue.cpp
index de83ba3..4cf95c5 100644
--- a/src/add-ons/kernel/network/protocols/tcp/BufferQueue.cpp
+++ b/src/add-ons/kernel/network/protocols/tcp/BufferQueue.cpp
@@ -436,6 +436,41 @@ BufferQueue::SetPushPointer()
                fPushPointer = fList.Tail()->sequence + fList.Tail()->size;
 }
 
+
+int
+BufferQueue::PopulateSackInfo(tcp_sequence sequence, int maxSackCount, 
tcp_sack* sacks)
+{
+       SegmentList::ReverseIterator iterator = fList.GetReverseIterator();
+       net_buffer* buffer = iterator.Next();
+
+       int sackCount = 0;
+       while (buffer != NULL && buffer->sequence > sequence) {
+               if (buffer->sequence + buffer->size < 
sacks[sackCount].left_edge) {
+                       if (sackCount + 1 == maxSackCount)
+                               break;
+                       ++sackCount;
+                       sacks[sackCount].left_edge = buffer->sequence;
+                       sacks[sackCount].right_edge = buffer->sequence + 
buffer->size;
+               } else {
+                       sacks[sackCount].left_edge = buffer->sequence;
+                       if (sacks[sackCount].right_edge == 0)
+                               sacks[sackCount].right_edge = buffer->sequence 
+ buffer->size;
+               }
+
+               buffer = iterator.Next();
+       }
+
+       if (sacks[0].left_edge != 0) {
+               for (int i = 0; i <= sackCount; ++i) {
+                       sacks[i].left_edge = htonl(sacks[i].left_edge);
+                       sacks[i].right_edge = htonl(sacks[i].right_edge);
+               }
+               ++sackCount;
+       }
+
+       return sackCount;
+}
+
 #if DEBUG_BUFFER_QUEUE
 
 /*!    Perform a sanity check of the whole queue.
diff --git a/src/add-ons/kernel/network/protocols/tcp/BufferQueue.h 
b/src/add-ons/kernel/network/protocols/tcp/BufferQueue.h
index 73986a8..4c4567e 100644
--- a/src/add-ons/kernel/network/protocols/tcp/BufferQueue.h
+++ b/src/add-ons/kernel/network/protocols/tcp/BufferQueue.h
@@ -42,6 +42,7 @@ public:
 
        inline  size_t                          PushedData() const;
                        void                            SetPushPointer();
+                       int                             
PopulateSackInfo(tcp_sequence sequence, int maxSackCount, tcp_sack* sacks);
 
                        size_t                          Used() const { return 
fNumBytes; }
        inline  size_t                          Free() const;
diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp 
b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
index 91b4b91..2e7ca44 100644
--- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
+++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
@@ -319,7 +319,8 @@ enum {
        FLAG_CLOSED                                     = 0x08,
        FLAG_DELETE_ON_CLOSE            = 0x10,
        FLAG_LOCAL                                      = 0x20,
-       FLAG_RECOVERY                           = 0x40
+       FLAG_RECOVERY                           = 0x40,
+       FLAG_OPTION_SACK_PERMITTED      = 0x80,
 };
 
 
@@ -450,7 +451,7 @@ TCPEndpoint::TCPEndpoint(net_socket* socket)
        fCongestionWindow(0),
        fSlowStartThreshold(0),
        fState(CLOSED),
-       fFlags(FLAG_OPTION_WINDOW_SCALE | FLAG_OPTION_TIMESTAMP)
+       fFlags(FLAG_OPTION_WINDOW_SCALE | FLAG_OPTION_TIMESTAMP | 
FLAG_OPTION_SACK_PERMITTED)
 {
        // TODO: to be replaced with a real read/write locking strategy!
        mutex_init(&fLock, "tcp lock");
@@ -1426,6 +1427,9 @@ TCPEndpoint::_PrepareReceivePath(tcp_segment_header& 
segment)
                        fReceivedTimestamp = segment.timestamp_value;
                } else
                        fFlags &= ~FLAG_OPTION_TIMESTAMP;
+
+               if ((segment.options & TCP_SACK_PERMITTED) == 0)
+                       fFlags &= ~FLAG_OPTION_SACK_PERMITTED;
        }
 
        if (fSendMaxSegmentSize > 2190)
@@ -2027,6 +2031,18 @@ TCPEndpoint::_SendQueued(bool force, uint32 sendWindow)
                        segment.timestamp_value = tcp_now();
                }
 
+               // SACK information is embedded with duplicate acknowledgements
+               if (!fReceiveQueue.IsContiguous() && fLastAcknowledgeSent == 
fReceiveNext
+                       && (fFlags & FLAG_OPTION_SACK_PERMITTED) != 0) {
+                       segment.options |= TCP_HAS_SACK;
+                       int maxSackCount = 4 - ((fFlags & 
FLAG_OPTION_TIMESTAMP) != 0);
+                       segment.sacks = (tcp_sack*)calloc(maxSackCount, 
sizeof(tcp_sack));
+                       if (segment.sacks != NULL)
+                               segment.sackCount = 
fReceiveQueue.PopulateSackInfo(fReceiveNext, maxSackCount, segment.sacks);
+                       else
+                               segment.sackCount = 0;
+               }
+
                if ((segment.flags & TCP_FLAG_SYNCHRONIZE) != 0
                        && fSendNext == fInitialSendSequence) {
                        // add connection establishment options
@@ -2035,6 +2051,8 @@ TCPEndpoint::_SendQueued(bool force, uint32 sendWindow)
                                segment.options |= TCP_HAS_WINDOW_SCALE;
                                segment.window_shift = fReceiveWindowShift;
                        }
+                       if ((fFlags & FLAG_OPTION_SACK_PERMITTED) != 0)
+                               segment.options |= TCP_SACK_PERMITTED;
                }
        }
 
diff --git a/src/add-ons/kernel/network/protocols/tcp/tcp.cpp 
b/src/add-ons/kernel/network/protocols/tcp/tcp.cpp
index b14f662..9f4a329 100644
--- a/src/add-ons/kernel/network/protocols/tcp/tcp.cpp
+++ b/src/add-ons/kernel/network/protocols/tcp/tcp.cpp
@@ -140,10 +140,10 @@ add_options(tcp_segment_header &segment, uint8 *buffer, 
size_t bufferSize)
                bump_option(option, length);
        }
 
-       if (segment.sack_count > 0) {
+       if (segment.sackCount > 0) {
                int sackCount = ((int)(bufferSize - length) - 4) / 
sizeof(tcp_sack);
-               if (sackCount > segment.sack_count)
-                       sackCount = segment.sack_count;
+               if (sackCount > segment.sackCount)
+                       sackCount = segment.sackCount;
 
                if (sackCount > 0) {
                        option->kind = TCP_OPTION_NOP;
@@ -154,6 +154,7 @@ add_options(tcp_segment_header &segment, uint8 *buffer, 
size_t bufferSize)
                        option->length = 2 + sackCount * sizeof(tcp_sack);
                        memcpy(option->sack, segment.sacks, sackCount * 
sizeof(tcp_sack));
                        bump_option(option, length);
+                       free(segment.sacks);
                }
        }
 
@@ -218,6 +219,18 @@ process_options(tcp_segment_header &segment, net_buffer 
*buffer, size_t size)
                                if (option->length == 2 && size >= 2)
                                        segment.options |= TCP_SACK_PERMITTED;
                                break;
+                       case TCP_OPTION_SACK:
+                               if (size >= option->length) {
+                                       segment.options |= TCP_HAS_SACK;
+                                       segment.sackCount = (option->length - 
2) / sizeof(tcp_sack);
+                                       segment.sacks = option->sack;
+
+                                       for (int i = 0; i < segment.sackCount; 
++i) {
+                                               segment.sacks[i].left_edge = 
ntohl(segment.sacks[i].left_edge);
+                                               segment.sacks[i].right_edge = 
ntohl(segment.sacks[i].right_edge);
+                                       }
+                               }
+                               break;
                }
 
                if (length < 0) {
@@ -432,9 +445,9 @@ tcp_options_length(tcp_segment_header& segment)
        if (segment.options & TCP_SACK_PERMITTED)
                length += 2;
 
-       if (segment.sack_count > 0) {
+       if (segment.sackCount > 0) {
                int sackCount = min_c((int)((kMaxOptionSize - length - 4)
-                       / sizeof(tcp_sack)), segment.sack_count);
+                       / sizeof(tcp_sack)), segment.sackCount);
                if (sackCount > 0)
                        length += 4 + sackCount * sizeof(tcp_sack);
        }
diff --git a/src/add-ons/kernel/network/protocols/tcp/tcp.h 
b/src/add-ons/kernel/network/protocols/tcp/tcp.h
index 24890a3..3b2100b 100644
--- a/src/add-ons/kernel/network/protocols/tcp/tcp.h
+++ b/src/add-ons/kernel/network/protocols/tcp/tcp.h
@@ -231,6 +231,7 @@ enum {
        TCP_HAS_WINDOW_SCALE    = 1 << 0,
        TCP_HAS_TIMESTAMPS              = 1 << 1,
        TCP_SACK_PERMITTED              = 1 << 2,
+       TCP_HAS_SACK                    = 1 << 3,
 };
 
 struct tcp_segment_header {
@@ -239,7 +240,7 @@ struct tcp_segment_header {
                flags(_flags),
                window_shift(0),
                max_segment_size(0),
-               sack_count(0),
+               sackCount(0),
                options(0)
        {}
 
@@ -255,7 +256,7 @@ struct tcp_segment_header {
        uint32  timestamp_reply;
 
        tcp_sack        *sacks;
-       int                     sack_count;
+       int                     sackCount;
 
        uint32  options;
 



Other related posts: