net/tcp: add window scale support

Reference here:
https://tools.ietf.org/html/rfc1323

Signed-off-by: chao.an <anchao@xiaomi.com>
This commit is contained in:
chao.an
2021-07-07 03:55:41 -05:00
committed by Xiang Xiao
parent a5cdc4e69b
commit aab03ef86d
5 changed files with 81 additions and 7 deletions
+3
View File
@@ -76,8 +76,11 @@
#define TCP_OPT_END 0 /* End of TCP options list */
#define TCP_OPT_NOOP 1 /* "No-operation" TCP option */
#define TCP_OPT_MSS 2 /* Maximum segment size TCP option */
#define TCP_OPT_WS 3 /* Window size scaling factor */
#define TCP_OPT_NOOP_LEN 1 /* Length of TCP NOOP option. */
#define TCP_OPT_MSS_LEN 4 /* Length of TCP MSS option. */
#define TCP_OPT_WS_LEN 3 /* Length of TCP WS option. */
/* The TCP states used in the struct tcp_conn_s tcpstateflags field */
+21
View File
@@ -106,6 +106,27 @@ config NET_TCP_FAST_RETRANSMIT_WATERMARK
missing segment, without waiting for a retransmission timer to
expire.
config NET_TCP_WINDOW_SCALE
bool "Enable TCP/IP Window Scale Option"
default n
---help---
RFC1323:
2. TCP WINDOW SCALE OPTION
The window scale extension expands the definition of the TCP
window to 32 bits and then uses a scale factor to carry this 32-
bit value in the 16-bit Window field of the TCP header (SEG.WND in
RFC-793).
if NET_TCP_WINDOW_SCALE
config NET_TCP_WINDOW_SCALE_FACTOR
int "TCP/IP Window Scale Factor"
default 0
---help---
This is the default value for window scale factor.
endif # NET_TCP_WINDOW_SCALE
config NET_TCP_NOTIFIER
bool "Support TCP notifications"
default n
+13 -1
View File
@@ -96,6 +96,10 @@
#define TCP_SEQ_ADD(a, b) ((uint32_t)((a) + (b)))
#define TCP_SEQ_SUB(a, b) ((uint32_t)((a) - (b)))
/* The TCP options flags */
#define TCP_WSCALE 0x01U /* Window Scale option enabled */
/****************************************************************************
* Public Type Definitions
****************************************************************************/
@@ -187,9 +191,16 @@ struct tcp_conn_s
uint16_t rport; /* The remoteTCP port, in network byte order */
uint16_t mss; /* Current maximum segment size for the
* connection */
uint32_t rcv_adv; /* The right edge of the recv window advertized */
#ifdef CONFIG_NET_TCP_WINDOW_SCALE
uint32_t snd_wnd; /* Sequence and acknowledgement numbers of last
* window update */
uint8_t snd_scale; /* Sender window scale factor */
uint8_t rcv_scale; /* Receiver windows scale factor */
#else
uint16_t snd_wnd; /* Sequence and acknowledgement numbers of last
* window update */
uint32_t rcv_adv; /* The right edge of the recv window advertized */
#endif
#if CONFIG_NET_RECV_BUFSIZE > 0
int32_t rcv_bufs; /* Maximum amount of bytes queued in recv */
#endif
@@ -198,6 +209,7 @@ struct tcp_conn_s
#else
uint16_t tx_unacked; /* Number bytes sent but not yet ACKed */
#endif
uint16_t flags; /* Flags of TCP-specific options */
/* If the TCP socket is bound to a local address, then this is
* a reference to the device that routes traffic on the corresponding
+24 -2
View File
@@ -388,6 +388,15 @@ static void tcp_input(FAR struct net_driver_s *dev, uint8_t domain,
(uint16_t)dev->d_buf[hdrlen + 3 + i];
conn->mss = tmp16 > tcp_mss ? tcp_mss : tmp16;
}
#ifdef CONFIG_NET_TCP_WINDOW_SCALE
else if (opt == TCP_OPT_WS &&
dev->d_buf[hdrlen + 1 + i] == TCP_OPT_WS_LEN)
{
conn->snd_scale = dev->d_buf[hdrlen + 2 + i];
conn->rcv_scale = CONFIG_NET_TCP_WINDOW_SCALE_FACTOR;
conn->flags |= TCP_WSCALE;
}
#endif
else
{
/* All other options have a length field, so that we
@@ -440,7 +449,12 @@ found:
/* Update the connection's window size */
conn->snd_wnd = ((uint16_t)tcp->wnd[0] << 8) + (uint16_t)tcp->wnd[1];
#ifdef CONFIG_NET_TCP_WINDOW_SCALE
conn->snd_wnd = (((uint32_t)tcp->wnd[0] << 8) + (uint32_t)tcp->wnd[1]) <<
conn->snd_scale;
#else
conn->snd_wnd = (((uint16_t)tcp->wnd[0] << 8) + (uint16_t)tcp->wnd[1]);
#endif
flags = 0;
@@ -783,6 +797,15 @@ found:
dev->d_buf[hdrlen + 3 + i];
conn->mss = tmp16 > tcp_mss ? tcp_mss : tmp16;
}
#ifdef CONFIG_NET_TCP_WINDOW_SCALE
else if (opt == TCP_OPT_WS &&
dev->d_buf[hdrlen + 1 + i] == TCP_OPT_WS_LEN)
{
conn->snd_scale = dev->d_buf[hdrlen + 2 + i];
conn->rcv_scale = CONFIG_NET_TCP_WINDOW_SCALE_FACTOR;
conn->flags |= TCP_WSCALE;
}
#endif
else
{
/* All other options have a length field, so that we
@@ -797,7 +820,6 @@ found:
break;
}
}
i += dev->d_buf[hdrlen + 1 + i];
+20 -4
View File
@@ -365,14 +365,18 @@ static void tcp_sendcommon(FAR struct net_driver_s *dev,
uint32_t rcvseq = tcp_getsequence(conn->rcvseq);
uint16_t recvwndo = tcp_get_recvwindow(dev, conn);
/* Update the Receiver Window */
conn->rcv_adv = rcvseq + recvwndo;
#ifdef CONFIG_NET_TCP_WINDOW_SCALE
recvwndo >>= conn->rcv_scale;
#endif
/* Set the TCP Window */
tcp->wnd[0] = recvwndo >> 8;
tcp->wnd[1] = recvwndo & 0xff;
/* Update the Receiver Window */
conn->rcv_adv = rcvseq + recvwndo;
}
/* Finish the IP portion of the message and calculate checksums */
@@ -674,6 +678,18 @@ void tcp_synack(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
tcp->optdata[optlen++] = TCP_OPT_MSS_LEN;
tcp->optdata[optlen++] = tcp_mss >> 8;
tcp->optdata[optlen++] = tcp_mss & 0xff;
#ifdef CONFIG_NET_TCP_WINDOW_SCALE
if (tcp->flags == TCP_SYN ||
((tcp->flags == (TCP_ACK | TCP_SYN)) && (conn->flags & TCP_WSCALE)))
{
tcp->optdata[optlen++] = TCP_OPT_NOOP;
tcp->optdata[optlen++] = TCP_OPT_WS;
tcp->optdata[optlen++] = TCP_OPT_WS_LEN;
tcp->optdata[optlen++] = CONFIG_NET_TCP_WINDOW_SCALE_FACTOR;
}
#endif
tcp->tcpoffset = ((TCP_HDRLEN + optlen) / 4) << 4;
dev->d_len += optlen;