2007-09-03 22:34:44 +02:00
|
|
|
/****************************************************************************
|
2014-06-18 18:50:09 +02:00
|
|
|
* net/udp/udp_conn.c
|
2007-09-02 23:58:35 +02:00
|
|
|
*
|
2024-09-11 14:39:39 +02:00
|
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
*
|
2018-01-23 01:32:02 +01:00
|
|
|
* Copyright (C) 2007-2009, 2011-2012, 2016, 2018 Gregory Nutt. All rights
|
|
|
|
* reserved.
|
2012-06-08 20:56:01 +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.
|
|
|
|
*
|
|
|
|
* 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
|
|
|
*
|
2007-09-03 22:34:44 +02:00
|
|
|
****************************************************************************/
|
2007-09-02 23:58:35 +02:00
|
|
|
|
2007-09-03 22:34:44 +02:00
|
|
|
/****************************************************************************
|
2007-09-02 23:58:35 +02:00
|
|
|
* Included Files
|
2007-09-03 22:34:44 +02:00
|
|
|
****************************************************************************/
|
2007-09-02 23:58:35 +02:00
|
|
|
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#if defined(CONFIG_NET) && defined(CONFIG_NET_UDP)
|
|
|
|
|
2009-12-15 15:53:45 +01:00
|
|
|
#include <stdint.h>
|
2007-09-03 01:11:10 +02:00
|
|
|
#include <string.h>
|
2007-09-03 22:34:44 +02:00
|
|
|
#include <assert.h>
|
2007-09-03 01:11:10 +02:00
|
|
|
#include <errno.h>
|
2007-11-23 20:25:39 +01:00
|
|
|
#include <debug.h>
|
|
|
|
|
2015-05-29 23:16:11 +02:00
|
|
|
#include <netinet/in.h>
|
|
|
|
|
2007-09-03 01:11:10 +02:00
|
|
|
#include <arch/irq.h>
|
|
|
|
|
2020-05-15 08:01:01 +02:00
|
|
|
#include <nuttx/clock.h>
|
2022-01-01 15:05:07 +01:00
|
|
|
#include <nuttx/kmalloc.h>
|
2022-09-06 08:18:45 +02:00
|
|
|
#include <nuttx/mutex.h>
|
2014-06-24 16:53:28 +02:00
|
|
|
#include <nuttx/net/netconfig.h>
|
2014-07-05 03:13:08 +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/udp.h>
|
2007-09-03 01:11:10 +02:00
|
|
|
|
2014-06-29 02:07:02 +02:00
|
|
|
#include "devif/devif.h"
|
2023-02-02 04:24:46 +01:00
|
|
|
#include "inet/inet.h"
|
2022-11-03 07:26:21 +01:00
|
|
|
#include "nat/nat.h"
|
2014-11-21 21:21:30 +01:00
|
|
|
#include "netdev/netdev.h"
|
2023-02-02 04:24:46 +01:00
|
|
|
#include "socket/socket.h"
|
2023-11-01 12:57:27 +01:00
|
|
|
#include "igmp/igmp.h"
|
2014-06-25 02:55:01 +02:00
|
|
|
#include "udp/udp.h"
|
2024-04-12 05:11:54 +02:00
|
|
|
#include "utils/utils.h"
|
2007-09-03 01:11:10 +02:00
|
|
|
|
2007-09-03 22:34:44 +02:00
|
|
|
/****************************************************************************
|
2007-09-03 01:11:10 +02:00
|
|
|
* Private Data
|
2007-09-03 22:34:44 +02:00
|
|
|
****************************************************************************/
|
2007-09-03 01:11:10 +02:00
|
|
|
|
2016-05-30 17:31:44 +02:00
|
|
|
/* The array containing all UDP connections. */
|
2007-09-03 01:11:10 +02:00
|
|
|
|
2023-02-02 15:20:55 +01:00
|
|
|
#if CONFIG_NET_UDP_PREALLOC_CONNS > 0
|
2023-05-30 07:28:05 +02:00
|
|
|
static struct udp_conn_s g_udp_connections[CONFIG_NET_UDP_PREALLOC_CONNS];
|
2021-12-31 08:20:29 +01:00
|
|
|
#endif
|
2007-09-03 22:34:44 +02:00
|
|
|
|
|
|
|
/* A list of all free UDP connections */
|
|
|
|
|
|
|
|
static dq_queue_t g_free_udp_connections;
|
2022-09-06 08:18:45 +02:00
|
|
|
static mutex_t g_free_lock = NXMUTEX_INITIALIZER;
|
2007-09-03 22:34:44 +02:00
|
|
|
|
|
|
|
/* A list of all allocated UDP connections */
|
|
|
|
|
|
|
|
static dq_queue_t g_active_udp_connections;
|
2007-09-03 01:11:10 +02:00
|
|
|
|
2007-09-03 22:34:44 +02:00
|
|
|
/****************************************************************************
|
2007-09-02 23:58:35 +02:00
|
|
|
* Private Functions
|
2007-09-03 22:34:44 +02:00
|
|
|
****************************************************************************/
|
2007-09-02 23:58:35 +02:00
|
|
|
|
2007-09-03 22:34:44 +02:00
|
|
|
/****************************************************************************
|
2014-06-29 03:26:16 +02:00
|
|
|
* Name: udp_find_conn()
|
2007-09-03 22:34:44 +02:00
|
|
|
*
|
|
|
|
* Description:
|
2017-09-02 18:27:03 +02:00
|
|
|
* Find the UDP connection that uses this local port number.
|
|
|
|
*
|
2023-02-02 04:24:46 +01:00
|
|
|
* Input Parameters:
|
|
|
|
* domain - IP domain (PF_INET or PF_INET6)
|
|
|
|
* ipaddr - The IP address to use in the lookup
|
|
|
|
* portno - The port to use in the lookup
|
|
|
|
* opt - The option from another conn to match the conflict conn
|
|
|
|
* SO_REUSEADDR: If both sockets have this, they never confilct.
|
|
|
|
*
|
2017-09-02 18:27:03 +02:00
|
|
|
* Assumptions:
|
|
|
|
* This function must be called with the network locked.
|
2007-09-03 22:34:44 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2015-01-17 21:13:56 +01:00
|
|
|
static FAR struct udp_conn_s *udp_find_conn(uint8_t domain,
|
|
|
|
FAR union ip_binding_u *ipaddr,
|
2023-02-02 04:24:46 +01:00
|
|
|
uint16_t portno, sockopt_t opt)
|
2007-09-03 01:11:10 +02:00
|
|
|
{
|
2021-12-31 08:20:29 +01:00
|
|
|
FAR struct udp_conn_s *conn = NULL;
|
2023-02-02 04:24:46 +01:00
|
|
|
#ifdef CONFIG_NET_SOCKOPTS
|
|
|
|
bool skip_reusable = _SO_GETOPT(opt, SO_REUSEADDR);
|
|
|
|
#endif
|
2007-09-03 01:11:10 +02:00
|
|
|
|
2015-10-08 23:10:04 +02:00
|
|
|
/* Now search each connection structure. */
|
2007-09-03 22:34:44 +02:00
|
|
|
|
2021-12-31 08:20:29 +01:00
|
|
|
while ((conn = udp_nextconn(conn)) != NULL)
|
2007-09-03 01:11:10 +02:00
|
|
|
{
|
2023-02-02 04:24:46 +01:00
|
|
|
/* With SO_REUSEADDR set for both sockets, we do not need to check its
|
|
|
|
* address and port.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_SOCKOPTS
|
|
|
|
if (skip_reusable && _SO_GETOPT(conn->sconn.s_options, SO_REUSEADDR))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-11-21 21:21:30 +01:00
|
|
|
/* If the port local port number assigned to the connections matches
|
|
|
|
* AND the IP address of the connection matches, then return a
|
2014-11-22 14:55:45 +01:00
|
|
|
* reference to the connection structure. INADDR_ANY is a special
|
|
|
|
* case: There can only be instance of a port number with INADDR_ANY.
|
2014-11-21 21:21:30 +01:00
|
|
|
*/
|
|
|
|
|
2015-01-17 21:13:56 +01:00
|
|
|
#ifdef CONFIG_NET_IPv4
|
2014-11-22 14:55:45 +01:00
|
|
|
#ifdef CONFIG_NET_IPv6
|
2015-01-17 21:13:56 +01:00
|
|
|
if (domain == PF_INET)
|
2014-11-22 14:55:45 +01:00
|
|
|
#endif
|
2014-11-21 21:21:30 +01:00
|
|
|
{
|
2022-08-24 09:06:59 +02:00
|
|
|
if (conn->domain == PF_INET && conn->lport == portno &&
|
2015-01-17 21:13:56 +01:00
|
|
|
(net_ipv4addr_cmp(conn->u.ipv4.laddr, ipaddr->ipv4.laddr) ||
|
|
|
|
net_ipv4addr_cmp(conn->u.ipv4.laddr, INADDR_ANY)))
|
|
|
|
{
|
|
|
|
return conn;
|
|
|
|
}
|
2014-11-21 21:21:30 +01:00
|
|
|
}
|
2015-01-17 21:13:56 +01:00
|
|
|
#endif /* CONFIG_NET_IPv4 */
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
2022-08-24 09:06:59 +02:00
|
|
|
if (conn->domain == PF_INET6 && conn->lport == portno &&
|
2015-01-17 21:13:56 +01:00
|
|
|
(net_ipv6addr_cmp(conn->u.ipv6.laddr, ipaddr->ipv6.laddr) ||
|
2018-06-23 20:53:27 +02:00
|
|
|
net_ipv6addr_cmp(conn->u.ipv6.laddr, g_ipv6_unspecaddr)))
|
2015-01-17 21:13:56 +01:00
|
|
|
{
|
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_IPv6 */
|
2007-09-03 01:11:10 +02:00
|
|
|
}
|
|
|
|
|
2007-09-09 21:47:52 +02:00
|
|
|
return NULL;
|
2007-09-03 01:11:10 +02:00
|
|
|
}
|
|
|
|
|
2015-01-17 21:13:56 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: udp_ipv4_active
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Find a connection structure that is the appropriate connection to be
|
|
|
|
* used within the provided UDP header
|
|
|
|
*
|
|
|
|
* Assumptions:
|
2017-09-02 18:27:03 +02:00
|
|
|
* This function must be called with the network locked.
|
2015-01-17 21:13:56 +01:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
static inline FAR struct udp_conn_s *
|
2024-03-27 10:15:44 +01:00
|
|
|
udp_ipv4_active(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn,
|
|
|
|
FAR struct udp_hdr_s *udp)
|
2015-01-17 21:13:56 +01:00
|
|
|
{
|
2017-08-08 15:48:07 +02:00
|
|
|
#ifdef CONFIG_NET_BROADCAST
|
2017-08-08 22:24:12 +02:00
|
|
|
static const in_addr_t bcast = INADDR_BROADCAST;
|
2017-08-08 15:48:07 +02:00
|
|
|
#endif
|
2015-01-18 15:56:05 +01:00
|
|
|
FAR struct ipv4_hdr_s *ip = IPv4BUF;
|
2015-01-17 21:13:56 +01:00
|
|
|
|
2024-03-27 10:15:44 +01:00
|
|
|
conn = udp_nextconn(conn);
|
|
|
|
|
2015-01-17 21:13:56 +01:00
|
|
|
while (conn)
|
|
|
|
{
|
|
|
|
/* If the local UDP port is non-zero, the connection is considered
|
|
|
|
* to be used. If so, then the following checks are performed:
|
|
|
|
*
|
net/udp: Resolve race condition in connection-less UDP sockets with read-ahead buffering.
In connection-mode UDP sockets, a remote address is retained in the UDP connection structure. This determines both there send() will send the packets and which packets recv() will accept.
This same mechanism is used for connection-less UDP sendto: A temporary remote address is written into the connection structure to support the sendto() operation. That address persists until the next recvfrom() when it is reset to accept any address.
When UDP read-ahead buffering is enabled, however, that means that the old, invalid remote address can be left in the connection structure for some time. This can cause read-ahead buffer to fail, dropping UDP packets.
Shortening the time between when he remote address is reset (i.e., immediately after the sendto() completes) is not a solution, that does not eliminate the race condition; in only makes it smaller.
With this change, a flag was added to the connection structure to indicate if the UDP socket is in connection mode or if it is connection-less. This change effects only UDP receive operations: The remote address in the UDP connection is always ignored if the UDP socket is not in connection-mode.
No for connection-mode sockets, that remote address behaves as before. But for connection-less sockets, it is only used by sendto().
2018-05-13 17:57:34 +02:00
|
|
|
* 1. The destination address is verified against the bound address
|
|
|
|
* of the connection.
|
|
|
|
*
|
|
|
|
* - The local port number is checked against the destination port
|
|
|
|
* number in the received packet.
|
|
|
|
* - If multiple network interfaces are supported, then the local
|
|
|
|
* IP address is available and we will insist that the
|
|
|
|
* destination IP matches the bound address (or the destination
|
|
|
|
* IP address is a broadcast address). If a socket is bound to
|
|
|
|
* INADDRY_ANY (laddr), then it should receive all packets
|
|
|
|
* directed to the port.
|
|
|
|
*
|
|
|
|
* 2. If this is a connection mode UDP socket, then the source address
|
|
|
|
* is verified against the connected remote address.
|
|
|
|
*
|
|
|
|
* - The remote port number is checked if the connection is bound
|
|
|
|
* to a remote port.
|
|
|
|
* - Finally, if the connection is bound to a remote IP address,
|
|
|
|
* the source IP address of the packet is checked. Broadcast
|
|
|
|
* addresses are also accepted.
|
2015-01-17 21:13:56 +01:00
|
|
|
*
|
|
|
|
* If all of the above are true then the newly received UDP packet
|
|
|
|
* is destined for this UDP connection.
|
2017-08-07 19:50:50 +02:00
|
|
|
*
|
net/udp: Resolve race condition in connection-less UDP sockets with read-ahead buffering.
In connection-mode UDP sockets, a remote address is retained in the UDP connection structure. This determines both there send() will send the packets and which packets recv() will accept.
This same mechanism is used for connection-less UDP sendto: A temporary remote address is written into the connection structure to support the sendto() operation. That address persists until the next recvfrom() when it is reset to accept any address.
When UDP read-ahead buffering is enabled, however, that means that the old, invalid remote address can be left in the connection structure for some time. This can cause read-ahead buffer to fail, dropping UDP packets.
Shortening the time between when he remote address is reset (i.e., immediately after the sendto() completes) is not a solution, that does not eliminate the race condition; in only makes it smaller.
With this change, a flag was added to the connection structure to indicate if the UDP socket is in connection mode or if it is connection-less. This change effects only UDP receive operations: The remote address in the UDP connection is always ignored if the UDP socket is not in connection-mode.
No for connection-mode sockets, that remote address behaves as before. But for connection-less sockets, it is only used by sendto().
2018-05-13 17:57:34 +02:00
|
|
|
* To send and receive multicast packets, the application should:
|
|
|
|
*
|
|
|
|
* - Bind socket to INADDR6_ANY (for the all-nodes multicast address)
|
|
|
|
* or to a specific <multicast-address>
|
|
|
|
* - setsockopt to SO_BROADCAST (for all-nodes address)
|
|
|
|
*
|
|
|
|
* For connection-less UDP sockets:
|
2017-08-07 19:50:50 +02:00
|
|
|
*
|
net/udp: Resolve race condition in connection-less UDP sockets with read-ahead buffering.
In connection-mode UDP sockets, a remote address is retained in the UDP connection structure. This determines both there send() will send the packets and which packets recv() will accept.
This same mechanism is used for connection-less UDP sendto: A temporary remote address is written into the connection structure to support the sendto() operation. That address persists until the next recvfrom() when it is reset to accept any address.
When UDP read-ahead buffering is enabled, however, that means that the old, invalid remote address can be left in the connection structure for some time. This can cause read-ahead buffer to fail, dropping UDP packets.
Shortening the time between when he remote address is reset (i.e., immediately after the sendto() completes) is not a solution, that does not eliminate the race condition; in only makes it smaller.
With this change, a flag was added to the connection structure to indicate if the UDP socket is in connection mode or if it is connection-less. This change effects only UDP receive operations: The remote address in the UDP connection is always ignored if the UDP socket is not in connection-mode.
No for connection-mode sockets, that remote address behaves as before. But for connection-less sockets, it is only used by sendto().
2018-05-13 17:57:34 +02:00
|
|
|
* - call sendto with sendaddr.sin_addr.s_addr = <multicast-address>
|
|
|
|
* - call recvfrom.
|
|
|
|
*
|
|
|
|
* For connection-mode UDP sockets:
|
|
|
|
*
|
|
|
|
* - call connect() to connect the UDP socket to a specific remote
|
|
|
|
* address, then
|
|
|
|
* - Call send() with no address address information
|
|
|
|
* - call recv() (from address information should not be needed)
|
2017-08-07 19:50:50 +02:00
|
|
|
*
|
2021-12-20 15:49:48 +01:00
|
|
|
* REVISIT: SO_BROADCAST flag is currently ignored.
|
2015-01-17 21:13:56 +01:00
|
|
|
*/
|
|
|
|
|
2021-12-20 15:49:48 +01:00
|
|
|
/* Check that there is a local port number and this matches
|
net/udp: Resolve race condition in connection-less UDP sockets with read-ahead buffering.
In connection-mode UDP sockets, a remote address is retained in the UDP connection structure. This determines both there send() will send the packets and which packets recv() will accept.
This same mechanism is used for connection-less UDP sendto: A temporary remote address is written into the connection structure to support the sendto() operation. That address persists until the next recvfrom() when it is reset to accept any address.
When UDP read-ahead buffering is enabled, however, that means that the old, invalid remote address can be left in the connection structure for some time. This can cause read-ahead buffer to fail, dropping UDP packets.
Shortening the time between when he remote address is reset (i.e., immediately after the sendto() completes) is not a solution, that does not eliminate the race condition; in only makes it smaller.
With this change, a flag was added to the connection structure to indicate if the UDP socket is in connection mode or if it is connection-less. This change effects only UDP receive operations: The remote address in the UDP connection is always ignored if the UDP socket is not in connection-mode.
No for connection-mode sockets, that remote address behaves as before. But for connection-less sockets, it is only used by sendto().
2018-05-13 17:57:34 +02:00
|
|
|
* the port number in the destination address.
|
|
|
|
*/
|
|
|
|
|
2015-01-17 21:13:56 +01:00
|
|
|
if (conn->lport != 0 && udp->destport == conn->lport &&
|
2017-08-08 15:48:07 +02:00
|
|
|
|
|
|
|
/* Local port accepts any address on this port or there
|
|
|
|
* is an exact match in destipaddr and the bound local
|
|
|
|
* address. This catches the receipt of a broadcast when
|
|
|
|
* the socket is bound to INADDR_ANY.
|
|
|
|
*/
|
|
|
|
|
2015-05-29 23:16:11 +02:00
|
|
|
(net_ipv4addr_cmp(conn->u.ipv4.laddr, INADDR_ANY) ||
|
net/udp: Resolve race condition in connection-less UDP sockets with read-ahead buffering.
In connection-mode UDP sockets, a remote address is retained in the UDP connection structure. This determines both there send() will send the packets and which packets recv() will accept.
This same mechanism is used for connection-less UDP sendto: A temporary remote address is written into the connection structure to support the sendto() operation. That address persists until the next recvfrom() when it is reset to accept any address.
When UDP read-ahead buffering is enabled, however, that means that the old, invalid remote address can be left in the connection structure for some time. This can cause read-ahead buffer to fail, dropping UDP packets.
Shortening the time between when he remote address is reset (i.e., immediately after the sendto() completes) is not a solution, that does not eliminate the race condition; in only makes it smaller.
With this change, a flag was added to the connection structure to indicate if the UDP socket is in connection mode or if it is connection-less. This change effects only UDP receive operations: The remote address in the UDP connection is always ignored if the UDP socket is not in connection-mode.
No for connection-mode sockets, that remote address behaves as before. But for connection-less sockets, it is only used by sendto().
2018-05-13 17:57:34 +02:00
|
|
|
net_ipv4addr_hdrcmp(ip->destipaddr, &conn->u.ipv4.laddr)))
|
|
|
|
{
|
|
|
|
/* Check if the socket is connection mode. In this case, only
|
|
|
|
* packets with source addresses from the connected remote peer
|
|
|
|
* will be accepted.
|
2017-08-08 15:48:07 +02:00
|
|
|
*/
|
|
|
|
|
net/udp: Resolve race condition in connection-less UDP sockets with read-ahead buffering.
In connection-mode UDP sockets, a remote address is retained in the UDP connection structure. This determines both there send() will send the packets and which packets recv() will accept.
This same mechanism is used for connection-less UDP sendto: A temporary remote address is written into the connection structure to support the sendto() operation. That address persists until the next recvfrom() when it is reset to accept any address.
When UDP read-ahead buffering is enabled, however, that means that the old, invalid remote address can be left in the connection structure for some time. This can cause read-ahead buffer to fail, dropping UDP packets.
Shortening the time between when he remote address is reset (i.e., immediately after the sendto() completes) is not a solution, that does not eliminate the race condition; in only makes it smaller.
With this change, a flag was added to the connection structure to indicate if the UDP socket is in connection mode or if it is connection-less. This change effects only UDP receive operations: The remote address in the UDP connection is always ignored if the UDP socket is not in connection-mode.
No for connection-mode sockets, that remote address behaves as before. But for connection-less sockets, it is only used by sendto().
2018-05-13 17:57:34 +02:00
|
|
|
if (_UDP_ISCONNECTMODE(conn->flags))
|
|
|
|
{
|
|
|
|
/* Check if the UDP connection is either (1) accepting packets
|
|
|
|
* from any port or (2) the packet srcport matches the local
|
|
|
|
* bound port number.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ((conn->rport == 0 || udp->srcport == conn->rport) &&
|
|
|
|
|
2018-05-14 14:36:59 +02:00
|
|
|
/* If (1) not connected to a remote address, or (2) a
|
|
|
|
* broadcast destipaddr was received, or (3) there is an
|
net/udp: Resolve race condition in connection-less UDP sockets with read-ahead buffering.
In connection-mode UDP sockets, a remote address is retained in the UDP connection structure. This determines both there send() will send the packets and which packets recv() will accept.
This same mechanism is used for connection-less UDP sendto: A temporary remote address is written into the connection structure to support the sendto() operation. That address persists until the next recvfrom() when it is reset to accept any address.
When UDP read-ahead buffering is enabled, however, that means that the old, invalid remote address can be left in the connection structure for some time. This can cause read-ahead buffer to fail, dropping UDP packets.
Shortening the time between when he remote address is reset (i.e., immediately after the sendto() completes) is not a solution, that does not eliminate the race condition; in only makes it smaller.
With this change, a flag was added to the connection structure to indicate if the UDP socket is in connection mode or if it is connection-less. This change effects only UDP receive operations: The remote address in the UDP connection is always ignored if the UDP socket is not in connection-mode.
No for connection-mode sockets, that remote address behaves as before. But for connection-less sockets, it is only used by sendto().
2018-05-13 17:57:34 +02:00
|
|
|
* exact match between the srcipaddr and the bound remote IP
|
|
|
|
* address, then accept the packet.
|
|
|
|
*/
|
|
|
|
|
|
|
|
(net_ipv4addr_cmp(conn->u.ipv4.raddr, INADDR_ANY) ||
|
2017-08-08 15:48:07 +02:00
|
|
|
#ifdef CONFIG_NET_BROADCAST
|
net/udp: Resolve race condition in connection-less UDP sockets with read-ahead buffering.
In connection-mode UDP sockets, a remote address is retained in the UDP connection structure. This determines both there send() will send the packets and which packets recv() will accept.
This same mechanism is used for connection-less UDP sendto: A temporary remote address is written into the connection structure to support the sendto() operation. That address persists until the next recvfrom() when it is reset to accept any address.
When UDP read-ahead buffering is enabled, however, that means that the old, invalid remote address can be left in the connection structure for some time. This can cause read-ahead buffer to fail, dropping UDP packets.
Shortening the time between when he remote address is reset (i.e., immediately after the sendto() completes) is not a solution, that does not eliminate the race condition; in only makes it smaller.
With this change, a flag was added to the connection structure to indicate if the UDP socket is in connection mode or if it is connection-less. This change effects only UDP receive operations: The remote address in the UDP connection is always ignored if the UDP socket is not in connection-mode.
No for connection-mode sockets, that remote address behaves as before. But for connection-less sockets, it is only used by sendto().
2018-05-13 17:57:34 +02:00
|
|
|
net_ipv4addr_hdrcmp(ip->destipaddr, &bcast) ||
|
2017-08-08 15:48:07 +02:00
|
|
|
#endif
|
net/udp: Resolve race condition in connection-less UDP sockets with read-ahead buffering.
In connection-mode UDP sockets, a remote address is retained in the UDP connection structure. This determines both there send() will send the packets and which packets recv() will accept.
This same mechanism is used for connection-less UDP sendto: A temporary remote address is written into the connection structure to support the sendto() operation. That address persists until the next recvfrom() when it is reset to accept any address.
When UDP read-ahead buffering is enabled, however, that means that the old, invalid remote address can be left in the connection structure for some time. This can cause read-ahead buffer to fail, dropping UDP packets.
Shortening the time between when he remote address is reset (i.e., immediately after the sendto() completes) is not a solution, that does not eliminate the race condition; in only makes it smaller.
With this change, a flag was added to the connection structure to indicate if the UDP socket is in connection mode or if it is connection-less. This change effects only UDP receive operations: The remote address in the UDP connection is always ignored if the UDP socket is not in connection-mode.
No for connection-mode sockets, that remote address behaves as before. But for connection-less sockets, it is only used by sendto().
2018-05-13 17:57:34 +02:00
|
|
|
net_ipv4addr_hdrcmp(ip->srcipaddr, &conn->u.ipv4.raddr)))
|
|
|
|
{
|
|
|
|
/* Matching connection found.. Break out of the loop and
|
|
|
|
* return this reference to it.
|
|
|
|
*/
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* This UDP socket is not connected. We need to match only
|
|
|
|
* the destination address with the bound socket address.
|
|
|
|
* Break out out of the loop and return this reference to
|
|
|
|
* the matching connection structure.
|
|
|
|
*/
|
2015-01-17 21:13:56 +01:00
|
|
|
|
net/udp: Resolve race condition in connection-less UDP sockets with read-ahead buffering.
In connection-mode UDP sockets, a remote address is retained in the UDP connection structure. This determines both there send() will send the packets and which packets recv() will accept.
This same mechanism is used for connection-less UDP sendto: A temporary remote address is written into the connection structure to support the sendto() operation. That address persists until the next recvfrom() when it is reset to accept any address.
When UDP read-ahead buffering is enabled, however, that means that the old, invalid remote address can be left in the connection structure for some time. This can cause read-ahead buffer to fail, dropping UDP packets.
Shortening the time between when he remote address is reset (i.e., immediately after the sendto() completes) is not a solution, that does not eliminate the race condition; in only makes it smaller.
With this change, a flag was added to the connection structure to indicate if the UDP socket is in connection mode or if it is connection-less. This change effects only UDP receive operations: The remote address in the UDP connection is always ignored if the UDP socket is not in connection-mode.
No for connection-mode sockets, that remote address behaves as before. But for connection-less sockets, it is only used by sendto().
2018-05-13 17:57:34 +02:00
|
|
|
break;
|
|
|
|
}
|
2015-01-17 21:13:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Look at the next active connection */
|
|
|
|
|
2022-02-07 04:34:18 +01:00
|
|
|
conn = (FAR struct udp_conn_s *)conn->sconn.node.flink;
|
2015-01-17 21:13:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_IPv4 */
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: udp_ipv6_active
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Find a connection structure that is the appropriate connection to be
|
|
|
|
* used within the provided UDP header
|
|
|
|
*
|
|
|
|
* Assumptions:
|
2017-09-02 18:27:03 +02:00
|
|
|
* This function must be called with the network locked.
|
2015-01-17 21:13:56 +01:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
static inline FAR struct udp_conn_s *
|
2024-03-27 10:15:44 +01:00
|
|
|
udp_ipv6_active(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn,
|
|
|
|
FAR struct udp_hdr_s *udp)
|
2015-01-17 21:13:56 +01:00
|
|
|
{
|
2015-01-18 15:56:05 +01:00
|
|
|
FAR struct ipv6_hdr_s *ip = IPv6BUF;
|
2015-01-17 21:13:56 +01:00
|
|
|
|
2024-03-27 10:15:44 +01:00
|
|
|
conn = udp_nextconn(conn);
|
|
|
|
|
net/udp: Resolve race condition in connection-less UDP sockets with read-ahead buffering.
In connection-mode UDP sockets, a remote address is retained in the UDP connection structure. This determines both there send() will send the packets and which packets recv() will accept.
This same mechanism is used for connection-less UDP sendto: A temporary remote address is written into the connection structure to support the sendto() operation. That address persists until the next recvfrom() when it is reset to accept any address.
When UDP read-ahead buffering is enabled, however, that means that the old, invalid remote address can be left in the connection structure for some time. This can cause read-ahead buffer to fail, dropping UDP packets.
Shortening the time between when he remote address is reset (i.e., immediately after the sendto() completes) is not a solution, that does not eliminate the race condition; in only makes it smaller.
With this change, a flag was added to the connection structure to indicate if the UDP socket is in connection mode or if it is connection-less. This change effects only UDP receive operations: The remote address in the UDP connection is always ignored if the UDP socket is not in connection-mode.
No for connection-mode sockets, that remote address behaves as before. But for connection-less sockets, it is only used by sendto().
2018-05-13 17:57:34 +02:00
|
|
|
while (conn != NULL)
|
2015-01-17 21:13:56 +01:00
|
|
|
{
|
|
|
|
/* If the local UDP port is non-zero, the connection is considered
|
|
|
|
* to be used. If so, then the following checks are performed:
|
|
|
|
*
|
net/udp: Resolve race condition in connection-less UDP sockets with read-ahead buffering.
In connection-mode UDP sockets, a remote address is retained in the UDP connection structure. This determines both there send() will send the packets and which packets recv() will accept.
This same mechanism is used for connection-less UDP sendto: A temporary remote address is written into the connection structure to support the sendto() operation. That address persists until the next recvfrom() when it is reset to accept any address.
When UDP read-ahead buffering is enabled, however, that means that the old, invalid remote address can be left in the connection structure for some time. This can cause read-ahead buffer to fail, dropping UDP packets.
Shortening the time between when he remote address is reset (i.e., immediately after the sendto() completes) is not a solution, that does not eliminate the race condition; in only makes it smaller.
With this change, a flag was added to the connection structure to indicate if the UDP socket is in connection mode or if it is connection-less. This change effects only UDP receive operations: The remote address in the UDP connection is always ignored if the UDP socket is not in connection-mode.
No for connection-mode sockets, that remote address behaves as before. But for connection-less sockets, it is only used by sendto().
2018-05-13 17:57:34 +02:00
|
|
|
* 1. The destination address is verified against the bound address
|
|
|
|
* of the connection.
|
|
|
|
*
|
|
|
|
* - The local port number is checked against the destination port
|
|
|
|
* number in the received packet.
|
|
|
|
* - If multiple network interfaces are supported, then the local
|
|
|
|
* IP address is available and we will insist that the
|
|
|
|
* destination IP matches the bound address. If a socket is bound
|
|
|
|
* to INADDR6_ANY (laddr), then it should receive all packets
|
2019-03-11 19:48:17 +01:00
|
|
|
* directed to the port. REVISIT: Should also depend on
|
|
|
|
* SO_BROADCAST.
|
net/udp: Resolve race condition in connection-less UDP sockets with read-ahead buffering.
In connection-mode UDP sockets, a remote address is retained in the UDP connection structure. This determines both there send() will send the packets and which packets recv() will accept.
This same mechanism is used for connection-less UDP sendto: A temporary remote address is written into the connection structure to support the sendto() operation. That address persists until the next recvfrom() when it is reset to accept any address.
When UDP read-ahead buffering is enabled, however, that means that the old, invalid remote address can be left in the connection structure for some time. This can cause read-ahead buffer to fail, dropping UDP packets.
Shortening the time between when he remote address is reset (i.e., immediately after the sendto() completes) is not a solution, that does not eliminate the race condition; in only makes it smaller.
With this change, a flag was added to the connection structure to indicate if the UDP socket is in connection mode or if it is connection-less. This change effects only UDP receive operations: The remote address in the UDP connection is always ignored if the UDP socket is not in connection-mode.
No for connection-mode sockets, that remote address behaves as before. But for connection-less sockets, it is only used by sendto().
2018-05-13 17:57:34 +02:00
|
|
|
*
|
|
|
|
* 2. If this is a connection mode UDP socket, then the source address
|
|
|
|
* is verified against the connected remote address.
|
|
|
|
*
|
|
|
|
* - The remote port number is checked if the connection is bound
|
|
|
|
* to a remote port.
|
|
|
|
* - Finally, if the connection is bound to a remote IP address,
|
|
|
|
* the source IP address of the packet is checked.
|
2015-01-17 21:13:56 +01:00
|
|
|
*
|
|
|
|
* If all of the above are true then the newly received UDP packet
|
|
|
|
* is destined for this UDP connection.
|
2017-08-07 19:50:50 +02:00
|
|
|
*
|
2017-08-07 21:03:23 +02:00
|
|
|
* To send and receive multicast packets, the application should:
|
2017-08-07 19:50:50 +02:00
|
|
|
*
|
net/udp: Resolve race condition in connection-less UDP sockets with read-ahead buffering.
In connection-mode UDP sockets, a remote address is retained in the UDP connection structure. This determines both there send() will send the packets and which packets recv() will accept.
This same mechanism is used for connection-less UDP sendto: A temporary remote address is written into the connection structure to support the sendto() operation. That address persists until the next recvfrom() when it is reset to accept any address.
When UDP read-ahead buffering is enabled, however, that means that the old, invalid remote address can be left in the connection structure for some time. This can cause read-ahead buffer to fail, dropping UDP packets.
Shortening the time between when he remote address is reset (i.e., immediately after the sendto() completes) is not a solution, that does not eliminate the race condition; in only makes it smaller.
With this change, a flag was added to the connection structure to indicate if the UDP socket is in connection mode or if it is connection-less. This change effects only UDP receive operations: The remote address in the UDP connection is always ignored if the UDP socket is not in connection-mode.
No for connection-mode sockets, that remote address behaves as before. But for connection-less sockets, it is only used by sendto().
2018-05-13 17:57:34 +02:00
|
|
|
* - Bind socket to INADDR6_ANY (for the all-nodes multicast address)
|
|
|
|
* or to a specific <multicast-address>
|
|
|
|
* - setsockopt to SO_BROADCAST (for all-nodes address)
|
|
|
|
*
|
|
|
|
* For connection-less UDP sockets:
|
|
|
|
*
|
|
|
|
* - call sendto with sendaddr.sin_addr.s_addr = <multicast-address>
|
|
|
|
* - call recvfrom.
|
|
|
|
*
|
|
|
|
* For connection-mode UDP sockets:
|
|
|
|
*
|
|
|
|
* - call connect() to connect the UDP socket to a specific remote
|
|
|
|
* address, then
|
|
|
|
* - Call send() with no address address information
|
|
|
|
* - call recv() (from address information should not be needed)
|
2017-08-07 19:50:50 +02:00
|
|
|
*
|
2021-12-20 15:49:48 +01:00
|
|
|
* REVISIT: SO_BROADCAST flag is currently ignored.
|
2015-01-17 21:13:56 +01:00
|
|
|
*/
|
|
|
|
|
2021-12-20 15:49:48 +01:00
|
|
|
/* Check that there is a local port number and this matches
|
net/udp: Resolve race condition in connection-less UDP sockets with read-ahead buffering.
In connection-mode UDP sockets, a remote address is retained in the UDP connection structure. This determines both there send() will send the packets and which packets recv() will accept.
This same mechanism is used for connection-less UDP sendto: A temporary remote address is written into the connection structure to support the sendto() operation. That address persists until the next recvfrom() when it is reset to accept any address.
When UDP read-ahead buffering is enabled, however, that means that the old, invalid remote address can be left in the connection structure for some time. This can cause read-ahead buffer to fail, dropping UDP packets.
Shortening the time between when he remote address is reset (i.e., immediately after the sendto() completes) is not a solution, that does not eliminate the race condition; in only makes it smaller.
With this change, a flag was added to the connection structure to indicate if the UDP socket is in connection mode or if it is connection-less. This change effects only UDP receive operations: The remote address in the UDP connection is always ignored if the UDP socket is not in connection-mode.
No for connection-mode sockets, that remote address behaves as before. But for connection-less sockets, it is only used by sendto().
2018-05-13 17:57:34 +02:00
|
|
|
* the port number in the destination address.
|
|
|
|
*/
|
2017-08-08 15:48:07 +02:00
|
|
|
|
net/udp: Resolve race condition in connection-less UDP sockets with read-ahead buffering.
In connection-mode UDP sockets, a remote address is retained in the UDP connection structure. This determines both there send() will send the packets and which packets recv() will accept.
This same mechanism is used for connection-less UDP sendto: A temporary remote address is written into the connection structure to support the sendto() operation. That address persists until the next recvfrom() when it is reset to accept any address.
When UDP read-ahead buffering is enabled, however, that means that the old, invalid remote address can be left in the connection structure for some time. This can cause read-ahead buffer to fail, dropping UDP packets.
Shortening the time between when he remote address is reset (i.e., immediately after the sendto() completes) is not a solution, that does not eliminate the race condition; in only makes it smaller.
With this change, a flag was added to the connection structure to indicate if the UDP socket is in connection mode or if it is connection-less. This change effects only UDP receive operations: The remote address in the UDP connection is always ignored if the UDP socket is not in connection-mode.
No for connection-mode sockets, that remote address behaves as before. But for connection-less sockets, it is only used by sendto().
2018-05-13 17:57:34 +02:00
|
|
|
if ((conn->lport != 0 && udp->destport == conn->lport &&
|
|
|
|
|
|
|
|
/* Check if the local port accepts any address on this port or
|
|
|
|
* that there is an exact match between the destipaddr and the
|
|
|
|
* bound local address. This catches the case of the all nodes
|
2018-06-23 20:53:27 +02:00
|
|
|
* multicast when the socket is bound to the IPv6 unspecified
|
|
|
|
* address.
|
2017-08-08 15:48:07 +02:00
|
|
|
*/
|
|
|
|
|
2018-06-23 20:53:27 +02:00
|
|
|
(net_ipv6addr_cmp(conn->u.ipv6.laddr, g_ipv6_unspecaddr) ||
|
net/udp: Resolve race condition in connection-less UDP sockets with read-ahead buffering.
In connection-mode UDP sockets, a remote address is retained in the UDP connection structure. This determines both there send() will send the packets and which packets recv() will accept.
This same mechanism is used for connection-less UDP sendto: A temporary remote address is written into the connection structure to support the sendto() operation. That address persists until the next recvfrom() when it is reset to accept any address.
When UDP read-ahead buffering is enabled, however, that means that the old, invalid remote address can be left in the connection structure for some time. This can cause read-ahead buffer to fail, dropping UDP packets.
Shortening the time between when he remote address is reset (i.e., immediately after the sendto() completes) is not a solution, that does not eliminate the race condition; in only makes it smaller.
With this change, a flag was added to the connection structure to indicate if the UDP socket is in connection mode or if it is connection-less. This change effects only UDP receive operations: The remote address in the UDP connection is always ignored if the UDP socket is not in connection-mode.
No for connection-mode sockets, that remote address behaves as before. But for connection-less sockets, it is only used by sendto().
2018-05-13 17:57:34 +02:00
|
|
|
net_ipv6addr_hdrcmp(ip->destipaddr, conn->u.ipv6.laddr))))
|
|
|
|
{
|
|
|
|
/* Check if the socket is connection mode. In this case, only
|
|
|
|
* packets with source addresses from the connected remote peer
|
|
|
|
* will be accepted.
|
2017-08-08 15:48:07 +02:00
|
|
|
*/
|
|
|
|
|
net/udp: Resolve race condition in connection-less UDP sockets with read-ahead buffering.
In connection-mode UDP sockets, a remote address is retained in the UDP connection structure. This determines both there send() will send the packets and which packets recv() will accept.
This same mechanism is used for connection-less UDP sendto: A temporary remote address is written into the connection structure to support the sendto() operation. That address persists until the next recvfrom() when it is reset to accept any address.
When UDP read-ahead buffering is enabled, however, that means that the old, invalid remote address can be left in the connection structure for some time. This can cause read-ahead buffer to fail, dropping UDP packets.
Shortening the time between when he remote address is reset (i.e., immediately after the sendto() completes) is not a solution, that does not eliminate the race condition; in only makes it smaller.
With this change, a flag was added to the connection structure to indicate if the UDP socket is in connection mode or if it is connection-less. This change effects only UDP receive operations: The remote address in the UDP connection is always ignored if the UDP socket is not in connection-mode.
No for connection-mode sockets, that remote address behaves as before. But for connection-less sockets, it is only used by sendto().
2018-05-13 17:57:34 +02:00
|
|
|
if (_UDP_ISCONNECTMODE(conn->flags))
|
|
|
|
{
|
|
|
|
/* Check if the UDP connection is either (1) accepting packets
|
|
|
|
* from any port or (2) the packet srcport matches the local
|
|
|
|
* bound port number.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ((conn->rport == 0 || udp->srcport == conn->rport) &&
|
|
|
|
|
|
|
|
/* If (1) not connected to a remote address, or (2) a all-
|
|
|
|
* nodes multicast destipaddr was received, or (3) there is an
|
|
|
|
* exact match between the srcipaddr and the bound remote IP
|
|
|
|
* address, then accept the packet.
|
|
|
|
*/
|
|
|
|
|
2018-06-23 20:53:27 +02:00
|
|
|
(net_ipv6addr_cmp(conn->u.ipv6.raddr, g_ipv6_unspecaddr) ||
|
2017-08-08 15:48:07 +02:00
|
|
|
#ifdef CONFIG_NET_BROADCAST
|
net/udp: Resolve race condition in connection-less UDP sockets with read-ahead buffering.
In connection-mode UDP sockets, a remote address is retained in the UDP connection structure. This determines both there send() will send the packets and which packets recv() will accept.
This same mechanism is used for connection-less UDP sendto: A temporary remote address is written into the connection structure to support the sendto() operation. That address persists until the next recvfrom() when it is reset to accept any address.
When UDP read-ahead buffering is enabled, however, that means that the old, invalid remote address can be left in the connection structure for some time. This can cause read-ahead buffer to fail, dropping UDP packets.
Shortening the time between when he remote address is reset (i.e., immediately after the sendto() completes) is not a solution, that does not eliminate the race condition; in only makes it smaller.
With this change, a flag was added to the connection structure to indicate if the UDP socket is in connection mode or if it is connection-less. This change effects only UDP receive operations: The remote address in the UDP connection is always ignored if the UDP socket is not in connection-mode.
No for connection-mode sockets, that remote address behaves as before. But for connection-less sockets, it is only used by sendto().
2018-05-13 17:57:34 +02:00
|
|
|
net_ipv6addr_hdrcmp(ip->destipaddr, g_ipv6_allnodes) ||
|
2017-08-08 15:48:07 +02:00
|
|
|
#endif
|
net/udp: Resolve race condition in connection-less UDP sockets with read-ahead buffering.
In connection-mode UDP sockets, a remote address is retained in the UDP connection structure. This determines both there send() will send the packets and which packets recv() will accept.
This same mechanism is used for connection-less UDP sendto: A temporary remote address is written into the connection structure to support the sendto() operation. That address persists until the next recvfrom() when it is reset to accept any address.
When UDP read-ahead buffering is enabled, however, that means that the old, invalid remote address can be left in the connection structure for some time. This can cause read-ahead buffer to fail, dropping UDP packets.
Shortening the time between when he remote address is reset (i.e., immediately after the sendto() completes) is not a solution, that does not eliminate the race condition; in only makes it smaller.
With this change, a flag was added to the connection structure to indicate if the UDP socket is in connection mode or if it is connection-less. This change effects only UDP receive operations: The remote address in the UDP connection is always ignored if the UDP socket is not in connection-mode.
No for connection-mode sockets, that remote address behaves as before. But for connection-less sockets, it is only used by sendto().
2018-05-13 17:57:34 +02:00
|
|
|
net_ipv6addr_hdrcmp(ip->srcipaddr, conn->u.ipv6.raddr)))
|
|
|
|
{
|
|
|
|
/* Matching connection found.. Break out of the loop and
|
|
|
|
* return this reference to it.
|
|
|
|
*/
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* This UDP socket is not connected. We need to match only
|
|
|
|
* the destination address with the bound socket address.
|
|
|
|
* Break out out of the loop and return this reference to
|
|
|
|
* the matching connection structure.
|
|
|
|
*/
|
2015-01-17 21:13:56 +01:00
|
|
|
|
net/udp: Resolve race condition in connection-less UDP sockets with read-ahead buffering.
In connection-mode UDP sockets, a remote address is retained in the UDP connection structure. This determines both there send() will send the packets and which packets recv() will accept.
This same mechanism is used for connection-less UDP sendto: A temporary remote address is written into the connection structure to support the sendto() operation. That address persists until the next recvfrom() when it is reset to accept any address.
When UDP read-ahead buffering is enabled, however, that means that the old, invalid remote address can be left in the connection structure for some time. This can cause read-ahead buffer to fail, dropping UDP packets.
Shortening the time between when he remote address is reset (i.e., immediately after the sendto() completes) is not a solution, that does not eliminate the race condition; in only makes it smaller.
With this change, a flag was added to the connection structure to indicate if the UDP socket is in connection mode or if it is connection-less. This change effects only UDP receive operations: The remote address in the UDP connection is always ignored if the UDP socket is not in connection-mode.
No for connection-mode sockets, that remote address behaves as before. But for connection-less sockets, it is only used by sendto().
2018-05-13 17:57:34 +02:00
|
|
|
break;
|
|
|
|
}
|
2015-01-17 21:13:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Look at the next active connection */
|
|
|
|
|
2022-02-07 04:34:18 +01:00
|
|
|
conn = (FAR struct udp_conn_s *)conn->sconn.node.flink;
|
2015-01-17 21:13:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_IPv6 */
|
|
|
|
|
2021-12-31 08:20:29 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: udp_alloc_conn
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Allocate a uninitialized UDP connection structure.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2023-02-02 15:20:55 +01:00
|
|
|
#if CONFIG_NET_UDP_ALLOC_CONNS > 0
|
2023-05-30 07:28:05 +02:00
|
|
|
static FAR struct udp_conn_s *udp_alloc_conn(void)
|
2021-12-31 08:20:29 +01:00
|
|
|
{
|
|
|
|
FAR struct udp_conn_s *conn;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Return the entry from the head of the free list */
|
|
|
|
|
|
|
|
if (dq_peek(&g_free_udp_connections) == NULL)
|
|
|
|
{
|
2023-02-02 15:20:55 +01:00
|
|
|
#if CONFIG_NET_UDP_MAX_CONNS > 0
|
2024-04-06 15:07:06 +02:00
|
|
|
if (dq_count(&g_active_udp_connections) +
|
|
|
|
CONFIG_NET_UDP_ALLOC_CONNS > CONFIG_NET_UDP_MAX_CONNS)
|
2023-02-02 15:20:55 +01:00
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2021-12-31 08:20:29 +01:00
|
|
|
conn = kmm_zalloc(sizeof(struct udp_conn_s) *
|
2023-02-02 15:20:55 +01:00
|
|
|
CONFIG_NET_UDP_ALLOC_CONNS);
|
2021-12-31 08:20:29 +01:00
|
|
|
if (conn == NULL)
|
|
|
|
{
|
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now initialize each connection structure */
|
|
|
|
|
2023-02-02 15:20:55 +01:00
|
|
|
for (i = 0; i < CONFIG_NET_UDP_ALLOC_CONNS; i++)
|
2021-12-31 08:20:29 +01:00
|
|
|
{
|
|
|
|
/* Mark the connection closed and move it to the free list */
|
|
|
|
|
|
|
|
conn[i].lport = 0;
|
2022-02-07 04:34:18 +01:00
|
|
|
dq_addlast(&conn[i].sconn.node, &g_free_udp_connections);
|
2021-12-31 08:20:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (FAR struct udp_conn_s *)dq_remfirst(&g_free_udp_connections);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-09-03 22:34:44 +02:00
|
|
|
/****************************************************************************
|
2007-09-02 23:58:35 +02:00
|
|
|
* Public Functions
|
2007-09-03 22:34:44 +02:00
|
|
|
****************************************************************************/
|
2007-09-02 23:58:35 +02:00
|
|
|
|
2021-12-17 07:35:51 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: udp_select_port
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Select an unused port number.
|
|
|
|
*
|
|
|
|
* NOTE that in principle this function could fail if there is no available
|
|
|
|
* port number. There is no check for that case and it would actually
|
|
|
|
* in an infinite loop if that were the case. In this simple, small UDP
|
|
|
|
* implementation, it is reasonable to assume that that error cannot happen
|
|
|
|
* and that a port number will always be available.
|
|
|
|
*
|
|
|
|
* Input Parameters:
|
|
|
|
* None
|
|
|
|
*
|
|
|
|
* Returned Value:
|
2024-04-12 05:11:54 +02:00
|
|
|
* Next available port number in host byte order, 0 for failure.
|
2021-12-17 07:35:51 +01:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
uint16_t udp_select_port(uint8_t domain, FAR union ip_binding_u *u)
|
|
|
|
{
|
|
|
|
static uint16_t g_last_udp_port;
|
|
|
|
uint16_t portno;
|
|
|
|
|
|
|
|
net_lock();
|
|
|
|
|
|
|
|
/* Generate port base dynamically */
|
|
|
|
|
|
|
|
if (g_last_udp_port == 0)
|
|
|
|
{
|
2024-04-12 05:11:54 +02:00
|
|
|
NET_PORT_RANDOM_INIT(g_last_udp_port);
|
2021-12-17 07:35:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Find an unused local port number. Loop until we find a valid
|
|
|
|
* listen port number that is not being used by any other connection.
|
|
|
|
*/
|
|
|
|
|
2024-04-12 05:11:54 +02:00
|
|
|
portno = g_last_udp_port; /* Record a starting port number */
|
|
|
|
|
2021-12-17 07:35:51 +01:00
|
|
|
do
|
|
|
|
{
|
2024-04-12 05:11:54 +02:00
|
|
|
NET_PORT_NEXT_H(g_last_udp_port);
|
|
|
|
if (g_last_udp_port == portno)
|
2021-12-17 07:35:51 +01:00
|
|
|
{
|
2024-04-12 05:11:54 +02:00
|
|
|
/* We have looped back, failed. */
|
|
|
|
|
|
|
|
portno = 0;
|
|
|
|
goto errout;
|
2021-12-17 07:35:51 +01:00
|
|
|
}
|
|
|
|
}
|
2023-02-02 04:24:46 +01:00
|
|
|
while (udp_find_conn(domain, u, HTONS(g_last_udp_port), 0) != NULL
|
2024-03-18 11:41:38 +01:00
|
|
|
#ifdef CONFIG_NET_NAT
|
|
|
|
|| nat_port_inuse(domain, IP_PROTO_UDP, (FAR union ip_addr_u *)u,
|
|
|
|
HTONS(g_last_udp_port))
|
2022-11-03 07:26:21 +01:00
|
|
|
#endif
|
|
|
|
);
|
2021-12-17 07:35:51 +01:00
|
|
|
|
|
|
|
/* Initialize and return the connection structure, bind it to the
|
|
|
|
* port number
|
|
|
|
*/
|
|
|
|
|
|
|
|
portno = g_last_udp_port;
|
2024-04-12 05:11:54 +02:00
|
|
|
|
|
|
|
errout:
|
2021-12-17 07:35:51 +01:00
|
|
|
net_unlock();
|
|
|
|
|
|
|
|
return portno;
|
|
|
|
}
|
|
|
|
|
2007-09-03 01:11:10 +02:00
|
|
|
/****************************************************************************
|
2015-01-17 20:07:48 +01:00
|
|
|
* Name: udp_initialize
|
2007-09-03 01:11:10 +02:00
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Initialize the UDP connection structures. Called once and only from
|
|
|
|
* the UIP layer.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
2007-09-02 23:58:35 +02:00
|
|
|
|
2014-06-25 02:55:01 +02:00
|
|
|
void udp_initialize(void)
|
2007-09-03 01:11:10 +02:00
|
|
|
{
|
2023-02-02 15:20:55 +01:00
|
|
|
#if CONFIG_NET_UDP_PREALLOC_CONNS > 0
|
2007-09-03 01:11:10 +02:00
|
|
|
int i;
|
2007-09-03 22:34:44 +02:00
|
|
|
|
2023-02-02 15:20:55 +01:00
|
|
|
for (i = 0; i < CONFIG_NET_UDP_PREALLOC_CONNS; i++)
|
2007-09-03 01:11:10 +02:00
|
|
|
{
|
2007-09-03 22:34:44 +02:00
|
|
|
/* Mark the connection closed and move it to the free list */
|
|
|
|
|
|
|
|
g_udp_connections[i].lport = 0;
|
2022-02-07 04:34:18 +01:00
|
|
|
dq_addlast(&g_udp_connections[i].sconn.node, &g_free_udp_connections);
|
2007-09-03 01:11:10 +02:00
|
|
|
}
|
2021-12-31 08:20:29 +01:00
|
|
|
#endif
|
2007-09-03 01:11:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
2015-01-17 20:07:48 +01:00
|
|
|
* Name: udp_alloc
|
2007-09-03 01:11:10 +02:00
|
|
|
*
|
|
|
|
* Description:
|
2014-07-05 22:40:29 +02:00
|
|
|
* Allocate a new, uninitialized UDP connection structure. This is
|
|
|
|
* normally something done by the implementation of the socket() API
|
2007-09-03 01:11:10 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2015-01-17 20:07:48 +01:00
|
|
|
FAR struct udp_conn_s *udp_alloc(uint8_t domain)
|
2007-09-03 01:11:10 +02:00
|
|
|
{
|
2014-06-25 02:55:01 +02:00
|
|
|
FAR struct udp_conn_s *conn;
|
2007-09-03 22:34:44 +02:00
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
/* The free list is protected by a mutex. */
|
2007-09-03 22:34:44 +02:00
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_lock(&g_free_lock);
|
2023-02-02 15:20:55 +01:00
|
|
|
|
2014-06-25 02:55:01 +02:00
|
|
|
conn = (FAR struct udp_conn_s *)dq_remfirst(&g_free_udp_connections);
|
2023-02-02 15:20:55 +01:00
|
|
|
|
|
|
|
#if CONFIG_NET_UDP_ALLOC_CONNS > 0
|
|
|
|
if (conn == NULL)
|
|
|
|
{
|
|
|
|
conn = udp_alloc_conn();
|
|
|
|
}
|
2021-12-31 08:20:29 +01:00
|
|
|
#endif
|
2023-02-02 15:20:55 +01:00
|
|
|
|
2007-09-03 22:34:44 +02:00
|
|
|
if (conn)
|
|
|
|
{
|
2007-09-09 21:47:52 +02:00
|
|
|
/* Make sure that the connection is marked as uninitialized */
|
2007-09-03 22:34:44 +02:00
|
|
|
|
2024-05-29 13:35:34 +02:00
|
|
|
conn->sconn.s_ttl = IP_TTL_DEFAULT;
|
|
|
|
conn->flags = 0;
|
2023-06-27 04:50:22 +02:00
|
|
|
#if defined(CONFIG_NET_IPv4) || defined(CONFIG_NET_IPv6)
|
2024-05-29 13:35:34 +02:00
|
|
|
conn->domain = domain;
|
2018-06-25 23:07:53 +02:00
|
|
|
#endif
|
2024-05-29 13:35:34 +02:00
|
|
|
conn->lport = 0;
|
2021-07-05 10:01:48 +02:00
|
|
|
#if CONFIG_NET_RECV_BUFSIZE > 0
|
2024-05-29 13:35:34 +02:00
|
|
|
conn->rcvbufs = CONFIG_NET_RECV_BUFSIZE;
|
2021-07-05 10:01:48 +02:00
|
|
|
#endif
|
2021-07-19 15:45:46 +02:00
|
|
|
#if CONFIG_NET_SEND_BUFSIZE > 0
|
2024-05-29 13:35:34 +02:00
|
|
|
conn->sndbufs = CONFIG_NET_SEND_BUFSIZE;
|
2021-07-19 15:45:46 +02:00
|
|
|
|
|
|
|
nxsem_init(&conn->sndsem, 0, 0);
|
|
|
|
#endif
|
2013-10-11 18:48:00 +02:00
|
|
|
|
2018-03-30 23:30:45 +02:00
|
|
|
#ifdef CONFIG_NET_UDP_WRITE_BUFFERS
|
2018-01-23 01:32:02 +01:00
|
|
|
/* Initialize the write buffer lists */
|
|
|
|
|
|
|
|
sq_init(&conn->write_q);
|
|
|
|
#endif
|
2013-10-11 18:48:00 +02:00
|
|
|
/* Enqueue the connection into the active list */
|
|
|
|
|
2022-02-07 04:34:18 +01:00
|
|
|
dq_addlast(&conn->sconn.node, &g_active_udp_connections);
|
2007-09-03 22:34:44 +02:00
|
|
|
}
|
2014-04-12 20:13:01 +02:00
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&g_free_lock);
|
2007-09-03 22:34:44 +02:00
|
|
|
return conn;
|
2007-09-03 01:11:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
2015-01-17 20:07:48 +01:00
|
|
|
* Name: udp_free
|
2007-09-03 01:11:10 +02:00
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Free a UDP connection structure that is no longer in use. This should be
|
2014-07-05 22:40:29 +02:00
|
|
|
* done by the implementation of close().
|
2007-09-03 01:11:10 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2014-06-25 02:55:01 +02:00
|
|
|
void udp_free(FAR struct udp_conn_s *conn)
|
2007-09-03 01:11:10 +02:00
|
|
|
{
|
2018-01-23 01:32:02 +01:00
|
|
|
#ifdef CONFIG_NET_UDP_WRITE_BUFFERS
|
|
|
|
FAR struct udp_wrbuffer_s *wrbuffer;
|
|
|
|
#endif
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
/* The free list is protected by a mutex. */
|
2007-09-03 22:34:44 +02:00
|
|
|
|
2009-06-15 20:58:22 +02:00
|
|
|
DEBUGASSERT(conn->crefs == 0);
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_lock(&g_free_lock);
|
2007-09-03 22:34:44 +02:00
|
|
|
conn->lport = 0;
|
2013-10-11 18:48:00 +02:00
|
|
|
|
|
|
|
/* Remove the connection from the active list */
|
|
|
|
|
2022-02-07 04:34:18 +01:00
|
|
|
dq_rem(&conn->sconn.node, &g_active_udp_connections);
|
2013-10-11 18:48:00 +02:00
|
|
|
|
2023-07-04 07:24:51 +02:00
|
|
|
/* Release any read-ahead buffers attached to the connection, NULL is ok */
|
2015-01-30 16:44:00 +01:00
|
|
|
|
2023-07-04 07:24:51 +02:00
|
|
|
iob_free_chain(conn->readahead);
|
2015-01-30 16:44:00 +01:00
|
|
|
|
2018-01-23 01:32:02 +01:00
|
|
|
#ifdef CONFIG_NET_UDP_WRITE_BUFFERS
|
|
|
|
/* Release any write buffers attached to the connection */
|
|
|
|
|
2019-03-11 19:48:17 +01:00
|
|
|
while ((wrbuffer = (struct udp_wrbuffer_s *)
|
|
|
|
sq_remfirst(&conn->write_q)) != NULL)
|
2018-01-23 01:32:02 +01:00
|
|
|
{
|
|
|
|
udp_wrbuffer_release(wrbuffer);
|
|
|
|
}
|
2021-07-19 15:45:46 +02:00
|
|
|
|
|
|
|
#if CONFIG_NET_SEND_BUFSIZE > 0
|
|
|
|
/* Notify the send buffer available */
|
|
|
|
|
|
|
|
udp_sendbuffer_notify(conn);
|
|
|
|
#endif /* CONFIG_NET_SEND_BUFSIZE */
|
|
|
|
|
2018-01-23 01:32:02 +01:00
|
|
|
#endif
|
|
|
|
|
2023-02-02 15:20:55 +01:00
|
|
|
/* Free the connection.
|
|
|
|
* If this is a preallocated or a batch allocated connection store it in
|
|
|
|
* the free connections list. Else free it.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#if CONFIG_NET_UDP_ALLOC_CONNS == 1
|
|
|
|
if (conn < g_udp_connections || conn >= (g_udp_connections +
|
|
|
|
CONFIG_NET_UDP_PREALLOC_CONNS))
|
|
|
|
{
|
|
|
|
kmm_free(conn);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
2023-02-28 11:31:21 +01:00
|
|
|
memset(conn, 0, sizeof(*conn));
|
2023-02-02 15:20:55 +01:00
|
|
|
dq_addlast(&conn->sconn.node, &g_free_udp_connections);
|
|
|
|
}
|
2013-10-11 18:48:00 +02:00
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&g_free_lock);
|
2007-09-03 01:11:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
2015-01-17 20:07:48 +01:00
|
|
|
* Name: udp_active
|
2007-09-03 01:11:10 +02:00
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Find a connection structure that is the appropriate
|
2014-11-08 13:18:21 +01:00
|
|
|
* connection to be used within the provided UDP header
|
2007-09-03 01:11:10 +02:00
|
|
|
*
|
|
|
|
* Assumptions:
|
2017-09-02 18:27:03 +02:00
|
|
|
* This function must be called with the network locked.
|
2007-09-03 01:11:10 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2015-01-15 22:06:46 +01:00
|
|
|
FAR struct udp_conn_s *udp_active(FAR struct net_driver_s *dev,
|
2024-03-27 10:15:44 +01:00
|
|
|
FAR struct udp_conn_s *conn,
|
2015-01-15 22:06:46 +01:00
|
|
|
FAR struct udp_hdr_s *udp)
|
2007-09-03 01:11:10 +02:00
|
|
|
{
|
2015-01-17 21:13:56 +01:00
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
if (IFF_IS_IPv6(dev->d_flags))
|
|
|
|
#endif
|
2007-09-03 01:11:10 +02:00
|
|
|
{
|
2024-03-27 10:15:44 +01:00
|
|
|
return udp_ipv6_active(dev, conn, udp);
|
2015-01-17 21:13:56 +01:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_IPv6 */
|
2007-09-03 01:11:10 +02:00
|
|
|
|
2015-01-17 21:13:56 +01:00
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
else
|
2014-11-22 00:44:12 +01:00
|
|
|
#endif
|
2015-01-17 21:13:56 +01:00
|
|
|
{
|
2024-03-27 10:15:44 +01:00
|
|
|
return udp_ipv4_active(dev, conn, udp);
|
2007-09-03 22:34:44 +02:00
|
|
|
}
|
2015-01-17 21:13:56 +01:00
|
|
|
#endif /* CONFIG_NET_IPv4 */
|
2007-09-03 01:11:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
2015-01-17 20:07:48 +01:00
|
|
|
* Name: udp_nextconn
|
2007-09-03 01:11:10 +02:00
|
|
|
*
|
|
|
|
* Description:
|
2007-11-06 00:04:16 +01:00
|
|
|
* Traverse the list of allocated UDP connections
|
2007-09-03 01:11:10 +02:00
|
|
|
*
|
|
|
|
* Assumptions:
|
2017-09-02 18:27:03 +02:00
|
|
|
* This function must be called with the network locked.
|
2007-09-03 01:11:10 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2014-07-01 02:03:58 +02:00
|
|
|
FAR struct udp_conn_s *udp_nextconn(FAR struct udp_conn_s *conn)
|
2007-09-03 01:11:10 +02:00
|
|
|
{
|
2007-11-06 00:04:16 +01:00
|
|
|
if (!conn)
|
|
|
|
{
|
2014-06-25 02:55:01 +02:00
|
|
|
return (FAR struct udp_conn_s *)g_active_udp_connections.head;
|
2007-11-06 00:04:16 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-02-07 04:34:18 +01:00
|
|
|
return (FAR struct udp_conn_s *)conn->sconn.node.flink;
|
2007-11-06 00:04:16 +01:00
|
|
|
}
|
2007-09-03 01:11:10 +02:00
|
|
|
}
|
|
|
|
|
2007-10-31 01:13:07 +01:00
|
|
|
/****************************************************************************
|
2015-01-17 20:07:48 +01:00
|
|
|
* Name: udp_bind
|
2007-10-31 01:13:07 +01:00
|
|
|
*
|
|
|
|
* Description:
|
2014-11-17 22:34:50 +01:00
|
|
|
* This function implements the low level parts of the standard UDP
|
2007-10-31 01:13:07 +01:00
|
|
|
* bind() operation.
|
|
|
|
*
|
|
|
|
* Assumptions:
|
|
|
|
* This function is called from normal user level code.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2015-01-17 21:13:56 +01:00
|
|
|
int udp_bind(FAR struct udp_conn_s *conn, FAR const struct sockaddr *addr)
|
2007-10-31 01:13:07 +01:00
|
|
|
{
|
2015-01-17 21:13:56 +01:00
|
|
|
uint16_t portno;
|
2014-11-21 21:21:30 +01:00
|
|
|
int ret;
|
2023-08-03 09:19:42 +02:00
|
|
|
FAR struct net_driver_s *dev;
|
2014-11-21 21:21:30 +01:00
|
|
|
|
2023-03-27 08:45:23 +02:00
|
|
|
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
|
|
|
|
if (conn->domain != addr->sa_family)
|
|
|
|
{
|
|
|
|
nerr("ERROR: Invalid address type: %d != %d\n", conn->domain,
|
|
|
|
addr->sa_family);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2024-02-08 14:32:20 +01:00
|
|
|
/* Interrupts must be disabled while access the UDP connection list */
|
|
|
|
|
|
|
|
net_lock();
|
|
|
|
|
2015-01-17 21:13:56 +01:00
|
|
|
#ifdef CONFIG_NET_IPv4
|
2014-11-21 21:21:30 +01:00
|
|
|
#ifdef CONFIG_NET_IPv6
|
2015-01-17 21:13:56 +01:00
|
|
|
if (conn->domain == PF_INET)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
FAR const struct sockaddr_in *inaddr =
|
|
|
|
(FAR const struct sockaddr_in *)addr;
|
2014-11-21 21:21:30 +01:00
|
|
|
|
2023-08-03 09:19:42 +02:00
|
|
|
if (!net_ipv4addr_cmp(inaddr->sin_addr.s_addr, INADDR_ANY) &&
|
|
|
|
!net_ipv4addr_cmp(inaddr->sin_addr.s_addr, HTONL(INADDR_LOOPBACK)) &&
|
|
|
|
!net_ipv4addr_cmp(inaddr->sin_addr.s_addr, INADDR_BROADCAST) &&
|
|
|
|
!IN_MULTICAST(NTOHL(inaddr->sin_addr.s_addr)))
|
|
|
|
{
|
|
|
|
ret = -EADDRNOTAVAIL;
|
|
|
|
|
|
|
|
for (dev = g_netdevices; dev; dev = dev->flink)
|
|
|
|
{
|
|
|
|
if (net_ipv4addr_cmp(inaddr->sin_addr.s_addr, dev->d_ipaddr))
|
|
|
|
{
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret == -EADDRNOTAVAIL)
|
|
|
|
{
|
|
|
|
net_unlock();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-17 21:13:56 +01:00
|
|
|
/* Get the port number that we are binding to */
|
2014-11-21 21:21:30 +01:00
|
|
|
|
2015-01-17 21:13:56 +01:00
|
|
|
portno = inaddr->sin_port;
|
2014-11-21 21:21:30 +01:00
|
|
|
|
2015-01-17 21:13:56 +01:00
|
|
|
/* Bind the local IP address to the connection. NOTE this address may
|
|
|
|
* be INADDR_ANY meaning, essentially, that we are binding to all
|
|
|
|
* interfaces for receiving (Sending will use the default port).
|
|
|
|
*/
|
|
|
|
|
2015-02-10 01:15:34 +01:00
|
|
|
net_ipv4addr_copy(conn->u.ipv4.laddr, inaddr->sin_addr.s_addr);
|
2015-01-17 21:13:56 +01:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_IPv4 */
|
2014-11-21 21:21:30 +01:00
|
|
|
|
2015-01-17 21:13:56 +01:00
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
else
|
2014-11-21 21:21:30 +01:00
|
|
|
#endif
|
2015-01-17 21:13:56 +01:00
|
|
|
{
|
|
|
|
FAR const struct sockaddr_in6 *inaddr =
|
|
|
|
(FAR const struct sockaddr_in6 *)addr;
|
2014-11-21 21:21:30 +01:00
|
|
|
|
2023-08-03 09:19:42 +02:00
|
|
|
if (!net_ipv6addr_cmp(inaddr->sin6_addr.in6_u.u6_addr16,
|
|
|
|
g_ipv6_unspecaddr) &&
|
|
|
|
!net_ipv6addr_cmp(inaddr->sin6_addr.in6_u.u6_addr16,
|
|
|
|
g_ipv6_loopback) &&
|
|
|
|
!net_ipv6addr_cmp(inaddr->sin6_addr.in6_u.u6_addr16,
|
|
|
|
g_ipv6_allnodes) &&
|
|
|
|
!net_ipv6addr_cmp(inaddr->sin6_addr.in6_u.u6_addr16, g_ipv6_allnodes))
|
|
|
|
{
|
|
|
|
ret = -EADDRNOTAVAIL;
|
|
|
|
|
|
|
|
for (dev = g_netdevices; dev; dev = dev->flink)
|
|
|
|
{
|
2023-08-25 11:37:11 +02:00
|
|
|
if (NETDEV_IS_MY_V6ADDR(dev,
|
|
|
|
inaddr->sin6_addr.in6_u.u6_addr16))
|
2023-08-03 09:19:42 +02:00
|
|
|
{
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret == -EADDRNOTAVAIL)
|
|
|
|
{
|
|
|
|
net_unlock();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-17 21:13:56 +01:00
|
|
|
/* Get the port number that we are binding to */
|
2014-11-22 00:00:08 +01:00
|
|
|
|
2015-01-21 01:14:09 +01:00
|
|
|
portno = inaddr->sin6_port;
|
2015-01-17 21:13:56 +01:00
|
|
|
|
|
|
|
/* Bind the local IP address to the connection. NOTE this address may
|
|
|
|
* be INADDR_ANY meaning, essentially, that we are binding to all
|
|
|
|
* interfaces for receiving (Sending will use the default port).
|
|
|
|
*/
|
|
|
|
|
2019-03-11 19:48:17 +01:00
|
|
|
net_ipv6addr_copy(conn->u.ipv6.laddr,
|
|
|
|
inaddr->sin6_addr.in6_u.u6_addr16);
|
2015-01-17 21:13:56 +01:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_IPv6 */
|
2007-11-23 20:25:39 +01:00
|
|
|
|
2009-03-19 01:18:21 +01:00
|
|
|
/* Is the user requesting to bind to any port? */
|
2007-11-23 20:25:39 +01:00
|
|
|
|
2015-01-17 21:13:56 +01:00
|
|
|
if (portno == 0)
|
2009-03-19 01:18:21 +01:00
|
|
|
{
|
2014-11-21 21:21:30 +01:00
|
|
|
/* Yes.. Select any unused local port number */
|
2009-03-19 01:18:21 +01:00
|
|
|
|
2024-04-12 05:11:54 +02:00
|
|
|
portno = HTONS(udp_select_port(conn->domain, &conn->u));
|
|
|
|
if (portno == 0)
|
|
|
|
{
|
|
|
|
ret = -EADDRINUSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
conn->lport = portno;
|
|
|
|
ret = OK;
|
|
|
|
}
|
2009-03-19 01:18:21 +01:00
|
|
|
}
|
|
|
|
else
|
2007-10-31 01:13:07 +01:00
|
|
|
{
|
2020-05-15 10:02:43 +02:00
|
|
|
/* Is any other UDP connection already bound to this address
|
|
|
|
* and port ?
|
|
|
|
*/
|
2007-11-23 20:25:39 +01:00
|
|
|
|
2023-02-02 04:24:46 +01:00
|
|
|
if (udp_find_conn(conn->domain, &conn->u, portno,
|
|
|
|
#ifdef CONFIG_NET_SOCKOPTS
|
|
|
|
conn->sconn.s_options
|
|
|
|
#else
|
|
|
|
0
|
|
|
|
#endif
|
|
|
|
) == NULL
|
2024-03-18 11:41:38 +01:00
|
|
|
#ifdef CONFIG_NET_NAT
|
|
|
|
&& !nat_port_inuse(conn->domain, IP_PROTO_UDP,
|
|
|
|
(FAR union ip_addr_u *)&conn->u, portno)
|
2022-11-03 07:26:21 +01:00
|
|
|
#endif
|
|
|
|
)
|
2007-11-23 20:25:39 +01:00
|
|
|
{
|
|
|
|
/* No.. then bind the socket to the port */
|
|
|
|
|
2015-01-17 21:13:56 +01:00
|
|
|
conn->lport = portno;
|
2009-03-19 01:18:21 +01:00
|
|
|
ret = OK;
|
2007-11-23 20:25:39 +01:00
|
|
|
}
|
2017-09-13 20:12:57 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
ret = -EADDRINUSE;
|
|
|
|
}
|
2007-10-31 01:13:07 +01:00
|
|
|
}
|
2014-04-12 20:13:01 +02:00
|
|
|
|
2024-02-08 14:32:20 +01:00
|
|
|
net_unlock();
|
2007-10-31 01:13:07 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2007-09-09 21:47:52 +02:00
|
|
|
/****************************************************************************
|
2015-01-17 20:07:48 +01:00
|
|
|
* Name: udp_connect
|
2007-09-09 21:47:52 +02:00
|
|
|
*
|
|
|
|
* Description:
|
2014-11-17 22:34:50 +01:00
|
|
|
* This function simply assigns a remote address to UDP "connection"
|
|
|
|
* structure. This function is called as part of the implementation of:
|
|
|
|
*
|
|
|
|
* - connect(). If connect() is called for a SOCK_DGRAM socket, then
|
2018-04-25 16:43:38 +02:00
|
|
|
* this logic performs the moral equivalent of connect() operation
|
2014-11-17 22:34:50 +01:00
|
|
|
* for the UDP socket.
|
|
|
|
* - recvfrom() and sendto(). This function is called to set the
|
|
|
|
* remote address of the peer.
|
|
|
|
*
|
|
|
|
* The function will automatically allocate an unused local port for the
|
|
|
|
* new connection if the socket is not yet bound to a local address.
|
|
|
|
* However, another port can be chosen by using the udp_bind() call,
|
|
|
|
* after the udp_connect() function has been called.
|
2007-09-09 21:47:52 +02:00
|
|
|
*
|
2014-07-05 22:40:29 +02:00
|
|
|
* Input Parameters:
|
2018-04-25 16:43:38 +02:00
|
|
|
* conn - A reference to UDP connection structure. A value of NULL will
|
|
|
|
* disconnect from any previously connected address.
|
2014-07-05 22:40:29 +02:00
|
|
|
* addr - The address of the remote host.
|
2007-09-09 21:47:52 +02:00
|
|
|
*
|
|
|
|
* Assumptions:
|
2018-04-25 16:43:38 +02:00
|
|
|
* This function is called (indirectly) from user code. Interrupts may
|
|
|
|
* be enabled.
|
2007-09-09 21:47:52 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
2007-09-02 23:58:35 +02:00
|
|
|
|
2015-01-17 21:13:56 +01:00
|
|
|
int udp_connect(FAR struct udp_conn_s *conn, FAR const struct sockaddr *addr)
|
2007-09-02 23:58:35 +02:00
|
|
|
{
|
2009-03-19 01:18:21 +01:00
|
|
|
/* Has this address already been bound to a local port (lport)? */
|
2007-09-02 23:58:35 +02:00
|
|
|
|
2007-10-31 01:13:07 +01:00
|
|
|
if (!conn->lport)
|
2007-09-02 23:58:35 +02:00
|
|
|
{
|
2009-03-19 01:18:21 +01:00
|
|
|
/* No.. Find an unused local port number and bind it to the
|
|
|
|
* connection structure.
|
2007-09-02 23:58:35 +02:00
|
|
|
*/
|
|
|
|
|
2022-01-18 08:38:00 +01:00
|
|
|
conn->lport = HTONS(udp_select_port(conn->domain, &conn->u));
|
2024-04-12 05:11:54 +02:00
|
|
|
if (!conn->lport)
|
|
|
|
{
|
|
|
|
nerr("ERROR: Failed to get a local port!\n");
|
|
|
|
return -EADDRINUSE;
|
|
|
|
}
|
2007-10-31 01:13:07 +01:00
|
|
|
}
|
2007-09-02 23:58:35 +02:00
|
|
|
|
2014-11-21 21:21:30 +01:00
|
|
|
/* Is there a remote port (rport)? */
|
2009-03-19 01:18:21 +01:00
|
|
|
|
2018-04-25 16:43:38 +02:00
|
|
|
if (addr != NULL)
|
2007-09-02 23:58:35 +02:00
|
|
|
{
|
2015-01-17 21:13:56 +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;
|
|
|
|
|
|
|
|
conn->rport = inaddr->sin_port;
|
2022-11-17 12:53:53 +01:00
|
|
|
|
|
|
|
/* Note: 0.0.0.0 is mapped to 127.0.0.1 by convention. */
|
|
|
|
|
|
|
|
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-01-17 21:13:56 +01:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_IPv4 */
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
FAR const struct sockaddr_in6 *inaddr =
|
|
|
|
(FAR const struct sockaddr_in6 *)addr;
|
|
|
|
|
2015-01-21 01:14:09 +01:00
|
|
|
conn->rport = inaddr->sin6_port;
|
2022-11-17 12:53:53 +01:00
|
|
|
|
|
|
|
/* Note: ::0 is mapped to ::1 by convention. */
|
|
|
|
|
|
|
|
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-01-17 21:13:56 +01:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_IPv6 */
|
2007-09-02 23:58:35 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-09-09 21:47:52 +02:00
|
|
|
conn->rport = 0;
|
2015-01-17 21:13:56 +01:00
|
|
|
|
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
if (conn->domain == PF_INET)
|
|
|
|
#endif
|
|
|
|
{
|
2015-05-29 23:16:11 +02:00
|
|
|
net_ipv4addr_copy(conn->u.ipv4.raddr, INADDR_ANY);
|
2015-01-17 21:13:56 +01:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_IPv4 */
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
2018-06-23 20:53:27 +02:00
|
|
|
net_ipv6addr_copy(conn->u.ipv6.raddr, g_ipv6_unspecaddr);
|
2015-01-17 21:13:56 +01:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_IPv6 */
|
2007-09-09 21:47:52 +02:00
|
|
|
}
|
2007-10-31 01:13:07 +01:00
|
|
|
|
2007-09-09 21:47:52 +02:00
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
2023-11-01 12:57:27 +01:00
|
|
|
#if defined(CONFIG_NET_IGMP)
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: udp_leavegroup
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* This function leaves the multicast group to which the conn belongs.
|
|
|
|
*
|
|
|
|
* Input Parameters:
|
|
|
|
* conn - A reference to UDP connection structure. A value of NULL will
|
|
|
|
* disconnect from any previously connected address.
|
|
|
|
*
|
|
|
|
* Assumptions:
|
|
|
|
* This function is called (indirectly) from user code. Interrupts may
|
|
|
|
* be enabled.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void udp_leavegroup(FAR struct udp_conn_s *conn)
|
|
|
|
{
|
|
|
|
if (conn->mreq.imr_multiaddr.s_addr != 0)
|
|
|
|
{
|
|
|
|
FAR struct net_driver_s *dev;
|
|
|
|
|
|
|
|
if ((dev = netdev_findbyindex(conn->mreq.imr_ifindex)) != NULL)
|
|
|
|
{
|
|
|
|
igmp_leavegroup(dev, &conn->mreq.imr_multiaddr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-09-03 01:11:10 +02:00
|
|
|
#endif /* CONFIG_NET && CONFIG_NET_UDP */
|