From 3388f7c151f1f8faf3906ae3753cf0872e099e33 Mon Sep 17 00:00:00 2001
From: A-star-ayush <myselfthebest@yahoo.com>
Date: Fri, 25 Aug 2017 14:14:35 +0530
Subject: [PATCH] tcp: rfc 2018: implemented SACK option
---
.../kernel/network/protocols/tcp/BufferQueue.cpp | 35 ++++++++++++++++++++++
.../kernel/network/protocols/tcp/BufferQueue.h | 1 +
.../kernel/network/protocols/tcp/TCPEndpoint.cpp | 22 ++++++++++++--
src/add-ons/kernel/network/protocols/tcp/tcp.cpp | 23 ++++++++++----
src/add-ons/kernel/network/protocols/tcp/tcp.h | 5 ++--
5 files changed, 77 insertions(+), 9 deletions(-)
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
|
b
|
BufferQueue::SetPushPointer()
|
436 | 436 | fPushPointer = fList.Tail()->sequence + fList.Tail()->size; |
437 | 437 | } |
438 | 438 | |
| 439 | |
| 440 | int |
| 441 | BufferQueue::PopulateSackInfo(tcp_sequence sequence, int maxSackCount, tcp_sack* sacks) |
| 442 | { |
| 443 | SegmentList::ReverseIterator iterator = fList.GetReverseIterator(); |
| 444 | net_buffer* buffer = iterator.Next(); |
| 445 | |
| 446 | int sackCount = 0; |
| 447 | while (buffer != NULL && buffer->sequence > sequence) { |
| 448 | if (buffer->sequence + buffer->size < sacks[sackCount].left_edge) { |
| 449 | if (sackCount + 1 == maxSackCount) |
| 450 | break; |
| 451 | ++sackCount; |
| 452 | sacks[sackCount].left_edge = buffer->sequence; |
| 453 | sacks[sackCount].right_edge = buffer->sequence + buffer->size; |
| 454 | } else { |
| 455 | sacks[sackCount].left_edge = buffer->sequence; |
| 456 | if (sacks[sackCount].right_edge == 0) |
| 457 | sacks[sackCount].right_edge = buffer->sequence + buffer->size; |
| 458 | } |
| 459 | |
| 460 | buffer = iterator.Next(); |
| 461 | } |
| 462 | |
| 463 | if (sacks[0].left_edge != 0) { |
| 464 | for (int i = 0; i <= sackCount; ++i) { |
| 465 | sacks[i].left_edge = htonl(sacks[i].left_edge); |
| 466 | sacks[i].right_edge = htonl(sacks[i].right_edge); |
| 467 | } |
| 468 | ++sackCount; |
| 469 | } |
| 470 | |
| 471 | return sackCount; |
| 472 | } |
| 473 | |
439 | 474 | #if DEBUG_BUFFER_QUEUE |
440 | 475 | |
441 | 476 | /*! 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
|
b
|
public:
|
42 | 42 | |
43 | 43 | inline size_t PushedData() const; |
44 | 44 | void SetPushPointer(); |
| 45 | int PopulateSackInfo(tcp_sequence sequence, int maxSackCount, tcp_sack* sacks); |
45 | 46 | |
46 | 47 | size_t Used() const { return fNumBytes; } |
47 | 48 | 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 1d02161..0e2282e 100644
a
|
b
|
enum {
|
319 | 319 | FLAG_CLOSED = 0x08, |
320 | 320 | FLAG_DELETE_ON_CLOSE = 0x10, |
321 | 321 | FLAG_LOCAL = 0x20, |
322 | | FLAG_RECOVERY = 0x40 |
| 322 | FLAG_RECOVERY = 0x40, |
| 323 | FLAG_OPTION_SACK_PERMITTED = 0x80, |
323 | 324 | }; |
324 | 325 | |
325 | 326 | |
… |
… |
TCPEndpoint::TCPEndpoint(net_socket* socket)
|
450 | 451 | fCongestionWindow(0), |
451 | 452 | fSlowStartThreshold(0), |
452 | 453 | fState(CLOSED), |
453 | | fFlags(FLAG_OPTION_WINDOW_SCALE | FLAG_OPTION_TIMESTAMP) |
| 454 | fFlags(FLAG_OPTION_WINDOW_SCALE | FLAG_OPTION_TIMESTAMP | FLAG_OPTION_SACK_PERMITTED) |
454 | 455 | { |
455 | 456 | // TODO: to be replaced with a real read/write locking strategy! |
456 | 457 | mutex_init(&fLock, "tcp lock"); |
… |
… |
TCPEndpoint::_PrepareReceivePath(tcp_segment_header& segment)
|
1426 | 1427 | fReceivedTimestamp = segment.timestamp_value; |
1427 | 1428 | } else |
1428 | 1429 | fFlags &= ~FLAG_OPTION_TIMESTAMP; |
| 1430 | |
| 1431 | if ((segment.options & TCP_SACK_PERMITTED) == 0) |
| 1432 | fFlags &= ~FLAG_OPTION_SACK_PERMITTED; |
1429 | 1433 | } |
1430 | 1434 | |
1431 | 1435 | if (fSendMaxSegmentSize > 2190) |
… |
… |
TCPEndpoint::_SendQueued(bool force, uint32 sendWindow)
|
2027 | 2031 | segment.timestamp_value = tcp_now(); |
2028 | 2032 | } |
2029 | 2033 | |
| 2034 | // SACK information is embedded with duplicate acknowledgements |
| 2035 | if (!fReceiveQueue.IsContiguous() && fLastAcknowledgeSent == fReceiveNext |
| 2036 | && (fFlags & FLAG_OPTION_SACK_PERMITTED) != 0) { |
| 2037 | segment.options |= TCP_HAS_SACK; |
| 2038 | int maxSackCount = 4 - ((fFlags & FLAG_OPTION_TIMESTAMP) != 0); |
| 2039 | segment.sacks = (tcp_sack*)calloc(maxSackCount, sizeof(tcp_sack)); |
| 2040 | if (segment.sacks != NULL) |
| 2041 | segment.sackCount = fReceiveQueue.PopulateSackInfo(fReceiveNext, maxSackCount, segment.sacks); |
| 2042 | else |
| 2043 | segment.sackCount = 0; |
| 2044 | } |
| 2045 | |
2030 | 2046 | if ((segment.flags & TCP_FLAG_SYNCHRONIZE) != 0 |
2031 | 2047 | && fSendNext == fInitialSendSequence) { |
2032 | 2048 | // add connection establishment options |
… |
… |
TCPEndpoint::_SendQueued(bool force, uint32 sendWindow)
|
2035 | 2051 | segment.options |= TCP_HAS_WINDOW_SCALE; |
2036 | 2052 | segment.window_shift = fReceiveWindowShift; |
2037 | 2053 | } |
| 2054 | if ((fFlags & FLAG_OPTION_SACK_PERMITTED) != 0) |
| 2055 | segment.options |= TCP_SACK_PERMITTED; |
2038 | 2056 | } |
2039 | 2057 | } |
2040 | 2058 | |
diff --git a/src/add-ons/kernel/network/protocols/tcp/tcp.cpp b/src/add-ons/kernel/network/protocols/tcp/tcp.cpp
index b14f662..61c4ca5 100644
a
|
b
|
add_options(tcp_segment_header &segment, uint8 *buffer, size_t bufferSize)
|
140 | 140 | bump_option(option, length); |
141 | 141 | } |
142 | 142 | |
143 | | if (segment.sack_count > 0) { |
| 143 | if (segment.sackCount > 0) { |
144 | 144 | int sackCount = ((int)(bufferSize - length) - 4) / sizeof(tcp_sack); |
145 | | if (sackCount > segment.sack_count) |
146 | | sackCount = segment.sack_count; |
| 145 | if (sackCount > segment.sackCount) |
| 146 | sackCount = segment.sackCount; |
147 | 147 | |
148 | 148 | if (sackCount > 0) { |
149 | 149 | option->kind = TCP_OPTION_NOP; |
… |
… |
add_options(tcp_segment_header &segment, uint8 *buffer, size_t bufferSize)
|
154 | 154 | option->length = 2 + sackCount * sizeof(tcp_sack); |
155 | 155 | memcpy(option->sack, segment.sacks, sackCount * sizeof(tcp_sack)); |
156 | 156 | bump_option(option, length); |
| 157 | free(segment.sacks); |
157 | 158 | } |
158 | 159 | } |
159 | 160 | |
… |
… |
process_options(tcp_segment_header &segment, net_buffer *buffer, size_t size)
|
218 | 219 | if (option->length == 2 && size >= 2) |
219 | 220 | segment.options |= TCP_SACK_PERMITTED; |
220 | 221 | break; |
| 222 | case TCP_OPTION_SACK: |
| 223 | if (size >= option->length) { |
| 224 | segment.options |= TCP_HAS_SACK; |
| 225 | segment.sackCount = (option->length - 2) / sizeof(tcp_sack); |
| 226 | segment.sacks = option->sack; |
| 227 | |
| 228 | for(int i = 0; i < segment.sackCount; ++i) { |
| 229 | segment.sacks[i].left_edge = ntohl(segment.sacks[i].left_edge); |
| 230 | segment.sacks[i].right_edge = ntohl(segment.sacks[i].right_edge); |
| 231 | } |
| 232 | } |
| 233 | break; |
221 | 234 | } |
222 | 235 | |
223 | 236 | if (length < 0) { |
… |
… |
tcp_options_length(tcp_segment_header& segment)
|
432 | 445 | if (segment.options & TCP_SACK_PERMITTED) |
433 | 446 | length += 2; |
434 | 447 | |
435 | | if (segment.sack_count > 0) { |
| 448 | if (segment.sackCount > 0) { |
436 | 449 | int sackCount = min_c((int)((kMaxOptionSize - length - 4) |
437 | | / sizeof(tcp_sack)), segment.sack_count); |
| 450 | / sizeof(tcp_sack)), segment.sackCount); |
438 | 451 | if (sackCount > 0) |
439 | 452 | length += 4 + sackCount * sizeof(tcp_sack); |
440 | 453 | } |
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
|
b
|
enum {
|
231 | 231 | TCP_HAS_WINDOW_SCALE = 1 << 0, |
232 | 232 | TCP_HAS_TIMESTAMPS = 1 << 1, |
233 | 233 | TCP_SACK_PERMITTED = 1 << 2, |
| 234 | TCP_HAS_SACK = 1 << 3, |
234 | 235 | }; |
235 | 236 | |
236 | 237 | struct tcp_segment_header { |
… |
… |
struct tcp_segment_header {
|
239 | 240 | flags(_flags), |
240 | 241 | window_shift(0), |
241 | 242 | max_segment_size(0), |
242 | | sack_count(0), |
| 243 | sackCount(0), |
243 | 244 | options(0) |
244 | 245 | {} |
245 | 246 | |
… |
… |
struct tcp_segment_header {
|
255 | 256 | uint32 timestamp_reply; |
256 | 257 | |
257 | 258 | tcp_sack *sacks; |
258 | | int sack_count; |
| 259 | int sackCount; |
259 | 260 | |
260 | 261 | uint32 options; |
261 | 262 | |