From b32d8b17149ab7de60f64b5729c28a17f53e23c7 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 30 Jun 2018 20:50:07 -0600 Subject: [PATCH] net/tcp and sixlowpan: Separate the the TCP receive window calculations to a separate header file. It must also be used by the special 6LoWPAN TCP logic. --- net/sixlowpan/sixlowpan_tcpsend.c | 8 +- net/tcp/Make.defs | 4 + net/tcp/tcp.h | 20 ++++ net/tcp/tcp_recvwindow.c | 150 ++++++++++++++++++++++++++++++ net/tcp/tcp_send.c | 74 ++------------- 5 files changed, 187 insertions(+), 69 deletions(-) create mode 100644 net/tcp/tcp_recvwindow.c diff --git a/net/sixlowpan/sixlowpan_tcpsend.c b/net/sixlowpan/sixlowpan_tcpsend.c index c7d60d4e93..240bf87224 100644 --- a/net/sixlowpan/sixlowpan_tcpsend.c +++ b/net/sixlowpan/sixlowpan_tcpsend.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/sixlowpan/sixlowpan_tcpsend.c * - * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2017-2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -267,6 +267,12 @@ static int sixlowpan_tcp_header(FAR struct tcp_conn_s *conn, } else { + /* Update the TCP received window based on I/O buffer availability */ + + tcp_update_recvwindws(dev); + + /* Set the TCP Window */ + ipv6tcp->tcp.wnd[0] = ((NET_DEV_RCVWNDO(dev)) >> 8); ipv6tcp->tcp.wnd[1] = ((NET_DEV_RCVWNDO(dev)) & 0xff); } diff --git a/net/tcp/Make.defs b/net/tcp/Make.defs index 32009fe3af..69a7b6adef 100644 --- a/net/tcp/Make.defs +++ b/net/tcp/Make.defs @@ -62,6 +62,10 @@ ifeq ($(CONFIG_NET_TCPPROTO_OPTIONS),y) SOCK_CSRCS += tcp_setsockopt.c tcp_getsockopt.c endif +ifeq ($(CONFIG_NET_TCP_RWND_CONTROL),y) +SOCK_CSRCS += tcp_recvwindow.c +endif + # Transport layer NET_CSRCS += tcp_conn.c tcp_seqno.c tcp_devpoll.c tcp_finddev.c tcp_timer.c diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h index 3be1135439..df38dddc92 100644 --- a/net/tcp/tcp.h +++ b/net/tcp/tcp.h @@ -1355,6 +1355,26 @@ int tcp_getsockopt(FAR struct socket *psock, int option, FAR void *value, FAR socklen_t *value_len); #endif +/**************************************************************************** + * Name: tcp_update_recvwindws + * + * Description: + * Update the TCP receive window for the specified device. + * + * Input Parameters: + * dev - The device whose TCP receive window will be updated. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_TCP_RWND_CONTROL +void tcp_update_recvwindws(FAR struct net_driver_s *dev); +#else +# define tcp_update_recvwindws(dev) +#endif + /**************************************************************************** * Name: psock_tcp_cansend * diff --git a/net/tcp/tcp_recvwindow.c b/net/tcp/tcp_recvwindow.c new file mode 100644 index 0000000000..fe9ee66f46 --- /dev/null +++ b/net/tcp/tcp_recvwindow.c @@ -0,0 +1,150 @@ +/**************************************************************************** + * net/tcp/tcp_recvwindow.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include "tcp/tcp.h" + +#ifdef CONFIG_NET_TCP_RWND_CONTROL + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tcp_update_recvwindws + * + * Description: + * Update the TCP receive window for the specified device. + * + * Input Parameters: + * dev - The device whose TCP receive window will be updated. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void tcp_update_recvwindws(FAR struct net_driver_s *dev) +{ + uint16_t iplen; + uint16_t overhead; + int navail; + +#ifdef CONFIG_NET_IPv6 +#ifdef CONFIG_NET_IPv4 + if (IFF_IS_IPv6(dev->d_flags)) +#endif + { + iplen = IPv6_HDRLEN; + } +#endif /* CONFIG_NET_IPv6 */ + +#ifdef CONFIG_NET_IPv4 +#ifdef CONFIG_NET_IPv6 + else +#endif + { + iplen = IPv4_HDRLEN; + } +#endif /* CONFIG_NET_IPv4 */ + + /* Update the TCP received window based on I/O buffer availability + * + * REVISIT: The actual TCP header length is varialble. TCP_HDRLEN + * is the minimum size. + */ + + overhead = NET_LL_HDRLEN(dev) + iplen + TCP_HDRLEN; + navail = iob_navail(); + if (navail > 0) + { + uint32_t rwnd; + + /* The optimal TCP window size is the amount of TCP data that we can + * currently buffer via TCP read-ahead buffering minus overhead for the + * link-layer, IP, and TCP headers. This logic here assumes that + * all IOBs are available for TCP buffering. + * + * Assume that all of the available IOBs are can be used for buffering + * on this connection. Also assume that at least one chain is available + * concatenate the IOBs. + * + * REVISIT: In an environment with multiple, active read-ahead TCP + * sockets (and perhaps multiple network devices) or if there are + * other consumers of IOBs (such as for TCP write buffering) then the + * total number of IOBs will all not be available for read-ahead + * buffering for this connection. + */ + + rwnd = (navail * CONFIG_IOB_BUFSIZE) - overhead; + if (rwnd > UINT16_MAX) + { + rwnd = UINT16_MAX; + } + + /* Save the new receive window size */ + + NET_DEV_RCVWNDO(dev) = (uint16_t)rwnd; + } + else /* if (navail == 0) */ + { + /* No IOBs are available... fall back to the configured default + * which assumes no write buffering. The only buffering available + * is within the packet buffer itself. + * + * NOTE: If no IOBs are available, then the next packet will be + * lost if there is no listener on the connection. + */ + + NET_DEV_RCVWNDO(dev) = dev->d_mtu - overhead; + } +} + +#endif /* CONFIG_NET_TCP_RWND_CONTROL */ diff --git a/net/tcp/tcp_send.c b/net/tcp/tcp_send.c index 5593857eb7..229eaeabed 100644 --- a/net/tcp/tcp_send.c +++ b/net/tcp/tcp_send.c @@ -55,10 +55,6 @@ #include #include -#ifdef CONFIG_NET_TCP_RWND_CONTROL -# include -#endif - #include "devif/devif.h" #include "inet/inet.h" #include "tcp/tcp.h" @@ -314,12 +310,6 @@ static void tcp_sendcommon(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, FAR struct tcp_hdr_s *tcp) { -#ifdef CONFIG_NET_TCP_RWND_CONTROL - uint16_t iplen; - uint16_t overhead; - int navail; -#endif - /* Copy the IP address into the IPv6 header */ #ifdef CONFIG_NET_IPv6 @@ -331,10 +321,6 @@ static void tcp_sendcommon(FAR struct net_driver_s *dev, net_ipv6addr_hdrcopy(ipv6->srcipaddr, dev->d_ipv6addr); net_ipv6addr_hdrcopy(ipv6->destipaddr, conn->u.ipv6.raddr); - -#ifdef CONFIG_NET_TCP_RWND_CONTROL - iplen = IPv6_HDRLEN; -#endif } #endif /* CONFIG_NET_IPv6 */ @@ -347,10 +333,6 @@ static void tcp_sendcommon(FAR struct net_driver_s *dev, net_ipv4addr_hdrcopy(ipv4->srcipaddr, &dev->d_ipaddr); net_ipv4addr_hdrcopy(ipv4->destipaddr, &conn->u.ipv4.raddr); - -#ifdef CONFIG_NET_TCP_RWND_CONTROL - iplen = IPv4_HDRLEN; -#endif } #endif /* CONFIG_NET_IPv4 */ @@ -362,56 +344,6 @@ static void tcp_sendcommon(FAR struct net_driver_s *dev, tcp->srcport = conn->lport; tcp->destport = conn->rport; -#ifdef CONFIG_NET_TCP_RWND_CONTROL - /* Update the TCP received window based on I/O buffer availability */ - /* NOTE: This algorithm is still experimental */ - - overhead = NET_LL_HDRLEN(dev) + iplen + TCP_HDRLEN; - navail = iob_navail(); - if (navail > 0) - { - uint32_t rwnd; - - /* The optimal TCP window size is the amount of TCP data that we can - * currently buffer via TCP read-ahead buffering minus overhead for the - * link-layer, IP, and TCP headers. This logic here assumes that - * all IOBs are available for TCP buffering. - * - * Assume that all of the available IOBs are can be used for buffering - * on this connection. Also assume that at least one chain is available - * concatenate the IOBs. - * - * REVISIT: In an environment with multiple, active read-ahead TCP - * sockets (and perhaps multiple network devices) or if there are - * other consumers of IOBs (such as for TCP write buffering) then the - * total number of IOBs will all not be available for read-ahead - * buffering for this connection. - */ - - rwnd = (navail * CONFIG_IOB_BUFSIZE) - overhead; - if (rwnd > UINT16_MAX) - { - rwnd = UINT16_MAX; - } - - /* Save the new receive window size */ - - NET_DEV_RCVWNDO(dev) = (uint16_t)rwnd; - } - else /* if (navail == 0) */ - { - /* No IOBs are available... fall back to the configured default - * which assumes no write buffering. The only buffering available - * is within the packet buffer itself. - * - * NOTE: If no IOBs are available, then the next packet will be - * lost if there is no listener on the connection. - */ - - NET_DEV_RCVWNDO(dev) = dev->d_mtu - overhead; - } -#endif - /* Set the TCP window */ if (conn->tcpstateflags & TCP_STOPPED) @@ -425,6 +357,12 @@ static void tcp_sendcommon(FAR struct net_driver_s *dev, } else { + /* Update the TCP received window based on I/O buffer availability */ + + tcp_update_recvwindws(dev); + + /* Set the TCP Window */ + tcp->wnd[0] = ((NET_DEV_RCVWNDO(dev)) >> 8); tcp->wnd[1] = ((NET_DEV_RCVWNDO(dev)) & 0xff); }