2015-05-29 18:45:41 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* net/udp/udp_finddev.c
|
|
|
|
*
|
2021-02-19 12:45:37 +01:00
|
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
|
|
* this work for additional information regarding copyright ownership. The
|
|
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
|
|
* "License"); you may not use this file except in compliance with the
|
|
|
|
* License. You may obtain a copy of the License at
|
2015-05-29 18:45:41 +02:00
|
|
|
*
|
2021-02-19 12:45:37 +01:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2015-05-29 18:45:41 +02:00
|
|
|
*
|
2021-02-19 12:45:37 +01:00
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
|
|
* License for the specific language governing permissions and limitations
|
|
|
|
* under the License.
|
2015-05-29 18:45:41 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* 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"
|
2022-11-10 07:44:17 +01:00
|
|
|
#include "utils/utils.h"
|
2018-06-26 14:53:13 +02:00
|
|
|
|
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
|
|
|
|
{
|
2018-10-29 19:20:44 +01:00
|
|
|
return netdev_findby_ripv4addr(conn->u.ipv4.laddr,
|
|
|
|
conn->u.ipv4.laddr);
|
2018-06-22 18:09:47 +02:00
|
|
|
}
|
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
|
|
|
|
{
|
2018-10-29 19:20:44 +01:00
|
|
|
return netdev_findby_ripv6addr(conn->u.ipv6.laddr,
|
|
|
|
conn->u.ipv6.laddr);
|
2018-06-22 18:09:47 +02:00
|
|
|
}
|
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.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2021-12-17 07:35:51 +01:00
|
|
|
FAR struct net_driver_s *
|
|
|
|
udp_find_raddr_device(FAR struct udp_conn_s *conn,
|
|
|
|
FAR struct sockaddr_storage *remote)
|
2015-05-29 18:45:41 +02:00
|
|
|
{
|
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
|
|
|
|
{
|
2021-12-17 07:35:51 +01:00
|
|
|
in_addr_t raddr;
|
|
|
|
|
|
|
|
if (remote)
|
|
|
|
{
|
|
|
|
FAR const struct sockaddr_in *inaddr =
|
|
|
|
(FAR const struct sockaddr_in *)remote;
|
|
|
|
net_ipv4addr_copy(raddr, inaddr->sin_addr.s_addr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
net_ipv4addr_copy(raddr, conn->u.ipv4.raddr);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
*/
|
|
|
|
|
2021-12-17 07:35:51 +01:00
|
|
|
if (raddr == INADDR_BROADCAST || IN_MULTICAST(NTOHL(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
|
|
|
|
* 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
|
|
|
|
2022-11-10 07:44:17 +01:00
|
|
|
return net_bound_device(&conn->sconn);
|
2018-06-22 18:09:47 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-10-29 19:20:44 +01:00
|
|
|
return netdev_findby_ripv4addr(conn->u.ipv4.laddr,
|
|
|
|
conn->u.ipv4.laddr);
|
2018-06-22 18:09:47 +02:00
|
|
|
}
|
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
|
|
|
|
2021-12-17 07:35:51 +01:00
|
|
|
else if (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-10-29 19:20:44 +01:00
|
|
|
return netdev_findby_ripv4addr(conn->u.ipv4.laddr,
|
2021-12-17 07:35:51 +01:00
|
|
|
raddr);
|
2018-06-22 16:19:17 +02:00
|
|
|
}
|
2018-06-25 15:51:21 +02:00
|
|
|
else
|
|
|
|
{
|
2019-03-11 19:48:17 +01:00
|
|
|
/* Not a suitable IPv4 unicast address for device lookup.
|
|
|
|
* Return the device bound to this UDP socket, if any.
|
|
|
|
*/
|
2018-06-25 15:51:21 +02:00
|
|
|
|
2022-11-10 07:44:17 +01:00
|
|
|
return net_bound_device(&conn->sconn);
|
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
|
|
|
|
{
|
2021-12-17 07:35:51 +01:00
|
|
|
net_ipv6addr_t raddr;
|
|
|
|
|
|
|
|
if (remote)
|
|
|
|
{
|
|
|
|
FAR const struct sockaddr_in6 *inaddr =
|
|
|
|
(FAR const struct sockaddr_in6 *)remote;
|
|
|
|
net_ipv6addr_copy(raddr, inaddr->sin6_addr.s6_addr16);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
net_ipv6addr_copy(raddr, conn->u.ipv6.raddr);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
*/
|
|
|
|
|
2021-12-17 07:35:51 +01:00
|
|
|
if (net_is_addr_mcast(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
|
|
|
|
2022-11-10 07:44:17 +01:00
|
|
|
return net_bound_device(&conn->sconn);
|
2018-06-22 18:09:47 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-10-29 19:20:44 +01:00
|
|
|
return netdev_findby_ripv6addr(conn->u.ipv6.laddr,
|
|
|
|
conn->u.ipv6.laddr);
|
2018-06-22 18:09:47 +02:00
|
|
|
}
|
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
|
|
|
|
2021-12-17 07:35:51 +01:00
|
|
|
else if (!net_ipv6addr_cmp(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-10-29 19:20:44 +01:00
|
|
|
return netdev_findby_ripv6addr(conn->u.ipv6.laddr,
|
2021-12-17 07:35:51 +01:00
|
|
|
raddr);
|
2018-06-22 16:19:17 +02:00
|
|
|
}
|
2018-06-25 15:51:21 +02:00
|
|
|
else
|
|
|
|
{
|
2019-03-11 19:48:17 +01:00
|
|
|
/* Not a suitable IPv6 unicast address for device lookup.
|
|
|
|
* Return the device bound to this UDP socket, if any.
|
|
|
|
*/
|
2018-06-25 15:51:21 +02:00
|
|
|
|
2022-11-10 07:44:17 +01:00
|
|
|
return net_bound_device(&conn->sconn);
|
2018-06-25 15:51:21 +02:00
|
|
|
}
|
2015-05-29 18:45:41 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* CONFIG_NET && CONFIG_NET_UDP */
|