2015-05-29 18:45:41 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* net/udp/udp_finddev.c
|
|
|
|
*
|
|
|
|
* Copyright (C) 2015 Gregory Nutt. All rights reserved.
|
|
|
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
*
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in
|
|
|
|
* the documentation and/or other materials provided with the
|
|
|
|
* distribution.
|
|
|
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
|
|
|
* used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Included Files
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#if defined(CONFIG_NET) && defined(CONFIG_NET_UDP)
|
|
|
|
|
2015-05-30 17:12:27 +02:00
|
|
|
#include <string.h>
|
|
|
|
|
2015-05-29 18:45:41 +02:00
|
|
|
#include <nuttx/net/netdev.h>
|
|
|
|
#include <nuttx/net/ip.h>
|
|
|
|
|
|
|
|
#include "netdev/netdev.h"
|
2017-08-07 19:50:50 +02:00
|
|
|
#include "inet/inet.h"
|
2015-05-29 18:45:41 +02:00
|
|
|
#include "udp/udp.h"
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Public Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
2017-04-22 00:33:14 +02:00
|
|
|
* Name: udp_find_laddr_device
|
2015-05-29 18:45:41 +02:00
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Select the network driver to use with the UDP transaction using the
|
|
|
|
* locally bound IP address.
|
|
|
|
*
|
2018-06-22 18:09:47 +02:00
|
|
|
* This is currently used in the UDP network poll setup to determine
|
|
|
|
* which device is being polled.
|
|
|
|
*
|
2015-05-29 18:45:41 +02:00
|
|
|
* Input Parameters:
|
|
|
|
* conn - UDP connection structure (not currently used).
|
|
|
|
*
|
|
|
|
* Returned Value:
|
|
|
|
* A pointer to the network driver to use.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
FAR struct net_driver_s *udp_find_laddr_device(FAR struct udp_conn_s *conn)
|
|
|
|
{
|
|
|
|
/* There are multiple network devices. We need to select the device that
|
|
|
|
* is going to route the UDP packet based on the provided IP address.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
if (conn->domain == PF_INET)
|
|
|
|
#endif
|
|
|
|
{
|
2018-06-22 18:09:47 +02:00
|
|
|
/* Make sure that the socket is bound to some non-zero, local
|
|
|
|
* address. Zero is used as an indication that the laddr is
|
|
|
|
* uninitialized and that the socket is, hence, not bound.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (conn->u.ipv4.laddr == 0)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return netdev_findby_ipv4addr(conn->u.ipv4.laddr,
|
|
|
|
conn->u.ipv4.laddr);
|
|
|
|
}
|
2015-05-29 18:45:41 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
2018-06-22 18:09:47 +02:00
|
|
|
/* Make sure that the socket is bound to some non-zero, local
|
2018-06-23 20:53:27 +02:00
|
|
|
* address. The IPv6 unspecified address is used as an indication
|
|
|
|
* that the laddr is uninitialized and that the socket is, hence,
|
|
|
|
* not bound.
|
2018-06-22 18:09:47 +02:00
|
|
|
*/
|
|
|
|
|
2018-06-23 20:53:27 +02:00
|
|
|
if (net_ipv6addr_cmp(conn->u.ipv6.laddr, g_ipv6_unspecaddr))
|
2018-06-22 18:09:47 +02:00
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return netdev_findby_ipv6addr(conn->u.ipv6.laddr,
|
|
|
|
conn->u.ipv6.laddr);
|
|
|
|
}
|
2015-05-29 18:45:41 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
2017-04-22 00:33:14 +02:00
|
|
|
* Name: udp_find_raddr_device
|
2015-05-29 18:45:41 +02:00
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Select the network driver to use with the UDP transaction using the
|
|
|
|
* remote IP address.
|
|
|
|
*
|
2018-06-22 18:09:47 +02:00
|
|
|
* This function is called for UDP sendto() in order to determine which
|
|
|
|
* network device that the UDP pack should be sent on.
|
|
|
|
*
|
2015-05-29 18:45:41 +02:00
|
|
|
* Input Parameters:
|
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
|
|
|
* conn - UDP connection structure.
|
2015-05-29 18:45:41 +02:00
|
|
|
*
|
|
|
|
* Returned Value:
|
|
|
|
* A pointer to the network driver to use.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
FAR struct net_driver_s *udp_find_raddr_device(FAR struct udp_conn_s *conn)
|
|
|
|
{
|
2017-08-08 22:24:12 +02:00
|
|
|
/* We need to select the device that is going to route the UDP packet
|
|
|
|
* based on the provided IP address.
|
2015-05-29 18:45:41 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
if (conn->domain == PF_INET)
|
|
|
|
#endif
|
|
|
|
{
|
2018-06-22 16:19:17 +02:00
|
|
|
/* Check if the remote, destination address is the broadcast
|
2018-06-23 14:20:25 +02:00
|
|
|
* or multicast address. If this is the case, select the device
|
2018-06-22 18:09:47 +02:00
|
|
|
* using the locally bound address (assuming that there is one).
|
2018-06-22 16:19:17 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
if (conn->u.ipv4.raddr == INADDR_BROADCAST ||
|
|
|
|
IN_MULTICAST(conn->u.ipv4.raddr))
|
|
|
|
{
|
2018-06-22 18:09:47 +02:00
|
|
|
/* Make sure that the socket is bound to some non-zero, local
|
|
|
|
* address. Zero is used as an indication that the laddr is
|
|
|
|
* uninitialized and that the socket is, hence, not bound.
|
|
|
|
*/
|
|
|
|
|
2018-06-25 15:51:21 +02:00
|
|
|
if (conn->u.ipv4.laddr == 0) /* INADDR_ANY */
|
2018-06-22 18:09:47 +02:00
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return netdev_findby_ipv4addr(conn->u.ipv4.laddr,
|
|
|
|
conn->u.ipv4.laddr);
|
|
|
|
}
|
2018-06-22 16:19:17 +02:00
|
|
|
}
|
2018-06-22 18:09:47 +02:00
|
|
|
|
2018-06-25 15:51:21 +02:00
|
|
|
/* There is no unique device associated with the unspecified
|
|
|
|
* address.
|
|
|
|
*/
|
2018-06-22 18:09:47 +02:00
|
|
|
|
2018-06-25 15:51:21 +02:00
|
|
|
else if (conn->u.ipv4.raddr != INADDR_ANY)
|
2018-06-22 16:19:17 +02:00
|
|
|
{
|
2018-06-25 15:51:21 +02:00
|
|
|
/* Normal lookup using the verified remote address */
|
|
|
|
|
2018-06-22 18:09:47 +02:00
|
|
|
return netdev_findby_ipv4addr(conn->u.ipv4.laddr,
|
|
|
|
conn->u.ipv4.raddr);
|
2018-06-22 16:19:17 +02:00
|
|
|
}
|
2018-06-25 15:51:21 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Not a suitable IPv4 unicast address for device lookup */
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-05-29 18:45:41 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
#ifdef CONFIG_NET_IPv4
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
2018-06-22 16:19:17 +02:00
|
|
|
/* Check if the remote, destination address is a multicast
|
2018-06-23 14:20:25 +02:00
|
|
|
* address. If this is the case, select the device
|
2018-06-22 18:09:47 +02:00
|
|
|
* using the locally bound address (assuming that there is one).
|
2018-06-22 16:19:17 +02:00
|
|
|
*/
|
|
|
|
|
2018-06-23 18:13:38 +02:00
|
|
|
if (net_is_addr_mcast(conn->u.ipv6.raddr))
|
2018-06-22 16:19:17 +02:00
|
|
|
{
|
2018-06-22 18:09:47 +02:00
|
|
|
/* Make sure that the socket is bound to some non-zero, local
|
2018-06-23 20:53:27 +02:00
|
|
|
* address. The IPv6 unspecified address is used as an
|
|
|
|
* indication that the laddr is uninitialized and that the
|
|
|
|
* socket is, hence, not bound.
|
2018-06-22 18:09:47 +02:00
|
|
|
*/
|
|
|
|
|
2018-06-23 20:53:27 +02:00
|
|
|
if (net_ipv6addr_cmp(conn->u.ipv6.laddr, g_ipv6_unspecaddr))
|
2018-06-22 18:09:47 +02:00
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return netdev_findby_ipv6addr(conn->u.ipv6.laddr,
|
|
|
|
conn->u.ipv6.laddr);
|
|
|
|
}
|
2018-06-22 16:19:17 +02:00
|
|
|
}
|
2018-06-22 18:09:47 +02:00
|
|
|
|
2018-06-25 15:51:21 +02:00
|
|
|
/* There is no unique device associated with the unspecified
|
|
|
|
* address.
|
|
|
|
*/
|
2018-06-22 18:09:47 +02:00
|
|
|
|
2018-06-25 15:51:21 +02:00
|
|
|
else if (!net_ipv6addr_cmp(conn->u.ipv6.raddr, g_ipv6_unspecaddr))
|
2018-06-22 16:19:17 +02:00
|
|
|
{
|
2018-06-25 15:51:21 +02:00
|
|
|
/* Normal lookup using the verified remote address */
|
|
|
|
|
2018-06-22 18:09:47 +02:00
|
|
|
return netdev_findby_ipv6addr(conn->u.ipv6.laddr,
|
|
|
|
conn->u.ipv6.raddr);
|
2018-06-22 16:19:17 +02:00
|
|
|
}
|
2018-06-25 15:51:21 +02:00
|
|
|
else
|
|
|
|
{
|
2018-06-25 20:08:10 +02:00
|
|
|
/* Not a suitable IPv6 unicast address for device lookup */
|
2018-06-25 15:51:21 +02:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-05-29 18:45:41 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* CONFIG_NET && CONFIG_NET_UDP */
|