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"
|
|
|
|
|
2018-06-26 14:53:13 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Private Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: upd_bound_device
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* If the UDP socket is bound to a device, return the reference to the
|
|
|
|
* bound device.
|
|
|
|
*
|
|
|
|
* Input Parameters:
|
|
|
|
* conn - UDP connection structure (not currently used).
|
|
|
|
*
|
|
|
|
* Returned Value:
|
|
|
|
* A reference to the bound device. If the retained interface index no
|
|
|
|
* longer refers to a valid device, this function will unbind the device
|
2018-07-04 15:35:51 +02:00
|
|
|
* and return an arbitrary network device at the head of the list of
|
|
|
|
* registered devices. This supports legacy IPv4 DHCPD behavior when
|
|
|
|
* there is only a single registered network device.
|
2018-06-26 14:53:13 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_UDP_BINDTODEVICE
|
2018-06-26 15:01:27 +02:00
|
|
|
static FAR struct net_driver_s *upd_bound_device(FAR struct udp_conn_s *conn)
|
2018-06-26 14:53:13 +02:00
|
|
|
{
|
|
|
|
FAR struct net_driver_s *dev = NULL;
|
|
|
|
|
|
|
|
/* Is the UDP socket bound to a device? */
|
|
|
|
|
|
|
|
if (conn->boundto != 0)
|
|
|
|
{
|
|
|
|
/* Yes..This socket has been bound to an interface. Convert the
|
|
|
|
* interface index into a device structure reference.
|
|
|
|
*/
|
|
|
|
|
|
|
|
dev = netdev_findbyindex(conn->boundto);
|
|
|
|
if (dev == NULL)
|
|
|
|
{
|
|
|
|
/* No device? It must have been unregistered. Un-bind the UDP
|
|
|
|
* socket.
|
|
|
|
*/
|
|
|
|
|
2018-06-26 15:01:27 +02:00
|
|
|
conn->boundto = 0;
|
2018-06-26 14:53:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-04 15:35:51 +02:00
|
|
|
/* REVISIT: If no device was bound or the bound device is no longer valid,
|
|
|
|
* then just return the arbitrary device at the head of the list of
|
|
|
|
* registered devices. This is lunacy if there are multiple, registered
|
|
|
|
* network devices but makes perfectly good since if there is only one.
|
|
|
|
*/
|
|
|
|
|
|
|
|
return dev == NULL ? g_netdevices : dev;
|
2018-06-26 14:53:13 +02:00
|
|
|
}
|
|
|
|
#else
|
2018-07-04 15:35:51 +02:00
|
|
|
# define upd_bound_device(c) g_netdevices
|
2018-06-26 14:53:13 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2015-05-29 18:45:41 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* 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:
|
2018-07-04 15:35:51 +02:00
|
|
|
* A pointer to the network driver to use. NULL is returned if driver is
|
|
|
|
* not bound to any local device.
|
2015-05-29 18:45:41 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
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
|
|
|
{
|
2018-06-26 14:53:13 +02:00
|
|
|
/* Return the device bound to this UDP socket, if any */
|
2018-06-25 23:07:53 +02:00
|
|
|
|
2018-06-26 14:53:13 +02:00
|
|
|
return upd_bound_device(conn);
|
2018-06-22 18:09:47 +02:00
|
|
|
}
|
|
|
|
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 */
|
2018-06-26 14:53:13 +02:00
|
|
|
/* Return the device bound to this UDP socket, if any */
|
2018-06-25 15:51:21 +02:00
|
|
|
|
2018-06-26 14:53:13 +02:00
|
|
|
return upd_bound_device(conn);
|
2018-06-25 15:51:21 +02:00
|
|
|
}
|
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
|
|
|
{
|
2018-06-26 14:53:13 +02:00
|
|
|
/* Return the device bound to this UDP socket, if any */
|
2018-06-25 23:07:53 +02:00
|
|
|
|
2018-06-26 14:53:13 +02:00
|
|
|
return upd_bound_device(conn);
|
2018-06-22 18:09:47 +02:00
|
|
|
}
|
|
|
|
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-26 14:53:13 +02:00
|
|
|
/* Return the device bound to this UDP socket, if any */
|
2018-06-25 15:51:21 +02:00
|
|
|
|
2018-06-26 14:53:13 +02:00
|
|
|
return upd_bound_device(conn);
|
2018-06-25 15:51:21 +02:00
|
|
|
}
|
2015-05-29 18:45:41 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* CONFIG_NET && CONFIG_NET_UDP */
|