diff --git a/include/nuttx/net/tcp.h b/include/nuttx/net/tcp.h index 9bd37e156ae..1a983f3473a 100644 --- a/include/nuttx/net/tcp.h +++ b/include/nuttx/net/tcp.h @@ -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 */ diff --git a/net/tcp/Kconfig b/net/tcp/Kconfig index df88824b8f1..e53ee05b3ab 100644 --- a/net/tcp/Kconfig +++ b/net/tcp/Kconfig @@ -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 diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h index 66da9c81daa..3367286df39 100644 --- a/net/tcp/tcp.h +++ b/net/tcp/tcp.h @@ -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 diff --git a/net/tcp/tcp_input.c b/net/tcp/tcp_input.c index 4782f81d496..96eeb5ac900 100644 --- a/net/tcp/tcp_input.c +++ b/net/tcp/tcp_input.c @@ -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]; diff --git a/net/tcp/tcp_send.c b/net/tcp/tcp_send.c index 0c3747f413b..ed72b1c310d 100644 --- a/net/tcp/tcp_send.c +++ b/net/tcp/tcp_send.c @@ -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;