2007-09-02 23:58:35 +02:00
|
|
|
/****************************************************************************
|
2014-06-18 18:18:53 +02:00
|
|
|
* net/tcp/tcp_conn.c
|
2007-09-02 23:58:35 +02:00
|
|
|
*
|
2018-03-12 17:59:46 +01:00
|
|
|
* Copyright (C) 2007-2011, 2013-2015, 2018 Gregory Nutt. All rights
|
|
|
|
* reserved.
|
2012-09-13 20:32:24 +02:00
|
|
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
2007-09-02 23:58:35 +02:00
|
|
|
*
|
2007-09-03 01:11:10 +02:00
|
|
|
* Large parts of this file were leveraged from uIP logic:
|
|
|
|
*
|
|
|
|
* Copyright (c) 2001-2003, Adam Dunkels.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
2007-09-02 23:58:35 +02:00
|
|
|
* 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
|
2007-09-03 01:11:10 +02:00
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. The name of the author may not be used to endorse or promote
|
|
|
|
* products derived from this software without specific prior
|
|
|
|
* written permission.
|
2007-09-02 23:58:35 +02:00
|
|
|
*
|
2007-09-03 01:11:10 +02:00
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
2007-09-02 23:58:35 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Included Files
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include <nuttx/config.h>
|
2007-11-22 19:36:46 +01:00
|
|
|
#if defined(CONFIG_NET) && defined(CONFIG_NET_TCP)
|
2007-09-02 23:58:35 +02:00
|
|
|
|
2009-12-15 15:53:45 +01:00
|
|
|
#include <stdint.h>
|
2007-09-02 23:58:35 +02:00
|
|
|
#include <string.h>
|
2009-12-17 16:01:22 +01:00
|
|
|
#include <assert.h>
|
2007-09-03 01:11:10 +02:00
|
|
|
#include <errno.h>
|
2007-11-06 00:04:16 +01:00
|
|
|
#include <debug.h>
|
2022-04-26 13:59:07 +02:00
|
|
|
#include <sys/random.h>
|
2007-11-06 00:04:16 +01:00
|
|
|
|
2015-05-29 23:16:11 +02:00
|
|
|
#include <netinet/in.h>
|
|
|
|
|
2007-09-02 23:58:35 +02:00
|
|
|
#include <arch/irq.h>
|
|
|
|
|
2020-05-15 08:01:01 +02:00
|
|
|
#include <nuttx/clock.h>
|
2021-12-31 08:19:48 +01:00
|
|
|
#include <nuttx/kmalloc.h>
|
2014-06-24 16:53:28 +02:00
|
|
|
#include <nuttx/net/netconfig.h>
|
2014-07-05 00:38:51 +02:00
|
|
|
#include <nuttx/net/net.h>
|
2014-06-24 17:28:44 +02:00
|
|
|
#include <nuttx/net/netdev.h>
|
2014-07-05 03:13:08 +02:00
|
|
|
#include <nuttx/net/ip.h>
|
2014-06-26 17:32:39 +02:00
|
|
|
#include <nuttx/net/tcp.h>
|
2007-09-02 23:58:35 +02:00
|
|
|
|
2014-06-29 02:07:02 +02:00
|
|
|
#include "devif/devif.h"
|
2017-08-07 19:50:50 +02:00
|
|
|
#include "inet/inet.h"
|
2014-07-05 00:38:51 +02:00
|
|
|
#include "tcp/tcp.h"
|
2020-05-06 04:25:03 +02:00
|
|
|
#include "arp/arp.h"
|
|
|
|
#include "icmpv6/icmpv6.h"
|
2022-10-26 08:31:04 +02:00
|
|
|
#include "nat/nat.h"
|
2007-09-02 23:58:35 +02:00
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Data
|
|
|
|
****************************************************************************/
|
|
|
|
|
2016-05-30 17:31:44 +02:00
|
|
|
/* The array containing all TCP connections. */
|
2007-09-02 23:58:35 +02:00
|
|
|
|
2022-11-04 11:38:07 +01:00
|
|
|
#if CONFIG_NET_TCP_PREALLOC_CONNS > 0
|
|
|
|
static struct tcp_conn_s g_tcp_connections[CONFIG_NET_TCP_PREALLOC_CONNS];
|
2021-12-31 08:19:48 +01:00
|
|
|
#endif
|
2007-09-02 23:58:35 +02:00
|
|
|
|
2007-09-03 22:34:44 +02:00
|
|
|
/* A list of all free TCP connections */
|
|
|
|
|
|
|
|
static dq_queue_t g_free_tcp_connections;
|
|
|
|
|
|
|
|
/* A list of all connected TCP connections */
|
|
|
|
|
|
|
|
static dq_queue_t g_active_tcp_connections;
|
|
|
|
|
2007-09-02 23:58:35 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Private Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
2014-11-22 14:14:17 +01:00
|
|
|
/****************************************************************************
|
2021-03-31 12:11:19 +02:00
|
|
|
* Name: tcp_listener
|
2014-11-22 14:14:17 +01:00
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Given a local port number (in network byte order), find the TCP
|
Sources and Docs: Fix typos and nxstyle issues
Documentation/contributing/coding_style.rst:
* Fix repeated words: ("this this").
* Remove trailing spaces.
boards/z80/z80/z80sim/README.txt:
* Fix repeated words: ("this this") and rewrap lines.
graphics/Kconfig,
libs/libc/math/Kconfig:
* Fix repeated words: ("this this").
arch/arm/src/armv7-a/arm_assert.c,
arch/arm/src/armv7-r/arm_assert.c,
arch/arm/src/imxrt/imxrt_enet.c,
arch/arm/src/kinetis/kinetis_enet.c,
arch/arm/src/kinetis/kinetis_flexcan.c,
arch/arm/src/s32k1xx/s32k1xx_enet.c,
arch/arm/src/s32k1xx/s32k1xx_flexcan.c,
arch/arm/src/stm32/stm32_pwm.c,
arch/arm/src/stm32h7/stm32_pwm.c,
arch/arm/src/stm32l4/stm32l4_pwm.c,
arch/renesas/src/rx65n/rx65n_usbdev.c,
binfmt/libnxflat/libnxflat_bind.c,
drivers/pipes/pipe_common.c,
net/igmp/igmp_input.c,
net/tcp/tcp_conn.c,
sched/sched/sched_roundrobin.c:
* Fix typo in comment ("this this").
arch/arm/src/cxd56xx/cxd56_usbdev.c,
arch/arm/src/lc823450/lc823450_usbdev.c:
* Fix typo in comment and rewrap lines.
arch/arm/src/imxrt/imxrt_usbdev.c,
arch/arm/src/stm32/stm32_dac.c,
arch/arm/src/stm32f0l0g0/stm32_pwm.c,
arch/arm/src/stm32f7/stm32_pwm.c,
arch/arm/src/tiva/lm/lm4f_gpio.h,
fs/nxffs/nxffs_write.c,
include/nuttx/analog/pga11x.h,
include/nuttx/usb/usbdev.h,
net/mld/mld_join.c:
* Fix typo in comment ("this this").
* Fix nxstyle issues.
2020-10-02 01:29:35 +02:00
|
|
|
* connection that listens on this port.
|
2014-11-22 14:14:17 +01:00
|
|
|
*
|
|
|
|
* Primary uses: (1) to determine if a port number is available, (2) to
|
|
|
|
* To identify the socket that will accept new connections on a local port.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2021-03-31 12:11:19 +02:00
|
|
|
static FAR struct tcp_conn_s *
|
|
|
|
tcp_listener(uint8_t domain, FAR const union ip_addr_u *ipaddr,
|
|
|
|
uint16_t portno)
|
2014-11-22 14:14:17 +01:00
|
|
|
{
|
2021-12-31 08:19:48 +01:00
|
|
|
FAR struct tcp_conn_s *conn = NULL;
|
2014-11-22 14:14:17 +01:00
|
|
|
|
|
|
|
/* Check if this port number is in use by any active UIP TCP connection */
|
|
|
|
|
2021-12-31 08:19:48 +01:00
|
|
|
while ((conn = tcp_nextconn(conn)) != NULL)
|
2014-11-22 14:14:17 +01:00
|
|
|
{
|
2014-11-22 17:46:37 +01:00
|
|
|
/* Check if this connection is open and the local port assignment
|
|
|
|
* matches the requested port number.
|
|
|
|
*/
|
|
|
|
|
2021-03-31 12:11:19 +02:00
|
|
|
if (conn->tcpstateflags != TCP_CLOSED && conn->lport == portno
|
|
|
|
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
|
|
|
|
&& domain == conn->domain
|
|
|
|
#endif
|
|
|
|
)
|
2014-11-22 14:14:17 +01:00
|
|
|
{
|
2014-11-22 17:46:37 +01:00
|
|
|
/* If there are multiple interface devices, then the local IP
|
|
|
|
* address of the connection must also match. INADDR_ANY is a
|
|
|
|
* special case: There can only be instance of a port number
|
|
|
|
* with INADDR_ANY.
|
|
|
|
*/
|
|
|
|
|
2021-03-31 12:11:19 +02:00
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
if (domain == PF_INET)
|
|
|
|
#endif /* CONFIG_NET_IPv6 */
|
2014-11-22 17:46:37 +01:00
|
|
|
{
|
2021-03-31 12:11:19 +02:00
|
|
|
if (net_ipv4addr_cmp(conn->u.ipv4.laddr, ipaddr->ipv4) ||
|
|
|
|
net_ipv4addr_cmp(conn->u.ipv4.laddr, INADDR_ANY))
|
|
|
|
{
|
|
|
|
/* The port number is in use, return the connection */
|
2014-11-22 14:14:17 +01:00
|
|
|
|
2021-03-31 12:11:19 +02:00
|
|
|
return conn;
|
|
|
|
}
|
2014-11-22 17:46:37 +01:00
|
|
|
}
|
2017-08-08 22:24:12 +02:00
|
|
|
#endif /* CONFIG_NET_IPv4 */
|
2015-01-18 00:07:54 +01:00
|
|
|
|
2017-08-08 22:24:12 +02:00
|
|
|
#ifdef CONFIG_NET_IPv6
|
2021-03-31 12:11:19 +02:00
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
else
|
|
|
|
#endif /* CONFIG_NET_IPv4 */
|
2015-01-18 00:07:54 +01:00
|
|
|
{
|
2021-03-31 12:11:19 +02:00
|
|
|
if (net_ipv6addr_cmp(conn->u.ipv6.laddr, ipaddr->ipv6) ||
|
|
|
|
net_ipv6addr_cmp(conn->u.ipv6.laddr, g_ipv6_unspecaddr))
|
|
|
|
{
|
|
|
|
/* The port number is in use, return the connection */
|
2015-01-18 00:07:54 +01:00
|
|
|
|
2021-03-31 12:11:19 +02:00
|
|
|
return conn;
|
|
|
|
}
|
2015-01-18 00:07:54 +01:00
|
|
|
}
|
2021-03-31 12:11:19 +02:00
|
|
|
#endif /* CONFIG_NET_IPv6 */
|
2015-01-18 00:07:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: tcp_ipv4_active
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Find a connection structure that is the appropriate
|
|
|
|
* connection to be used with the provided TCP/IP header
|
|
|
|
*
|
|
|
|
* Assumptions:
|
2020-02-23 09:50:23 +01:00
|
|
|
* This function is called from network logic with the network locked.
|
2015-01-18 00:07:54 +01:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
static inline FAR struct tcp_conn_s *
|
|
|
|
tcp_ipv4_active(FAR struct net_driver_s *dev, FAR struct tcp_hdr_s *tcp)
|
|
|
|
{
|
2015-01-18 15:56:05 +01:00
|
|
|
FAR struct ipv4_hdr_s *ip = IPv4BUF;
|
2015-01-18 00:07:54 +01:00
|
|
|
FAR struct tcp_conn_s *conn;
|
|
|
|
in_addr_t srcipaddr;
|
|
|
|
in_addr_t destipaddr;
|
|
|
|
|
|
|
|
conn = (FAR struct tcp_conn_s *)g_active_tcp_connections.head;
|
|
|
|
srcipaddr = net_ip4addr_conv32(ip->srcipaddr);
|
|
|
|
destipaddr = net_ip4addr_conv32(ip->destipaddr);
|
|
|
|
|
|
|
|
while (conn)
|
|
|
|
{
|
|
|
|
/* Find an open connection matching the TCP input. The following
|
|
|
|
* checks are performed:
|
|
|
|
*
|
|
|
|
* - The local port number is checked against the destination port
|
|
|
|
* number in the received packet.
|
|
|
|
* - The remote port number is checked if the connection is bound
|
|
|
|
* to a remote port.
|
2017-08-08 22:24:12 +02:00
|
|
|
* - Insist that the destination IP matches the bound address. If
|
|
|
|
* a socket is bound to INADDRY_ANY, then it should receive all
|
|
|
|
* packets directed to the port.
|
2015-01-18 00:07:54 +01:00
|
|
|
* - Finally, if the connection is bound to a remote IP address,
|
|
|
|
* the source IP address of the packet is checked.
|
|
|
|
*
|
|
|
|
* If all of the above are true then the newly received TCP packet
|
|
|
|
* is destined for this TCP connection.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (conn->tcpstateflags != TCP_CLOSED &&
|
|
|
|
tcp->destport == conn->lport &&
|
|
|
|
tcp->srcport == conn->rport &&
|
2015-05-29 23:16:11 +02:00
|
|
|
(net_ipv4addr_cmp(conn->u.ipv4.laddr, INADDR_ANY) ||
|
2015-01-18 00:07:54 +01:00
|
|
|
net_ipv4addr_cmp(destipaddr, conn->u.ipv4.laddr)) &&
|
|
|
|
net_ipv4addr_cmp(srcipaddr, conn->u.ipv4.raddr))
|
|
|
|
{
|
|
|
|
/* Matching connection found.. break out of the loop and return a
|
|
|
|
* reference to it.
|
|
|
|
*/
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Look at the next active connection */
|
|
|
|
|
2022-02-07 04:49:41 +01:00
|
|
|
conn = (FAR struct tcp_conn_s *)conn->sconn.node.flink;
|
2015-01-18 00:07:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_IPv4 */
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: tcp_ipv6_active
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Find a connection structure that is the appropriate
|
|
|
|
* connection to be used with the provided TCP/IP header
|
|
|
|
*
|
|
|
|
* Assumptions:
|
2018-10-30 01:00:30 +01:00
|
|
|
* This function is called from network logic with the network locked.
|
|
|
|
*
|
2015-01-18 00:07:54 +01:00
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
static inline FAR struct tcp_conn_s *
|
|
|
|
tcp_ipv6_active(FAR struct net_driver_s *dev, FAR struct tcp_hdr_s *tcp)
|
|
|
|
{
|
2015-01-18 15:56:05 +01:00
|
|
|
FAR struct ipv6_hdr_s *ip = IPv6BUF;
|
2015-01-18 00:07:54 +01:00
|
|
|
FAR struct tcp_conn_s *conn;
|
|
|
|
net_ipv6addr_t *srcipaddr;
|
2015-02-10 13:54:10 +01:00
|
|
|
net_ipv6addr_t *destipaddr;
|
2015-01-18 00:07:54 +01:00
|
|
|
|
|
|
|
conn = (FAR struct tcp_conn_s *)g_active_tcp_connections.head;
|
|
|
|
srcipaddr = (net_ipv6addr_t *)ip->srcipaddr;
|
|
|
|
destipaddr = (net_ipv6addr_t *)ip->destipaddr;
|
|
|
|
|
|
|
|
while (conn)
|
|
|
|
{
|
|
|
|
/* Find an open connection matching the TCP input. The following
|
|
|
|
* checks are performed:
|
|
|
|
*
|
|
|
|
* - The local port number is checked against the destination port
|
|
|
|
* number in the received packet.
|
|
|
|
* - The remote port number is checked if the connection is bound
|
|
|
|
* to a remote port.
|
2017-08-08 22:24:12 +02:00
|
|
|
* - Insist that the destination IP matches the bound address. If
|
2018-06-23 20:53:27 +02:00
|
|
|
* a socket is bound to the IPv6 unspecified address, then it
|
|
|
|
* should receive all packets directed to the port.
|
2015-01-18 00:07:54 +01:00
|
|
|
* - Finally, if the connection is bound to a remote IP address,
|
|
|
|
* the source IP address of the packet is checked.
|
|
|
|
*
|
|
|
|
* If all of the above are true then the newly received TCP packet
|
|
|
|
* is destined for this TCP connection.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (conn->tcpstateflags != TCP_CLOSED &&
|
|
|
|
tcp->destport == conn->lport &&
|
|
|
|
tcp->srcport == conn->rport &&
|
2018-06-23 20:53:27 +02:00
|
|
|
(net_ipv6addr_cmp(conn->u.ipv6.laddr, g_ipv6_unspecaddr) ||
|
2015-01-18 00:07:54 +01:00
|
|
|
net_ipv6addr_cmp(*destipaddr, conn->u.ipv6.laddr)) &&
|
|
|
|
net_ipv6addr_cmp(*srcipaddr, conn->u.ipv6.raddr))
|
|
|
|
{
|
|
|
|
/* Matching connection found.. break out of the loop and return a
|
|
|
|
* reference to it.
|
|
|
|
*/
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Look at the next active connection */
|
|
|
|
|
2022-02-07 04:49:41 +01:00
|
|
|
conn = (FAR struct tcp_conn_s *)conn->sconn.node.flink;
|
2015-01-18 00:07:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_IPv6 */
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: tcp_ipv4_bind
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* This function implements the lower level parts of the standard TCP
|
|
|
|
* bind() operation.
|
|
|
|
*
|
2018-02-01 17:00:02 +01:00
|
|
|
* Returned Value:
|
2015-01-18 00:07:54 +01:00
|
|
|
* 0 on success or -EADDRINUSE on failure
|
|
|
|
*
|
|
|
|
* Assumptions:
|
|
|
|
* This function is called from normal user level code.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
static inline int tcp_ipv4_bind(FAR struct tcp_conn_s *conn,
|
|
|
|
FAR const struct sockaddr_in *addr)
|
|
|
|
{
|
|
|
|
int port;
|
2015-05-30 17:12:27 +02:00
|
|
|
int ret;
|
2015-01-18 00:07:54 +01:00
|
|
|
|
|
|
|
/* Verify or select a local port and address */
|
|
|
|
|
2016-12-03 23:28:19 +01:00
|
|
|
net_lock();
|
2015-01-18 00:07:54 +01:00
|
|
|
|
2021-03-04 07:03:09 +01:00
|
|
|
/* Verify or select a local port (network byte order) */
|
2015-01-18 00:07:54 +01:00
|
|
|
|
|
|
|
port = tcp_selectport(PF_INET,
|
2015-02-10 01:15:34 +01:00
|
|
|
(FAR const union ip_addr_u *)&addr->sin_addr.s_addr,
|
2021-03-04 07:03:09 +01:00
|
|
|
addr->sin_port);
|
2015-01-18 00:07:54 +01:00
|
|
|
if (port < 0)
|
|
|
|
{
|
2016-06-12 01:37:21 +02:00
|
|
|
nerr("ERROR: tcp_selectport failed: %d\n", port);
|
2022-02-03 08:23:52 +01:00
|
|
|
net_unlock();
|
2015-01-18 00:07:54 +01:00
|
|
|
return port;
|
|
|
|
}
|
|
|
|
|
2020-05-04 19:34:04 +02:00
|
|
|
/* Save the local address in the connection structure (network order). */
|
2015-01-18 00:07:54 +01:00
|
|
|
|
2021-03-04 07:03:09 +01:00
|
|
|
conn->lport = port;
|
2015-02-10 01:15:34 +01:00
|
|
|
net_ipv4addr_copy(conn->u.ipv4.laddr, addr->sin_addr.s_addr);
|
2015-01-18 00:07:54 +01:00
|
|
|
|
2015-09-03 03:48:31 +02:00
|
|
|
/* Find the device that can receive packets on the network associated with
|
|
|
|
* this local address.
|
2015-05-30 17:12:27 +02:00
|
|
|
*/
|
|
|
|
|
2015-09-03 03:48:31 +02:00
|
|
|
ret = tcp_local_ipv4_device(conn);
|
2015-05-30 17:12:27 +02:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
/* If no device is found, then the address is not reachable */
|
|
|
|
|
2016-06-12 01:37:21 +02:00
|
|
|
nerr("ERROR: tcp_local_ipv4_device failed: %d\n", ret);
|
2015-05-30 17:12:27 +02:00
|
|
|
|
|
|
|
/* Back out the local address setting */
|
|
|
|
|
|
|
|
conn->lport = 0;
|
|
|
|
net_ipv4addr_copy(conn->u.ipv4.laddr, INADDR_ANY);
|
|
|
|
}
|
|
|
|
|
2016-12-03 23:28:19 +01:00
|
|
|
net_unlock();
|
2022-02-03 08:23:52 +01:00
|
|
|
return ret;
|
2015-01-18 00:07:54 +01:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_IPv4 */
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: tcp_ipv6_bind
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* This function implements the lower level parts of the standard TCP
|
|
|
|
* bind() operation.
|
|
|
|
*
|
2018-02-01 17:00:02 +01:00
|
|
|
* Returned Value:
|
2015-01-18 00:07:54 +01:00
|
|
|
* 0 on success or -EADDRINUSE on failure
|
|
|
|
*
|
|
|
|
* Assumptions:
|
|
|
|
* This function is called from normal user level code.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
static inline int tcp_ipv6_bind(FAR struct tcp_conn_s *conn,
|
|
|
|
FAR const struct sockaddr_in6 *addr)
|
|
|
|
{
|
|
|
|
int port;
|
2015-05-30 17:12:27 +02:00
|
|
|
int ret;
|
2015-01-18 00:07:54 +01:00
|
|
|
|
|
|
|
/* Verify or select a local port and address */
|
|
|
|
|
2016-12-03 23:28:19 +01:00
|
|
|
net_lock();
|
2015-01-18 00:07:54 +01:00
|
|
|
|
2021-03-04 07:03:09 +01:00
|
|
|
/* Verify or select a local port (network byte order) */
|
2015-01-18 00:07:54 +01:00
|
|
|
|
2015-02-10 13:54:10 +01:00
|
|
|
/* The port number must be unique for this address binding */
|
|
|
|
|
2015-01-18 00:07:54 +01:00
|
|
|
port = tcp_selectport(PF_INET6,
|
2020-05-04 19:34:04 +02:00
|
|
|
(FAR const union ip_addr_u *)addr->sin6_addr.in6_u.u6_addr16,
|
2021-03-04 07:03:09 +01:00
|
|
|
addr->sin6_port);
|
2015-01-18 00:07:54 +01:00
|
|
|
if (port < 0)
|
|
|
|
{
|
2016-06-12 01:37:21 +02:00
|
|
|
nerr("ERROR: tcp_selectport failed: %d\n", port);
|
2022-02-03 08:23:52 +01:00
|
|
|
net_unlock();
|
2015-01-18 00:07:54 +01:00
|
|
|
return port;
|
|
|
|
}
|
|
|
|
|
2020-05-04 19:34:04 +02:00
|
|
|
/* Save the local address in the connection structure (network order). */
|
2015-01-18 00:07:54 +01:00
|
|
|
|
2021-03-04 07:03:09 +01:00
|
|
|
conn->lport = port;
|
2015-01-18 00:07:54 +01:00
|
|
|
net_ipv6addr_copy(conn->u.ipv6.laddr, addr->sin6_addr.in6_u.u6_addr16);
|
|
|
|
|
2015-05-30 17:12:27 +02:00
|
|
|
/* Find the device that can receive packets on the network
|
|
|
|
* associated with this local address.
|
|
|
|
*/
|
|
|
|
|
2015-09-03 03:48:31 +02:00
|
|
|
ret = tcp_local_ipv6_device(conn);
|
2015-05-30 17:12:27 +02:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
/* If no device is found, then the address is not reachable */
|
|
|
|
|
2016-06-12 01:37:21 +02:00
|
|
|
nerr("ERROR: tcp_local_ipv6_device failed: %d\n", ret);
|
2015-05-30 17:12:27 +02:00
|
|
|
|
|
|
|
/* Back out the local address setting */
|
|
|
|
|
|
|
|
conn->lport = 0;
|
2018-06-23 20:53:27 +02:00
|
|
|
net_ipv6addr_copy(conn->u.ipv6.laddr, g_ipv6_unspecaddr);
|
2015-05-30 17:12:27 +02:00
|
|
|
}
|
|
|
|
|
2016-12-03 23:28:19 +01:00
|
|
|
net_unlock();
|
2022-02-03 08:23:52 +01:00
|
|
|
return ret;
|
2015-01-18 00:07:54 +01:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_IPv6 */
|
|
|
|
|
2021-12-31 08:19:48 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: tcp_alloc_conn
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Find or allocate a free TCP/IP connection structure for use.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2022-11-04 11:38:07 +01:00
|
|
|
#if CONFIG_NET_TCP_ALLOC_CONNS > 0
|
2021-12-31 08:19:48 +01:00
|
|
|
FAR struct tcp_conn_s *tcp_alloc_conn(void)
|
|
|
|
{
|
|
|
|
FAR struct tcp_conn_s *conn;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Return the entry from the head of the free list */
|
|
|
|
|
|
|
|
if (dq_peek(&g_free_tcp_connections) == NULL)
|
|
|
|
{
|
2022-11-04 11:38:07 +01:00
|
|
|
#if CONFIG_NET_TCP_MAX_CONNS > 0
|
|
|
|
if (dq_count(&g_active_tcp_connections) + CONFIG_NET_TCP_ALLOC_CONNS
|
|
|
|
>= CONFIG_NET_TCP_MAX_CONNS)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2021-12-31 08:19:48 +01:00
|
|
|
conn = kmm_zalloc(sizeof(struct tcp_conn_s) *
|
2022-11-04 11:38:07 +01:00
|
|
|
CONFIG_NET_TCP_ALLOC_CONNS);
|
2021-12-31 08:19:48 +01:00
|
|
|
if (conn == NULL)
|
|
|
|
{
|
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now initialize each connection structure */
|
|
|
|
|
2022-11-04 11:38:07 +01:00
|
|
|
for (i = 0; i < CONFIG_NET_TCP_ALLOC_CONNS; i++)
|
2021-12-31 08:19:48 +01:00
|
|
|
{
|
|
|
|
/* Mark the connection closed and move it to the free list */
|
|
|
|
|
|
|
|
conn[i].tcpstateflags = TCP_CLOSED;
|
2022-02-07 04:49:41 +01:00
|
|
|
dq_addlast(&conn[i].sconn.node, &g_free_tcp_connections);
|
2021-12-31 08:19:48 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (FAR struct tcp_conn_s *)dq_remfirst(&g_free_tcp_connections);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-09-02 23:58:35 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Public Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
2022-10-28 10:08:36 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: tcp_selectport
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* If the port number is zero; select an unused port for the connection.
|
|
|
|
* If the port number is non-zero, verify that no other connection has
|
|
|
|
* been created with this port number.
|
|
|
|
*
|
|
|
|
* Input Parameters:
|
|
|
|
* portno -- the selected port number in network order. Zero means no port
|
|
|
|
* selected.
|
|
|
|
*
|
|
|
|
* Returned Value:
|
|
|
|
* Selected or verified port number in network order on success, a negated
|
|
|
|
* errno on failure:
|
|
|
|
*
|
|
|
|
* EADDRINUSE
|
|
|
|
* The given address is already in use.
|
|
|
|
* EADDRNOTAVAIL
|
|
|
|
* Cannot assign requested address (unlikely)
|
|
|
|
*
|
|
|
|
* Assumptions:
|
|
|
|
* Interrupts are disabled
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
int tcp_selectport(uint8_t domain,
|
|
|
|
FAR const union ip_addr_u *ipaddr,
|
|
|
|
uint16_t portno)
|
|
|
|
{
|
|
|
|
static uint16_t g_last_tcp_port;
|
|
|
|
ssize_t ret;
|
|
|
|
|
|
|
|
/* Generate port base dynamically */
|
|
|
|
|
|
|
|
if (g_last_tcp_port == 0)
|
|
|
|
{
|
|
|
|
ret = getrandom(&g_last_tcp_port, sizeof(uint16_t), 0);
|
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
ret = getrandom(&g_last_tcp_port, sizeof(uint16_t), GRND_RANDOM);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret != sizeof(uint16_t))
|
|
|
|
{
|
|
|
|
g_last_tcp_port = clock_systime_ticks() % 32000;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_last_tcp_port = g_last_tcp_port % 32000;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_last_tcp_port < 4096)
|
|
|
|
{
|
|
|
|
g_last_tcp_port += 4096;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (portno == 0)
|
|
|
|
{
|
|
|
|
/* No local port assigned. Loop until we find a valid listen port
|
|
|
|
* number that is not being used by any other connection. NOTE the
|
|
|
|
* following loop is assumed to terminate but could not if all
|
|
|
|
* 32000-4096+1 ports are in used (unlikely).
|
|
|
|
*/
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
/* Guess that the next available port number will be the one after
|
|
|
|
* the last port number assigned. Make sure that the port number
|
|
|
|
* is within range.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (++g_last_tcp_port >= 32000)
|
|
|
|
{
|
|
|
|
g_last_tcp_port = 4096;
|
|
|
|
}
|
|
|
|
|
|
|
|
portno = HTONS(g_last_tcp_port);
|
|
|
|
}
|
|
|
|
while (tcp_listener(domain, ipaddr, portno)
|
|
|
|
#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4)
|
|
|
|
|| (domain == PF_INET &&
|
|
|
|
ipv4_nat_port_inuse(IP_PROTO_TCP, ipaddr->ipv4, portno))
|
|
|
|
#endif
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* A port number has been supplied. Verify that no other TCP/IP
|
|
|
|
* connection is using this local port.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (tcp_listener(domain, ipaddr, portno)
|
|
|
|
#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4)
|
|
|
|
|| (domain == PF_INET &&
|
|
|
|
ipv4_nat_port_inuse(IP_PROTO_TCP, ipaddr->ipv4, portno))
|
|
|
|
#endif
|
|
|
|
)
|
|
|
|
{
|
|
|
|
/* It is in use... return EADDRINUSE */
|
|
|
|
|
|
|
|
return -EADDRINUSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the selected or verified port number (host byte order) */
|
|
|
|
|
|
|
|
return portno;
|
|
|
|
}
|
|
|
|
|
2007-09-02 23:58:35 +02:00
|
|
|
/****************************************************************************
|
2015-01-15 22:06:46 +01:00
|
|
|
* Name: tcp_initialize
|
2007-09-02 23:58:35 +02:00
|
|
|
*
|
|
|
|
* Description:
|
2007-09-03 01:11:10 +02:00
|
|
|
* Initialize the TCP/IP connection structures. Called only once and only
|
2018-06-25 20:41:28 +02:00
|
|
|
* from the network layer at start-up.
|
2007-09-02 23:58:35 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2014-06-25 02:12:49 +02:00
|
|
|
void tcp_initialize(void)
|
2007-09-02 23:58:35 +02:00
|
|
|
{
|
2022-11-04 11:38:07 +01:00
|
|
|
#if CONFIG_NET_TCP_PREALLOC_CONNS > 0
|
2007-09-02 23:58:35 +02:00
|
|
|
int i;
|
2007-09-03 22:34:44 +02:00
|
|
|
|
2022-11-04 11:38:07 +01:00
|
|
|
for (i = 0; i < CONFIG_NET_TCP_PREALLOC_CONNS; i++)
|
2007-09-02 23:58:35 +02:00
|
|
|
{
|
2007-09-03 22:34:44 +02:00
|
|
|
/* Mark the connection closed and move it to the free list */
|
|
|
|
|
2014-07-07 00:10:26 +02:00
|
|
|
g_tcp_connections[i].tcpstateflags = TCP_CLOSED;
|
2022-02-07 04:49:41 +01:00
|
|
|
dq_addlast(&g_tcp_connections[i].sconn.node, &g_free_tcp_connections);
|
2007-09-02 23:58:35 +02:00
|
|
|
}
|
2021-12-31 08:19:48 +01:00
|
|
|
#endif
|
2007-09-02 23:58:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
2015-01-15 22:06:46 +01:00
|
|
|
* Name: tcp_alloc
|
2007-09-02 23:58:35 +02:00
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Find a free TCP/IP connection structure and allocate it
|
|
|
|
* for use. This is normally something done by the implementation of the
|
2018-07-05 18:54:45 +02:00
|
|
|
* socket() API but is also called from the event processing logic when a
|
2017-09-02 18:27:03 +02:00
|
|
|
* TCP packet is received while "listening"
|
2007-09-02 23:58:35 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2015-01-17 20:07:48 +01:00
|
|
|
FAR struct tcp_conn_s *tcp_alloc(uint8_t domain)
|
2007-09-02 23:58:35 +02:00
|
|
|
{
|
2014-06-25 02:12:49 +02:00
|
|
|
FAR struct tcp_conn_s *conn;
|
2007-09-02 23:58:35 +02:00
|
|
|
|
2017-09-02 18:27:03 +02:00
|
|
|
/* Because this routine is called from both event processing (with the
|
|
|
|
* network locked) and and from user level. Make sure that the network
|
|
|
|
* locked in any cased while accessing g_free_tcp_connections[];
|
2007-09-02 23:58:35 +02:00
|
|
|
*/
|
|
|
|
|
2016-12-03 23:28:19 +01:00
|
|
|
net_lock();
|
2007-09-02 23:58:35 +02:00
|
|
|
|
2007-09-03 22:34:44 +02:00
|
|
|
/* Return the entry from the head of the free list */
|
2007-09-02 23:58:35 +02:00
|
|
|
|
2014-06-25 02:12:49 +02:00
|
|
|
conn = (FAR struct tcp_conn_s *)dq_remfirst(&g_free_tcp_connections);
|
2007-09-02 23:58:35 +02:00
|
|
|
|
2014-06-02 15:48:05 +02:00
|
|
|
#ifndef CONFIG_NET_SOLINGER
|
2007-09-03 22:34:44 +02:00
|
|
|
/* Is the free list empty? */
|
|
|
|
|
|
|
|
if (!conn)
|
|
|
|
{
|
2020-05-04 19:34:04 +02:00
|
|
|
/* As a fall-back, check for connection structures which can be
|
|
|
|
* stalled.
|
2013-10-06 17:48:54 +02:00
|
|
|
* Search the active connection list for the oldest connection
|
2014-06-02 15:48:05 +02:00
|
|
|
* that is about to be closed anyway.
|
2007-09-02 23:58:35 +02:00
|
|
|
*/
|
|
|
|
|
2014-06-25 02:12:49 +02:00
|
|
|
FAR struct tcp_conn_s *tmp =
|
|
|
|
(FAR struct tcp_conn_s *)g_active_tcp_connections.head;
|
2013-11-29 00:47:03 +01:00
|
|
|
|
2007-09-03 22:34:44 +02:00
|
|
|
while (tmp)
|
2007-09-02 23:58:35 +02:00
|
|
|
{
|
2016-06-20 19:59:15 +02:00
|
|
|
ninfo("conn: %p state: %02x\n", tmp, tmp->tcpstateflags);
|
2013-10-06 17:48:54 +02:00
|
|
|
|
2014-06-02 15:48:05 +02:00
|
|
|
/* Is this connection in a state we can sacrifice. */
|
|
|
|
|
net/tcp: fix assertion of fallback connection alloc
When the free connection list is unenough to alloc a new instance,
the TCP stack will reuse the currently closed connection, but if
the handle is not released by the user via close(2), the reference
count of the connection remains in a non-zero value, it will cause
the assertion to fail, so when the handle is not released we should
not use such a conn instance when being actively closed, and ensure
that the reference count is assigned within the net lock protection
|(gdb) bt
|#0 up_assert (filename=0x565c78f7 "tcp/tcp_conn.c", lineno=771) at sim/up_assert.c:75
|#1 0x56566177 in _assert (filename=0x565c78f7 "tcp/tcp_conn.c", linenum=771) at assert/lib_assert.c:36
|#2 0x5657d620 in tcp_free (conn=0x565fb3e0 <g_tcp_connections>) at tcp/tcp_conn.c:771
|#3 0x5657d5a1 in tcp_alloc (domain=2 '\002') at tcp/tcp_conn.c:700
|#4 0x565b1f50 in inet_tcp_alloc (psock=0xf3dea150) at inet/inet_sockif.c:144
|#5 0x565b2082 in inet_setup (psock=0xf3dea150, protocol=0) at inet/inet_sockif.c:253
|#6 0x565b1bf0 in psock_socket (domain=2, type=1, protocol=0, psock=0xf3dea150) at socket/socket.c:121
|#7 0x56588f5f in socket (domain=2, type=1, protocol=0) at socket/socket.c:278
|#8 0x565b11c0 in hello_main (argc=1, argv=0xf3dfab10) at hello_main.c:35
|#9 0x56566631 in nxtask_startup (entrypt=0x565b10ef <hello_main>, argc=1, argv=0xf3dfab10) at sched/task_startup.c:70
|#10 0x565597fa in nxtask_start () at task/task_start.c:134
Signed-off-by: chao.an <anchao@xiaomi.com>
2022-07-08 21:30:10 +02:00
|
|
|
if ((tmp->crefs == 0) &&
|
|
|
|
(tmp->tcpstateflags == TCP_CLOSED ||
|
|
|
|
tmp->tcpstateflags == TCP_CLOSING ||
|
2014-07-07 00:10:26 +02:00
|
|
|
tmp->tcpstateflags == TCP_FIN_WAIT_1 ||
|
|
|
|
tmp->tcpstateflags == TCP_FIN_WAIT_2 ||
|
|
|
|
tmp->tcpstateflags == TCP_TIME_WAIT ||
|
net/tcp: fix assertion of fallback connection alloc
When the free connection list is unenough to alloc a new instance,
the TCP stack will reuse the currently closed connection, but if
the handle is not released by the user via close(2), the reference
count of the connection remains in a non-zero value, it will cause
the assertion to fail, so when the handle is not released we should
not use such a conn instance when being actively closed, and ensure
that the reference count is assigned within the net lock protection
|(gdb) bt
|#0 up_assert (filename=0x565c78f7 "tcp/tcp_conn.c", lineno=771) at sim/up_assert.c:75
|#1 0x56566177 in _assert (filename=0x565c78f7 "tcp/tcp_conn.c", linenum=771) at assert/lib_assert.c:36
|#2 0x5657d620 in tcp_free (conn=0x565fb3e0 <g_tcp_connections>) at tcp/tcp_conn.c:771
|#3 0x5657d5a1 in tcp_alloc (domain=2 '\002') at tcp/tcp_conn.c:700
|#4 0x565b1f50 in inet_tcp_alloc (psock=0xf3dea150) at inet/inet_sockif.c:144
|#5 0x565b2082 in inet_setup (psock=0xf3dea150, protocol=0) at inet/inet_sockif.c:253
|#6 0x565b1bf0 in psock_socket (domain=2, type=1, protocol=0, psock=0xf3dea150) at socket/socket.c:121
|#7 0x56588f5f in socket (domain=2, type=1, protocol=0) at socket/socket.c:278
|#8 0x565b11c0 in hello_main (argc=1, argv=0xf3dfab10) at hello_main.c:35
|#9 0x56566631 in nxtask_startup (entrypt=0x565b10ef <hello_main>, argc=1, argv=0xf3dfab10) at sched/task_startup.c:70
|#10 0x565597fa in nxtask_start () at task/task_start.c:134
Signed-off-by: chao.an <anchao@xiaomi.com>
2022-07-08 21:30:10 +02:00
|
|
|
tmp->tcpstateflags == TCP_LAST_ACK))
|
2007-09-02 23:58:35 +02:00
|
|
|
{
|
2013-10-06 17:48:54 +02:00
|
|
|
/* Yes.. Is it the oldest one we have seen so far? */
|
2007-09-03 22:34:44 +02:00
|
|
|
|
2022-05-17 12:23:00 +02:00
|
|
|
if (!conn || tmp->timer < conn->timer)
|
2007-09-03 22:34:44 +02:00
|
|
|
{
|
|
|
|
/* Yes.. remember it */
|
|
|
|
|
|
|
|
conn = tmp;
|
|
|
|
}
|
2007-09-02 23:58:35 +02:00
|
|
|
}
|
2007-09-03 22:34:44 +02:00
|
|
|
|
|
|
|
/* Look at the next active connection */
|
|
|
|
|
2022-02-07 04:49:41 +01:00
|
|
|
tmp = (FAR struct tcp_conn_s *)tmp->sconn.node.flink;
|
2007-09-02 23:58:35 +02:00
|
|
|
}
|
2007-09-03 22:34:44 +02:00
|
|
|
|
2013-10-06 17:48:54 +02:00
|
|
|
/* Did we find a connection that we can re-use? */
|
2007-09-03 22:34:44 +02:00
|
|
|
|
2013-10-06 17:48:54 +02:00
|
|
|
if (conn != NULL)
|
|
|
|
{
|
2016-06-20 17:37:08 +02:00
|
|
|
nwarn("WARNING: Closing unestablished connection: %p\n", conn);
|
2013-10-06 17:48:54 +02:00
|
|
|
|
|
|
|
/* Yes... free it. This will remove the connection from the list
|
|
|
|
* of active connections and release all resources held by the
|
|
|
|
* connection.
|
|
|
|
*
|
|
|
|
* REVISIT: Could there be any higher level, socket interface
|
|
|
|
* that needs to be informed that we did this to them?
|
2014-06-02 15:48:05 +02:00
|
|
|
*
|
|
|
|
* Actually yes. When CONFIG_NET_SOLINGER is enabled there is a
|
|
|
|
* pending callback in netclose_disconnect waiting for getting
|
|
|
|
* woken up. Otherwise there's the callback too, but no one is
|
|
|
|
* waiting for it.
|
2013-10-06 17:48:54 +02:00
|
|
|
*/
|
|
|
|
|
2014-06-25 02:12:49 +02:00
|
|
|
tcp_free(conn);
|
2013-10-06 17:48:54 +02:00
|
|
|
|
2022-11-04 11:38:07 +01:00
|
|
|
/* Now there should be one free connection. If dynamic connections
|
|
|
|
* allocation is disabled, it is guaranteed so. In case that
|
|
|
|
* dynamic connections are used, it may be already in the free
|
|
|
|
* list, or at least there should be enough space in the heap for
|
|
|
|
* a new connection.
|
|
|
|
*/
|
2013-10-06 17:48:54 +02:00
|
|
|
|
2019-03-11 19:48:17 +01:00
|
|
|
conn = (FAR struct tcp_conn_s *)
|
|
|
|
dq_remfirst(&g_free_tcp_connections);
|
2013-10-06 17:48:54 +02:00
|
|
|
}
|
2007-09-02 23:58:35 +02:00
|
|
|
}
|
2014-06-02 15:48:05 +02:00
|
|
|
#endif
|
2007-09-02 23:58:35 +02:00
|
|
|
|
2021-12-31 08:19:48 +01:00
|
|
|
/* Allocate the connect entry from heap */
|
|
|
|
|
2022-11-04 11:38:07 +01:00
|
|
|
#if CONFIG_NET_TCP_ALLOC_CONNS > 0
|
2021-12-31 08:19:48 +01:00
|
|
|
if (conn == NULL)
|
|
|
|
{
|
|
|
|
conn = tcp_alloc_conn();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-12-03 23:28:19 +01:00
|
|
|
net_unlock();
|
2007-09-03 22:34:44 +02:00
|
|
|
|
|
|
|
/* Mark the connection allocated */
|
|
|
|
|
|
|
|
if (conn)
|
|
|
|
{
|
2014-06-25 02:12:49 +02:00
|
|
|
memset(conn, 0, sizeof(struct tcp_conn_s));
|
2014-07-07 00:10:26 +02:00
|
|
|
conn->tcpstateflags = TCP_ALLOCATED;
|
2015-01-17 21:13:56 +01:00
|
|
|
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
|
2015-01-17 20:07:48 +01:00
|
|
|
conn->domain = domain;
|
2018-03-12 17:59:46 +01:00
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_NET_TCP_KEEPALIVE
|
|
|
|
conn->keepidle = 2 * DSEC_PER_HOUR;
|
|
|
|
conn->keepintvl = 2 * DSEC_PER_SEC;
|
|
|
|
conn->keepcnt = 3;
|
2021-07-05 10:01:48 +02:00
|
|
|
#endif
|
|
|
|
#if CONFIG_NET_RECV_BUFSIZE > 0
|
|
|
|
conn->rcv_bufs = CONFIG_NET_RECV_BUFSIZE;
|
2021-07-19 15:45:46 +02:00
|
|
|
#endif
|
|
|
|
#if CONFIG_NET_SEND_BUFSIZE > 0
|
|
|
|
conn->snd_bufs = CONFIG_NET_SEND_BUFSIZE;
|
|
|
|
|
|
|
|
nxsem_init(&conn->snd_sem, 0, 0);
|
2015-01-17 21:13:56 +01:00
|
|
|
#endif
|
2007-09-03 22:34:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return conn;
|
2007-09-02 23:58:35 +02:00
|
|
|
}
|
|
|
|
|
2023-01-03 13:16:07 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: tcp_free_rx_buffers
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Free rx buffer of a connection
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void tcp_free_rx_buffers(FAR struct tcp_conn_s *conn)
|
|
|
|
{
|
|
|
|
/* Release any read-ahead buffers attached to the connection */
|
|
|
|
|
|
|
|
iob_free_chain(conn->readahead);
|
|
|
|
conn->readahead = NULL;
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_TCP_OUT_OF_ORDER
|
|
|
|
/* Release any out-of-order buffers */
|
|
|
|
|
|
|
|
if (conn->nofosegs > 0)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < conn->nofosegs; i++)
|
|
|
|
{
|
|
|
|
iob_free_chain(conn->ofosegs[i].data);
|
|
|
|
}
|
|
|
|
|
|
|
|
conn->nofosegs = 0;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_TCP_OUT_OF_ORDER */
|
|
|
|
}
|
|
|
|
|
2007-09-02 23:58:35 +02:00
|
|
|
/****************************************************************************
|
2015-01-15 22:06:46 +01:00
|
|
|
* Name: tcp_free
|
2007-09-02 23:58:35 +02:00
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Free a connection structure that is no longer in use. This should be
|
|
|
|
* done by the implementation of close()
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2014-06-25 02:12:49 +02:00
|
|
|
void tcp_free(FAR struct tcp_conn_s *conn)
|
2007-09-02 23:58:35 +02:00
|
|
|
{
|
2014-06-29 20:59:34 +02:00
|
|
|
FAR struct devif_callback_s *cb;
|
|
|
|
FAR struct devif_callback_s *next;
|
2014-01-14 00:26:11 +01:00
|
|
|
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
2014-06-21 23:23:39 +02:00
|
|
|
FAR struct tcp_wrbuffer_s *wrbuffer;
|
2007-11-20 00:35:42 +01:00
|
|
|
#endif
|
2007-09-03 22:34:44 +02:00
|
|
|
|
2017-09-02 18:27:03 +02:00
|
|
|
/* Because g_free_tcp_connections is accessed from user level and event
|
2019-07-28 15:39:55 +02:00
|
|
|
* processing logic, it is necessary to keep the network locked during this
|
2007-09-03 22:34:44 +02:00
|
|
|
* operation.
|
|
|
|
*/
|
|
|
|
|
2016-12-03 23:28:19 +01:00
|
|
|
net_lock();
|
2007-09-03 22:34:44 +02:00
|
|
|
|
net/tcp: fix assertion of fallback connection alloc
When the free connection list is unenough to alloc a new instance,
the TCP stack will reuse the currently closed connection, but if
the handle is not released by the user via close(2), the reference
count of the connection remains in a non-zero value, it will cause
the assertion to fail, so when the handle is not released we should
not use such a conn instance when being actively closed, and ensure
that the reference count is assigned within the net lock protection
|(gdb) bt
|#0 up_assert (filename=0x565c78f7 "tcp/tcp_conn.c", lineno=771) at sim/up_assert.c:75
|#1 0x56566177 in _assert (filename=0x565c78f7 "tcp/tcp_conn.c", linenum=771) at assert/lib_assert.c:36
|#2 0x5657d620 in tcp_free (conn=0x565fb3e0 <g_tcp_connections>) at tcp/tcp_conn.c:771
|#3 0x5657d5a1 in tcp_alloc (domain=2 '\002') at tcp/tcp_conn.c:700
|#4 0x565b1f50 in inet_tcp_alloc (psock=0xf3dea150) at inet/inet_sockif.c:144
|#5 0x565b2082 in inet_setup (psock=0xf3dea150, protocol=0) at inet/inet_sockif.c:253
|#6 0x565b1bf0 in psock_socket (domain=2, type=1, protocol=0, psock=0xf3dea150) at socket/socket.c:121
|#7 0x56588f5f in socket (domain=2, type=1, protocol=0) at socket/socket.c:278
|#8 0x565b11c0 in hello_main (argc=1, argv=0xf3dfab10) at hello_main.c:35
|#9 0x56566631 in nxtask_startup (entrypt=0x565b10ef <hello_main>, argc=1, argv=0xf3dfab10) at sched/task_startup.c:70
|#10 0x565597fa in nxtask_start () at task/task_start.c:134
Signed-off-by: chao.an <anchao@xiaomi.com>
2022-07-08 21:30:10 +02:00
|
|
|
DEBUGASSERT(conn->crefs == 0);
|
|
|
|
|
net/tcp: use independent work to free the conn instance
I noticed that the conn instance will leak during stress test,
The close work queued from tcp_close_eventhandler() will be canceled
by tcp_timer() immediately:
Breakpoint 1, tcp_close_eventhandler (dev=0x565cd338 <up_irq_restore+108>, pvpriv=0x5655e6ff <getpid+12>, flags=0) at tcp/tcp_close.c:71
(gdb) bt
| #0 tcp_close_eventhandler (dev=0x565cd338 <up_irq_restore+108>, pvpriv=0x5655e6ff <getpid+12>, flags=0) at tcp/tcp_close.c:71
| #1 0x5658bf1e in devif_conn_event (dev=0x5660bd80 <g_sim_dev>, flags=512, list=0x5660d558 <g_cbprealloc+312>) at devif/devif_callback.c:508
| #2 0x5658a219 in tcp_callback (dev=0x5660bd80 <g_sim_dev>, conn=0x5660c4a0 <g_tcp_connections>, flags=512) at tcp/tcp_callback.c:167
| #3 0x56589253 in tcp_timer (dev=0x5660bd80 <g_sim_dev>, conn=0x5660c4a0 <g_tcp_connections>) at tcp/tcp_timer.c:378
| #4 0x5658dd47 in tcp_poll (dev=0x5660bd80 <g_sim_dev>, conn=0x5660c4a0 <g_tcp_connections>) at tcp/tcp_devpoll.c:95
| #5 0x5658b95f in devif_poll_tcp_connections (dev=0x5660bd80 <g_sim_dev>, callback=0x565770f2 <netdriver_txpoll>) at devif/devif_poll.c:601
| #6 0x5658b9ea in devif_poll (dev=0x5660bd80 <g_sim_dev>, callback=0x565770f2 <netdriver_txpoll>) at devif/devif_poll.c:722
| #7 0x56577230 in netdriver_txavail_work (arg=0x5660bd80 <g_sim_dev>) at sim/up_netdriver.c:308
| #8 0x5655999e in work_thread (argc=2, argv=0xf3db5dd0) at wqueue/kwork_thread.c:178
| #9 0x5655983f in nxtask_start () at task/task_start.c:129
(gdb) c
Continuing.
Breakpoint 2, tcp_update_timer (conn=0x5660c4a0 <g_tcp_connections>) at tcp/tcp_timer.c:178
(gdb) bt
| #0 tcp_update_timer (conn=0x5660c4a0 <g_tcp_connections>) at tcp/tcp_timer.c:178
| #1 0x5658952a in tcp_timer (dev=0x5660bd80 <g_sim_dev>, conn=0x5660c4a0 <g_tcp_connections>) at tcp/tcp_timer.c:708
| #2 0x5658dd47 in tcp_poll (dev=0x5660bd80 <g_sim_dev>, conn=0x5660c4a0 <g_tcp_connections>) at tcp/tcp_devpoll.c:95
| #3 0x5658b95f in devif_poll_tcp_connections (dev=0x5660bd80 <g_sim_dev>, callback=0x565770f2 <netdriver_txpoll>) at devif/devif_poll.c:601
| #4 0x5658b9ea in devif_poll (dev=0x5660bd80 <g_sim_dev>, callback=0x565770f2 <netdriver_txpoll>) at devif/devif_poll.c:722
| #5 0x56577230 in netdriver_txavail_work (arg=0x5660bd80 <g_sim_dev>) at sim/up_netdriver.c:308
| #6 0x5655999e in work_thread (argc=2, argv=0xf3db5dd0) at wqueue/kwork_thread.c:178
| #7 0x5655983f in nxtask_start () at task/task_start.c:129
Since a separate work will add 24 bytes to each conn instance,
but in order to support the feature of asynchronous close(),
I can not find a better way than adding a separate work,
for resource constraints, I recommend the developers to enable
CONFIG_NET_ALLOC_CONNS, which will reduce the ram usage.
Signed-off-by: chao an <anchao@xiaomi.com>
2022-08-30 05:04:31 +02:00
|
|
|
/* Cancel close work */
|
|
|
|
|
|
|
|
work_cancel(LPWORK, &conn->clswork);
|
|
|
|
|
|
|
|
/* Cancel tcp timer */
|
|
|
|
|
2022-04-25 17:08:24 +02:00
|
|
|
tcp_stop_timer(conn);
|
|
|
|
|
2021-06-29 12:18:00 +02:00
|
|
|
/* Free remaining callbacks, actually there should be only the send
|
|
|
|
* callback for CONFIG_NET_TCP_WRITE_BUFFERS is left.
|
2013-10-08 17:14:27 +02:00
|
|
|
*/
|
2013-10-06 17:48:54 +02:00
|
|
|
|
2022-02-07 04:49:41 +01:00
|
|
|
for (cb = conn->sconn.list; cb; cb = next)
|
2013-10-06 17:48:54 +02:00
|
|
|
{
|
2015-05-28 20:01:38 +02:00
|
|
|
next = cb->nxtconn;
|
2014-06-29 02:36:09 +02:00
|
|
|
tcp_callback_free(conn, cb);
|
2013-10-06 17:48:54 +02:00
|
|
|
}
|
|
|
|
|
2014-07-07 00:10:26 +02:00
|
|
|
/* TCP_ALLOCATED means that that the connection is not in the active list
|
2007-09-03 22:34:44 +02:00
|
|
|
* yet.
|
|
|
|
*/
|
|
|
|
|
2014-07-07 00:10:26 +02:00
|
|
|
if (conn->tcpstateflags != TCP_ALLOCATED)
|
2007-09-03 22:34:44 +02:00
|
|
|
{
|
|
|
|
/* Remove the connection from the active list */
|
|
|
|
|
2022-02-07 04:49:41 +01:00
|
|
|
dq_rem(&conn->sconn.node, &g_active_tcp_connections);
|
2007-09-03 22:34:44 +02:00
|
|
|
}
|
|
|
|
|
2023-01-03 13:16:07 +01:00
|
|
|
tcp_free_rx_buffers(conn);
|
2023-01-06 08:30:58 +01:00
|
|
|
|
2014-01-14 00:26:11 +01:00
|
|
|
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
|
|
|
/* Release any write buffers attached to the connection */
|
|
|
|
|
2019-03-11 19:48:17 +01:00
|
|
|
while ((wrbuffer = (struct tcp_wrbuffer_s *)
|
|
|
|
sq_remfirst(&conn->write_q)) != NULL)
|
2014-01-14 00:26:11 +01:00
|
|
|
{
|
2014-06-21 23:23:39 +02:00
|
|
|
tcp_wrbuffer_release(wrbuffer);
|
2014-01-14 00:26:11 +01:00
|
|
|
}
|
|
|
|
|
2019-03-11 19:48:17 +01:00
|
|
|
while ((wrbuffer = (struct tcp_wrbuffer_s *)
|
|
|
|
sq_remfirst(&conn->unacked_q)) != NULL)
|
2014-01-14 00:26:11 +01:00
|
|
|
{
|
2014-06-21 23:23:39 +02:00
|
|
|
tcp_wrbuffer_release(wrbuffer);
|
2014-01-14 00:26:11 +01:00
|
|
|
}
|
2021-07-19 15:45:46 +02:00
|
|
|
|
|
|
|
#if CONFIG_NET_SEND_BUFSIZE > 0
|
|
|
|
/* Notify the send buffer available */
|
|
|
|
|
|
|
|
tcp_sendbuffer_notify(conn);
|
|
|
|
#endif /* CONFIG_NET_SEND_BUFSIZE */
|
|
|
|
|
2014-01-14 00:26:11 +01:00
|
|
|
#endif
|
2008-11-20 20:24:06 +01:00
|
|
|
|
|
|
|
#ifdef CONFIG_NET_TCPBACKLOG
|
2014-01-14 00:26:11 +01:00
|
|
|
/* Remove any backlog attached to this connection */
|
|
|
|
|
2008-11-20 20:24:06 +01:00
|
|
|
if (conn->backlog)
|
|
|
|
{
|
2014-06-25 02:12:49 +02:00
|
|
|
tcp_backlogdestroy(conn);
|
2008-11-20 20:24:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If this connection is, itself, backlogged, then remove it from the
|
|
|
|
* parent connection's backlog list.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (conn->blparent)
|
|
|
|
{
|
2014-06-25 02:12:49 +02:00
|
|
|
tcp_backlogdelete(conn->blparent, conn);
|
2008-11-20 20:24:06 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2022-11-04 11:38:07 +01:00
|
|
|
/* Mark the connection available. */
|
2007-09-02 23:58:35 +02:00
|
|
|
|
2014-07-07 00:10:26 +02:00
|
|
|
conn->tcpstateflags = TCP_CLOSED;
|
2022-11-04 11:38:07 +01:00
|
|
|
|
|
|
|
/* If this is a preallocated or a batch allocated connection store it in
|
|
|
|
* the free connections list. Else free it.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#if CONFIG_NET_TCP_ALLOC_CONNS == 1
|
|
|
|
if (conn < g_tcp_connections || conn >= (g_tcp_connections +
|
|
|
|
CONFIG_NET_TCP_PREALLOC_CONNS))
|
|
|
|
{
|
|
|
|
kmm_free(conn);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
dq_addlast(&conn->sconn.node, &g_free_tcp_connections);
|
|
|
|
}
|
|
|
|
|
2016-12-03 23:28:19 +01:00
|
|
|
net_unlock();
|
2007-09-02 23:58:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
2015-01-15 22:06:46 +01:00
|
|
|
* Name: tcp_active
|
2007-09-02 23:58:35 +02:00
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Find a connection structure that is the appropriate
|
2009-09-11 20:21:57 +02:00
|
|
|
* connection to be used with the provided TCP/IP header
|
2007-09-02 23:58:35 +02:00
|
|
|
*
|
|
|
|
* Assumptions:
|
2020-02-23 09:50:23 +01:00
|
|
|
* This function is called from network logic with the network locked.
|
2007-09-02 23:58:35 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2015-01-15 22:06:46 +01:00
|
|
|
FAR struct tcp_conn_s *tcp_active(FAR struct net_driver_s *dev,
|
|
|
|
FAR struct tcp_hdr_s *tcp)
|
2007-09-02 23:58:35 +02:00
|
|
|
{
|
2015-01-18 00:07:54 +01:00
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
if (IFF_IS_IPv6(dev->d_flags))
|
2014-11-22 17:46:37 +01:00
|
|
|
#endif
|
2007-09-02 23:58:35 +02:00
|
|
|
{
|
2015-01-18 00:07:54 +01:00
|
|
|
return tcp_ipv6_active(dev, tcp);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_IPv6 */
|
2007-09-02 23:58:35 +02:00
|
|
|
|
2015-01-18 00:07:54 +01:00
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
else
|
2014-11-22 17:46:37 +01:00
|
|
|
#endif
|
2015-01-18 00:07:54 +01:00
|
|
|
{
|
|
|
|
return tcp_ipv4_active(dev, tcp);
|
2007-09-02 23:58:35 +02:00
|
|
|
}
|
2015-01-18 00:07:54 +01:00
|
|
|
#endif /* CONFIG_NET_IPv4 */
|
2007-09-03 22:34:44 +02:00
|
|
|
}
|
2007-09-03 01:11:10 +02:00
|
|
|
|
2007-11-06 00:04:16 +01:00
|
|
|
/****************************************************************************
|
2015-01-15 22:06:46 +01:00
|
|
|
* Name: tcp_nextconn
|
2007-11-06 00:04:16 +01:00
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Traverse the list of active TCP connections
|
|
|
|
*
|
|
|
|
* Assumptions:
|
2020-02-23 09:50:23 +01:00
|
|
|
* This function is called from network logic with the network locked.
|
2007-11-06 00:04:16 +01:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2014-07-01 02:03:58 +02:00
|
|
|
FAR struct tcp_conn_s *tcp_nextconn(FAR struct tcp_conn_s *conn)
|
2007-11-06 00:04:16 +01:00
|
|
|
{
|
|
|
|
if (!conn)
|
|
|
|
{
|
2014-06-25 02:12:49 +02:00
|
|
|
return (FAR struct tcp_conn_s *)g_active_tcp_connections.head;
|
2007-11-06 00:04:16 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-02-07 04:49:41 +01:00
|
|
|
return (FAR struct tcp_conn_s *)conn->sconn.node.flink;
|
2007-11-06 00:04:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-23 22:45:30 +02:00
|
|
|
/****************************************************************************
|
2015-01-15 22:06:46 +01:00
|
|
|
* Name: tcp_alloc_accept
|
2007-09-03 22:34:44 +02:00
|
|
|
*
|
|
|
|
* Description:
|
2017-09-02 18:27:03 +02:00
|
|
|
* Called when driver event processing matches the incoming packet
|
2014-07-03 01:23:25 +02:00
|
|
|
* with a connection in LISTEN. In that case, this function will create
|
|
|
|
* a new connection and initialize it to send a SYNACK in return.
|
2007-09-03 22:34:44 +02:00
|
|
|
*
|
|
|
|
* Assumptions:
|
2020-02-23 09:50:23 +01:00
|
|
|
* This function is called from network logic with the network locked.
|
2007-09-03 22:34:44 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2014-11-15 20:13:23 +01:00
|
|
|
FAR struct tcp_conn_s *tcp_alloc_accept(FAR struct net_driver_s *dev,
|
2015-01-15 22:06:46 +01:00
|
|
|
FAR struct tcp_hdr_s *tcp)
|
2007-09-03 22:34:44 +02:00
|
|
|
{
|
2015-01-15 22:06:46 +01:00
|
|
|
FAR struct tcp_conn_s *conn;
|
2015-01-18 00:07:54 +01:00
|
|
|
uint8_t domain;
|
2015-05-30 17:12:27 +02:00
|
|
|
int ret;
|
2015-01-15 22:06:46 +01:00
|
|
|
|
2015-01-18 00:07:54 +01:00
|
|
|
/* Get the appropriate IP domain */
|
|
|
|
|
2017-09-13 21:04:26 +02:00
|
|
|
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
|
2015-01-18 00:07:54 +01:00
|
|
|
bool ipv6 = IFF_IS_IPv6(dev->d_flags);
|
|
|
|
domain = ipv6 ? PF_INET6 : PF_INET;
|
|
|
|
#elif defined(CONFIG_NET_IPv4)
|
|
|
|
domain = PF_INET;
|
|
|
|
#else /* defined(CONFIG_NET_IPv6) */
|
|
|
|
domain = PF_INET6;
|
2015-01-17 20:07:48 +01:00
|
|
|
#endif
|
2015-01-18 00:07:54 +01:00
|
|
|
|
|
|
|
/* Allocate the connection structure */
|
|
|
|
|
|
|
|
conn = tcp_alloc(domain);
|
2007-09-03 22:34:44 +02:00
|
|
|
if (conn)
|
|
|
|
{
|
2015-05-30 17:12:27 +02:00
|
|
|
/* Set up the local address (laddr) and the remote address (raddr)
|
|
|
|
* that describes the TCP connection.
|
|
|
|
*/
|
2015-01-18 00:07:54 +01:00
|
|
|
|
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
if (ipv6)
|
|
|
|
#endif
|
|
|
|
{
|
2015-01-18 15:56:05 +01:00
|
|
|
FAR struct ipv6_hdr_s *ip = IPv6BUF;
|
2015-01-18 00:07:54 +01:00
|
|
|
|
2015-05-30 17:12:27 +02:00
|
|
|
/* Set the IPv6 specific MSS and the IPv6 locally bound address */
|
|
|
|
|
2015-01-18 00:07:54 +01:00
|
|
|
conn->mss = TCP_IPv6_INITIAL_MSS(dev);
|
|
|
|
net_ipv6addr_copy(conn->u.ipv6.raddr, ip->srcipaddr);
|
|
|
|
net_ipv6addr_copy(conn->u.ipv6.laddr, ip->destipaddr);
|
2015-08-27 17:06:46 +02:00
|
|
|
|
|
|
|
/* We now have to filter all outgoing transfers so that they use
|
|
|
|
* only the MSS of this device.
|
|
|
|
*/
|
|
|
|
|
|
|
|
DEBUGASSERT(conn->dev == NULL || conn->dev == dev);
|
|
|
|
conn->dev = dev;
|
2015-05-30 17:12:27 +02:00
|
|
|
|
|
|
|
/* Find the device that can receive packets on the network
|
|
|
|
* associated with this local address.
|
|
|
|
*/
|
|
|
|
|
2015-09-03 03:48:31 +02:00
|
|
|
ret = tcp_remote_ipv6_device(conn);
|
2015-01-18 00:07:54 +01:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_IPv6 */
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
else
|
2014-11-22 17:46:37 +01:00
|
|
|
#endif
|
2015-01-18 00:07:54 +01:00
|
|
|
{
|
2015-01-18 15:56:05 +01:00
|
|
|
FAR struct ipv4_hdr_s *ip = IPv4BUF;
|
2015-01-18 00:07:54 +01:00
|
|
|
|
2015-09-03 03:48:31 +02:00
|
|
|
/* Set the IPv6 specific MSS and the IPv4 bound remote address. */
|
2015-05-30 17:12:27 +02:00
|
|
|
|
2015-01-18 00:07:54 +01:00
|
|
|
conn->mss = TCP_IPv4_INITIAL_MSS(dev);
|
|
|
|
net_ipv4addr_copy(conn->u.ipv4.raddr,
|
|
|
|
net_ip4addr_conv32(ip->srcipaddr));
|
2015-09-03 03:48:31 +02:00
|
|
|
|
|
|
|
/* Set the local address as well */
|
|
|
|
|
2015-01-18 00:07:54 +01:00
|
|
|
net_ipv4addr_copy(conn->u.ipv4.laddr,
|
|
|
|
net_ip4addr_conv32(ip->destipaddr));
|
2015-08-27 17:06:46 +02:00
|
|
|
|
|
|
|
/* We now have to filter all outgoing transfers so that they use
|
|
|
|
* only the MSS of this device.
|
|
|
|
*/
|
|
|
|
|
|
|
|
DEBUGASSERT(conn->dev == NULL || conn->dev == dev);
|
|
|
|
conn->dev = dev;
|
2015-05-30 17:12:27 +02:00
|
|
|
|
|
|
|
/* Find the device that can receive packets on the network
|
|
|
|
* associated with this local address.
|
|
|
|
*/
|
|
|
|
|
2015-09-03 03:48:31 +02:00
|
|
|
ret = tcp_remote_ipv4_device(conn);
|
2015-01-18 00:07:54 +01:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_IPv4 */
|
|
|
|
|
2015-05-30 17:12:27 +02:00
|
|
|
/* Verify that a network device that can provide packets to this
|
|
|
|
* local address was found.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
/* If no device is found, then the address is not reachable.
|
|
|
|
* That should be impossible in this context and we should
|
|
|
|
* probably really just assert here.
|
|
|
|
*/
|
|
|
|
|
2016-06-12 01:37:21 +02:00
|
|
|
nerr("ERROR: Failed to find network device: %d\n", ret);
|
2015-05-30 17:12:27 +02:00
|
|
|
tcp_free(conn);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Fill in the necessary fields for the new connection. */
|
|
|
|
|
|
|
|
conn->rto = TCP_RTO;
|
|
|
|
conn->sa = 0;
|
|
|
|
conn->sv = 4;
|
|
|
|
conn->nrtx = 0;
|
|
|
|
conn->lport = tcp->destport;
|
|
|
|
conn->rport = tcp->srcport;
|
2014-07-07 00:10:26 +02:00
|
|
|
conn->tcpstateflags = TCP_SYN_RCVD;
|
2007-09-03 22:34:44 +02:00
|
|
|
|
2014-06-25 02:12:49 +02:00
|
|
|
tcp_initsequence(conn->sndseq);
|
2022-11-02 17:40:08 +01:00
|
|
|
#if !defined(CONFIG_NET_TCP_WRITE_BUFFERS)
|
|
|
|
conn->rexmit_seq = tcp_getsequence(conn->sndseq);
|
|
|
|
#endif
|
|
|
|
|
2019-12-08 20:13:51 +01:00
|
|
|
conn->tx_unacked = 1;
|
2014-01-14 00:26:11 +01:00
|
|
|
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
While working with version 7.10 I discovered a problem in TCP stack that could be observed on high network load. Generally speaking, the problem is that RST flag is set in unnecessary case, in which between loss of some TCP packet and its proper retransmission, another packets had been successfully sent. The scenario is as follows: NuttX did not receive ACK for some sent packet, so it has been probably lost somewhere. But before its retransmission starts, NuttX is correctly issuing next TCP packets, with sequence numbers increasing properly. When the retransmission of previously lost packet finally succeeds, tcp_input receives the accumulated ACK value, which acknowledges also the packets sent in the meantime (i.e. between unsuccessful sending of lost packet and its proper retransmission). However, variable unackseq is still set to conn->isn + conn->sent, which is truth only if no further packets transmission occurred in the meantime. Because of incorrect (in such specific case) unackseq value, few lines further condition if (ackseq <= unackseq)is not met, and, as a result, we are going to reset label.
2016-06-20 14:55:29 +02:00
|
|
|
conn->expired = 0;
|
|
|
|
conn->isn = 0;
|
|
|
|
conn->sent = 0;
|
|
|
|
conn->sndseq_max = 0;
|
2014-01-14 00:26:11 +01:00
|
|
|
#endif
|
2007-09-03 22:34:44 +02:00
|
|
|
|
2010-11-27 02:01:26 +01:00
|
|
|
/* rcvseq should be the seqno from the incoming packet + 1. */
|
2007-09-03 22:34:44 +02:00
|
|
|
|
2015-01-15 22:06:46 +01:00
|
|
|
memcpy(conn->rcvseq, tcp->seqno, 4);
|
2021-06-01 09:57:00 +02:00
|
|
|
conn->rcv_adv = tcp_getsequence(conn->rcvseq);
|
2007-11-16 19:48:39 +01:00
|
|
|
|
2007-11-20 00:09:39 +01:00
|
|
|
/* Initialize the list of TCP read-ahead buffers */
|
|
|
|
|
2021-06-18 07:34:21 +02:00
|
|
|
conn->readahead = NULL;
|
2007-11-20 00:09:39 +01:00
|
|
|
|
2014-01-14 00:26:11 +01:00
|
|
|
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
|
|
|
/* Initialize the write buffer lists */
|
|
|
|
|
|
|
|
sq_init(&conn->write_q);
|
|
|
|
sq_init(&conn->unacked_q);
|
|
|
|
#endif
|
|
|
|
|
2007-11-16 19:48:39 +01:00
|
|
|
/* And, finally, put the connection structure into the active list.
|
|
|
|
* Interrupts should already be disabled in this context.
|
|
|
|
*/
|
|
|
|
|
2022-02-07 04:49:41 +01:00
|
|
|
dq_addlast(&conn->sconn.node, &g_active_tcp_connections);
|
2022-04-25 17:08:24 +02:00
|
|
|
tcp_update_retrantimer(conn, TCP_RTO);
|
2007-11-20 00:09:39 +01:00
|
|
|
}
|
2013-10-06 17:48:54 +02:00
|
|
|
|
2007-09-03 22:34:44 +02:00
|
|
|
return conn;
|
2007-09-02 23:58:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
2015-01-15 22:06:46 +01:00
|
|
|
* Name: tcp_bind
|
2007-09-02 23:58:35 +02:00
|
|
|
*
|
|
|
|
* Description:
|
2014-07-06 20:34:27 +02:00
|
|
|
* This function implements the lower level parts of the standard TCP
|
2007-09-02 23:58:35 +02:00
|
|
|
* bind() operation.
|
|
|
|
*
|
2018-02-01 17:00:02 +01:00
|
|
|
* Returned Value:
|
2007-11-16 19:48:39 +01:00
|
|
|
* 0 on success or -EADDRINUSE on failure
|
|
|
|
*
|
2007-09-02 23:58:35 +02:00
|
|
|
* Assumptions:
|
|
|
|
* This function is called from normal user level code.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2015-01-18 00:07:54 +01:00
|
|
|
int tcp_bind(FAR struct tcp_conn_s *conn, FAR const struct sockaddr *addr)
|
2007-09-02 23:58:35 +02:00
|
|
|
{
|
2015-01-18 00:07:54 +01:00
|
|
|
#ifdef CONFIG_NET_IPv4
|
2014-11-22 17:46:37 +01:00
|
|
|
#ifdef CONFIG_NET_IPv6
|
2015-01-18 00:07:54 +01:00
|
|
|
if (conn->domain == PF_INET)
|
2014-11-22 17:46:37 +01:00
|
|
|
#endif
|
2007-09-09 19:20:56 +02:00
|
|
|
{
|
2015-01-18 00:07:54 +01:00
|
|
|
FAR const struct sockaddr_in *inaddr =
|
|
|
|
(FAR const struct sockaddr_in *)addr;
|
2007-11-16 19:48:39 +01:00
|
|
|
|
2015-01-18 00:07:54 +01:00
|
|
|
return tcp_ipv4_bind(conn, inaddr);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_IPv4 */
|
2007-11-22 15:42:52 +01:00
|
|
|
|
2015-01-18 00:07:54 +01:00
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
else
|
2007-11-16 19:48:39 +01:00
|
|
|
#endif
|
2015-01-18 00:07:54 +01:00
|
|
|
{
|
|
|
|
FAR const struct sockaddr_in6 *inaddr =
|
|
|
|
(FAR const struct sockaddr_in6 *)addr;
|
2007-11-16 19:48:39 +01:00
|
|
|
|
2015-01-18 00:07:54 +01:00
|
|
|
return tcp_ipv6_bind(conn, inaddr);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_IPv6 */
|
2007-09-02 23:58:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
2014-06-25 02:12:49 +02:00
|
|
|
* Name: tcp_connect
|
2007-09-02 23:58:35 +02:00
|
|
|
*
|
|
|
|
* Description:
|
2014-07-06 20:34:27 +02:00
|
|
|
* This function implements the lower level parts of the standard
|
2007-09-02 23:58:35 +02:00
|
|
|
* TCP connect() operation: It connects to a remote host using TCP.
|
|
|
|
*
|
|
|
|
* This function is used to start a new connection to the specified
|
2014-04-12 20:13:01 +02:00
|
|
|
* port on the specified host. It uses the connection structure that was
|
2007-09-02 23:58:35 +02:00
|
|
|
* allocated by a preceding socket() call. It sets the connection to
|
|
|
|
* the SYN_SENT state and sets the retransmission timer to 0. This will
|
|
|
|
* cause a TCP SYN segment to be sent out the next time this connection
|
|
|
|
* is periodically processed, which usually is done within 0.5 seconds
|
2014-06-25 02:12:49 +02:00
|
|
|
* after the call to tcp_connect().
|
2007-09-02 23:58:35 +02:00
|
|
|
*
|
|
|
|
* Assumptions:
|
|
|
|
* This function is called from normal user level code.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2015-01-17 22:17:35 +01:00
|
|
|
int tcp_connect(FAR struct tcp_conn_s *conn, FAR const struct sockaddr *addr)
|
2007-09-02 23:58:35 +02:00
|
|
|
{
|
2007-09-09 19:20:56 +02:00
|
|
|
int port;
|
2015-05-30 17:12:27 +02:00
|
|
|
int ret;
|
2007-09-02 23:58:35 +02:00
|
|
|
|
2014-07-07 00:10:26 +02:00
|
|
|
/* The connection is expected to be in the TCP_ALLOCATED state.. i.e.,
|
2007-09-03 22:34:44 +02:00
|
|
|
* allocated via up_tcpalloc(), but not yet put into the active connections
|
|
|
|
* list.
|
|
|
|
*/
|
|
|
|
|
2014-07-07 00:10:26 +02:00
|
|
|
if (!conn || conn->tcpstateflags != TCP_ALLOCATED)
|
2007-09-03 22:34:44 +02:00
|
|
|
{
|
|
|
|
return -EISCONN;
|
|
|
|
}
|
|
|
|
|
2014-04-12 20:13:01 +02:00
|
|
|
/* If the TCP port has not already been bound to a local port, then select
|
2020-05-04 19:34:04 +02:00
|
|
|
* one now. We assume that the IP address has been bound to a local device,
|
2014-11-22 17:46:37 +01:00
|
|
|
* but the port may still be INPORT_ANY.
|
2007-09-02 23:58:35 +02:00
|
|
|
*/
|
|
|
|
|
2016-12-03 23:28:19 +01:00
|
|
|
net_lock();
|
2015-02-10 13:54:10 +01:00
|
|
|
|
2021-03-04 07:03:09 +01:00
|
|
|
/* Check if the local port has been bind() */
|
|
|
|
|
|
|
|
port = conn->lport;
|
|
|
|
|
|
|
|
if (port == 0)
|
|
|
|
{
|
2015-02-10 13:54:10 +01:00
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
#ifdef CONFIG_NET_IPv6
|
2021-03-04 07:03:09 +01:00
|
|
|
if (conn->domain == PF_INET)
|
2015-02-10 01:15:34 +01:00
|
|
|
#endif
|
2021-03-04 07:03:09 +01:00
|
|
|
{
|
|
|
|
/* Select a port that is unique for this IPv4 local address
|
|
|
|
* (network order).
|
|
|
|
*/
|
2015-02-10 13:54:10 +01:00
|
|
|
|
2021-03-04 07:03:09 +01:00
|
|
|
port = tcp_selectport(PF_INET,
|
|
|
|
(FAR const union ip_addr_u *)
|
|
|
|
&conn->u.ipv4.laddr, 0);
|
|
|
|
}
|
2015-02-10 13:54:10 +01:00
|
|
|
#endif /* CONFIG_NET_IPv4 */
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
#ifdef CONFIG_NET_IPv4
|
2021-03-04 07:03:09 +01:00
|
|
|
else
|
2014-11-22 17:46:37 +01:00
|
|
|
#endif
|
2021-03-04 07:03:09 +01:00
|
|
|
{
|
|
|
|
/* Select a port that is unique for this IPv6 local address
|
|
|
|
* (network order).
|
|
|
|
*/
|
2015-02-10 13:54:10 +01:00
|
|
|
|
2021-03-04 07:03:09 +01:00
|
|
|
port = tcp_selectport(PF_INET6,
|
|
|
|
(FAR const union ip_addr_u *)
|
|
|
|
conn->u.ipv6.laddr, 0);
|
|
|
|
}
|
2015-02-10 13:54:10 +01:00
|
|
|
#endif /* CONFIG_NET_IPv6 */
|
|
|
|
|
2021-03-04 07:03:09 +01:00
|
|
|
/* Did we have a port assignment? */
|
2015-02-10 13:54:10 +01:00
|
|
|
|
2021-03-04 07:03:09 +01:00
|
|
|
if (port < 0)
|
|
|
|
{
|
|
|
|
ret = port;
|
|
|
|
goto errout_with_lock;
|
|
|
|
}
|
2007-09-02 23:58:35 +02:00
|
|
|
}
|
|
|
|
|
2015-08-27 03:18:04 +02:00
|
|
|
/* Set up the local address (laddr) and the remote address (raddr) that
|
|
|
|
* describes the TCP connection.
|
|
|
|
*/
|
2007-09-02 23:58:35 +02:00
|
|
|
|
2015-01-17 22:17:35 +01:00
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
if (conn->domain == PF_INET)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
FAR const struct sockaddr_in *inaddr =
|
|
|
|
(FAR const struct sockaddr_in *)addr;
|
|
|
|
|
|
|
|
/* Save MSS and the port from the sockaddr (already in network order) */
|
|
|
|
|
|
|
|
conn->mss = MIN_IPv4_TCP_INITIAL_MSS;
|
|
|
|
conn->rport = inaddr->sin_port;
|
2007-09-02 23:58:35 +02:00
|
|
|
|
2022-11-17 12:53:53 +01:00
|
|
|
/* The sockaddr address is 32-bits in network order.
|
|
|
|
* Note: 0.0.0.0 is mapped to 127.0.0.1 by convention.
|
|
|
|
*/
|
2015-01-17 22:17:35 +01:00
|
|
|
|
2022-11-17 12:53:53 +01:00
|
|
|
if (inaddr->sin_addr.s_addr == INADDR_ANY)
|
|
|
|
{
|
|
|
|
net_ipv4addr_copy(conn->u.ipv4.raddr, HTONL(INADDR_LOOPBACK));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
net_ipv4addr_copy(conn->u.ipv4.raddr, inaddr->sin_addr.s_addr);
|
|
|
|
}
|
2015-05-30 17:12:27 +02:00
|
|
|
|
|
|
|
/* Find the device that can receive packets on the network associated
|
2015-09-03 03:48:31 +02:00
|
|
|
* with this remote address.
|
2015-05-30 17:12:27 +02:00
|
|
|
*/
|
|
|
|
|
2015-09-03 03:48:31 +02:00
|
|
|
ret = tcp_remote_ipv4_device(conn);
|
2015-01-17 22:17:35 +01:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_IPv4 */
|
2007-09-02 23:58:35 +02:00
|
|
|
|
2015-01-17 22:17:35 +01:00
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
FAR const struct sockaddr_in6 *inaddr =
|
|
|
|
(FAR const struct sockaddr_in6 *)addr;
|
|
|
|
|
|
|
|
/* Save MSS and the port from the sockaddr (already in network order) */
|
|
|
|
|
|
|
|
conn->mss = MIN_IPv6_TCP_INITIAL_MSS;
|
2015-01-21 01:14:09 +01:00
|
|
|
conn->rport = inaddr->sin6_port;
|
2015-01-17 22:17:35 +01:00
|
|
|
|
2022-11-17 12:53:53 +01:00
|
|
|
/* The sockaddr address is 128-bits in network order.
|
|
|
|
* Note: ::0 is mapped to ::1 by convention.
|
|
|
|
*/
|
2015-01-17 22:17:35 +01:00
|
|
|
|
2022-11-17 12:53:53 +01:00
|
|
|
if (net_ipv6addr_cmp(addr, g_ipv6_unspecaddr))
|
|
|
|
{
|
|
|
|
struct in6_addr loopback_sin6_addr = IN6ADDR_LOOPBACK_INIT;
|
|
|
|
net_ipv6addr_copy(conn->u.ipv6.raddr,
|
|
|
|
loopback_sin6_addr.s6_addr16);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
net_ipv6addr_copy(conn->u.ipv6.raddr, inaddr->sin6_addr.s6_addr16);
|
|
|
|
}
|
2015-05-30 17:12:27 +02:00
|
|
|
|
|
|
|
/* Find the device that can receive packets on the network associated
|
|
|
|
* with this local address.
|
|
|
|
*/
|
|
|
|
|
2015-09-03 03:48:31 +02:00
|
|
|
ret = tcp_remote_ipv6_device(conn);
|
2015-01-17 22:17:35 +01:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_IPv6 */
|
2007-09-03 22:34:44 +02:00
|
|
|
|
2015-05-30 17:12:27 +02:00
|
|
|
/* Verify that a network device that can provide packets to this local
|
|
|
|
* address was found.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
/* If no device is found, then the address is not reachable. That
|
|
|
|
* should be impossible in this context and we should probably really
|
|
|
|
* just assert here.
|
|
|
|
*/
|
|
|
|
|
2016-06-12 01:37:21 +02:00
|
|
|
nerr("ERROR: Failed to find network device: %d\n", ret);
|
2015-05-30 17:12:27 +02:00
|
|
|
goto errout_with_lock;
|
|
|
|
}
|
|
|
|
|
2020-05-06 04:25:03 +02:00
|
|
|
#if defined(CONFIG_NET_ARP_SEND) || defined(CONFIG_NET_ICMPv6_NEIGHBOR)
|
|
|
|
#ifdef CONFIG_NET_ARP_SEND
|
|
|
|
#ifdef CONFIG_NET_ICMPv6_NEIGHBOR
|
|
|
|
if (conn->domain == PF_INET)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
/* Make sure that the IP address mapping is in the ARP table */
|
|
|
|
|
|
|
|
ret = arp_send(conn->u.ipv4.raddr);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_ARP_SEND */
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_ICMPv6_NEIGHBOR
|
|
|
|
#ifdef CONFIG_NET_ARP_SEND
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
/* Make sure that the IP address mapping is in the Neighbor Table */
|
|
|
|
|
|
|
|
ret = icmpv6_neighbor(conn->u.ipv6.raddr);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_ICMPv6_NEIGHBOR */
|
|
|
|
|
|
|
|
/* Did we successfully get the address mapping? */
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
ret = -ENETUNREACH;
|
|
|
|
goto errout_with_lock;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_ARP_SEND || CONFIG_NET_ICMPv6_NEIGHBOR */
|
|
|
|
|
2015-05-30 17:12:27 +02:00
|
|
|
/* Initialize and return the connection structure, bind it to the port
|
|
|
|
* number. At this point, we do not know the size of the initial MSS We
|
|
|
|
* know the total size of the packet buffer, but we don't yet know the
|
|
|
|
* size of link layer header.
|
|
|
|
*/
|
|
|
|
|
|
|
|
conn->tcpstateflags = TCP_SYN_SENT;
|
|
|
|
tcp_initsequence(conn->sndseq);
|
|
|
|
|
2022-11-02 17:40:08 +01:00
|
|
|
/* Save initial sndseq to rexmit_seq, otherwise it will be zero */
|
|
|
|
|
|
|
|
#if !defined(CONFIG_NET_TCP_WRITE_BUFFERS)
|
|
|
|
conn->rexmit_seq = tcp_getsequence(conn->sndseq);
|
|
|
|
#endif
|
|
|
|
|
2019-12-08 20:13:51 +01:00
|
|
|
conn->tx_unacked = 1; /* TCP length of the SYN is one. */
|
2015-05-30 17:12:27 +02:00
|
|
|
conn->nrtx = 0;
|
2022-04-25 17:08:24 +02:00
|
|
|
conn->timeout = true; /* Send the SYN immediately. */
|
2015-05-30 17:12:27 +02:00
|
|
|
conn->rto = TCP_RTO;
|
|
|
|
conn->sa = 0;
|
|
|
|
conn->sv = 16; /* Initial value of the RTT variance. */
|
2021-03-04 07:03:09 +01:00
|
|
|
conn->lport = (uint16_t)port;
|
2015-05-30 17:12:27 +02:00
|
|
|
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
|
|
|
conn->expired = 0;
|
|
|
|
conn->isn = 0;
|
|
|
|
conn->sent = 0;
|
While working with version 7.10 I discovered a problem in TCP stack that could be observed on high network load. Generally speaking, the problem is that RST flag is set in unnecessary case, in which between loss of some TCP packet and its proper retransmission, another packets had been successfully sent. The scenario is as follows: NuttX did not receive ACK for some sent packet, so it has been probably lost somewhere. But before its retransmission starts, NuttX is correctly issuing next TCP packets, with sequence numbers increasing properly. When the retransmission of previously lost packet finally succeeds, tcp_input receives the accumulated ACK value, which acknowledges also the packets sent in the meantime (i.e. between unsuccessful sending of lost packet and its proper retransmission). However, variable unackseq is still set to conn->isn + conn->sent, which is truth only if no further packets transmission occurred in the meantime. Because of incorrect (in such specific case) unackseq value, few lines further condition if (ackseq <= unackseq)is not met, and, as a result, we are going to reset label.
2016-06-20 14:55:29 +02:00
|
|
|
conn->sndseq_max = 0;
|
2015-05-30 17:12:27 +02:00
|
|
|
#endif
|
|
|
|
|
2007-11-20 00:09:39 +01:00
|
|
|
/* Initialize the list of TCP read-ahead buffers */
|
|
|
|
|
2021-06-18 07:34:21 +02:00
|
|
|
conn->readahead = NULL;
|
2007-11-20 00:09:39 +01:00
|
|
|
|
2014-01-14 00:26:11 +01:00
|
|
|
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
|
|
|
/* Initialize the TCP write buffer lists */
|
|
|
|
|
|
|
|
sq_init(&conn->write_q);
|
|
|
|
sq_init(&conn->unacked_q);
|
|
|
|
#endif
|
|
|
|
|
2015-05-30 17:12:27 +02:00
|
|
|
/* And, finally, put the connection structure into the active list. */
|
2007-09-03 22:34:44 +02:00
|
|
|
|
2022-02-07 04:49:41 +01:00
|
|
|
dq_addlast(&conn->sconn.node, &g_active_tcp_connections);
|
2015-05-30 17:12:27 +02:00
|
|
|
ret = OK;
|
2007-09-03 22:34:44 +02:00
|
|
|
|
2015-05-30 17:12:27 +02:00
|
|
|
errout_with_lock:
|
2016-12-03 23:28:19 +01:00
|
|
|
net_unlock();
|
2015-05-30 17:12:27 +02:00
|
|
|
return ret;
|
2007-09-02 23:58:35 +02:00
|
|
|
}
|
|
|
|
|
2007-11-22 19:36:46 +01:00
|
|
|
#endif /* CONFIG_NET && CONFIG_NET_TCP */
|