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;
|
|
|
|
|
2023-02-09 08:35:00 +01:00
|
|
|
if (conn->u.ipv4.laddr != INADDR_ANY)
|
2021-12-17 07:35:51 +01:00
|
|
|
{
|
2023-02-09 08:35:00 +01:00
|
|
|
/* If the socket is bound to some non-zero, local address.
|
|
|
|
* Normal lookup using the verified local address.
|
|
|
|
*/
|
2021-12-17 07:35:51 +01:00
|
|
|
|
2023-02-09 08:35:00 +01:00
|
|
|
return netdev_findby_lipv4addr(conn->u.ipv4.laddr);
|
|
|
|
}
|
2018-06-22 16:19:17 +02:00
|
|
|
|
2023-02-09 08:35:00 +01:00
|
|
|
#ifdef CONFIG_NET_BINDTODEVICE
|
|
|
|
if (conn->sconn.s_boundto != 0)
|
2018-06-22 16:19:17 +02:00
|
|
|
{
|
2023-02-09 08:35:00 +01:00
|
|
|
/* If the socket is bound to a local network device.
|
|
|
|
* Select the network device that has been bound.
|
|
|
|
* If the index is invalid, return NULL.
|
2018-06-22 18:09:47 +02:00
|
|
|
*/
|
|
|
|
|
2023-02-09 08:35:00 +01:00
|
|
|
return netdev_findbyindex(conn->sconn.s_boundto);
|
2018-06-22 16:19:17 +02:00
|
|
|
}
|
2023-02-09 08:35:00 +01:00
|
|
|
#endif
|
2018-06-22 18:09:47 +02:00
|
|
|
|
2023-02-09 08:35:00 +01:00
|
|
|
if (remote)
|
2018-06-22 16:19:17 +02:00
|
|
|
{
|
2023-02-09 08:35:00 +01:00
|
|
|
FAR const struct sockaddr_in *inaddr =
|
|
|
|
(FAR const struct sockaddr_in *)remote;
|
|
|
|
net_ipv4addr_copy(raddr, inaddr->sin_addr.s_addr);
|
2018-06-22 16:19:17 +02:00
|
|
|
}
|
2018-06-25 15:51:21 +02:00
|
|
|
else
|
|
|
|
{
|
2023-02-09 08:35:00 +01:00
|
|
|
net_ipv4addr_copy(raddr, conn->u.ipv4.raddr);
|
2018-06-25 15:51:21 +02:00
|
|
|
}
|
2023-02-09 08:35:00 +01:00
|
|
|
|
|
|
|
/* Normal lookup using the verified remote address */
|
|
|
|
|
|
|
|
return netdev_findby_ripv4addr(conn->u.ipv4.laddr, raddr);
|
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;
|
|
|
|
|
2023-02-09 08:35:00 +01:00
|
|
|
if (!net_ipv6addr_cmp(conn->u.ipv6.laddr, g_ipv6_unspecaddr))
|
2021-12-17 07:35:51 +01:00
|
|
|
{
|
2023-02-09 08:35:00 +01:00
|
|
|
/* If the socket is bound to some non-zero, local address.
|
|
|
|
* Normal lookup using the verified local address.
|
|
|
|
*/
|
2021-12-17 07:35:51 +01:00
|
|
|
|
2023-02-09 08:35:00 +01:00
|
|
|
return netdev_findby_lipv6addr(conn->u.ipv6.laddr);
|
|
|
|
}
|
2018-06-22 16:19:17 +02:00
|
|
|
|
2023-02-09 08:35:00 +01:00
|
|
|
#ifdef CONFIG_NET_BINDTODEVICE
|
|
|
|
if (conn->sconn.s_boundto != 0)
|
2018-06-22 16:19:17 +02:00
|
|
|
{
|
2023-02-09 08:35:00 +01:00
|
|
|
/* If the socket is bound to a local network device.
|
|
|
|
* Select the network device that has been bound.
|
|
|
|
* If the index is invalid, return NULL.
|
2018-06-22 18:09:47 +02:00
|
|
|
*/
|
|
|
|
|
2023-02-09 08:35:00 +01:00
|
|
|
return netdev_findbyindex(conn->sconn.s_boundto);
|
2018-06-22 16:19:17 +02:00
|
|
|
}
|
2023-02-09 08:35:00 +01:00
|
|
|
#endif
|
2018-06-22 18:09:47 +02:00
|
|
|
|
2023-02-09 08:35:00 +01:00
|
|
|
if (remote)
|
2018-06-22 16:19:17 +02:00
|
|
|
{
|
2023-02-09 08:35:00 +01:00
|
|
|
FAR const struct sockaddr_in6 *inaddr =
|
|
|
|
(FAR const struct sockaddr_in6 *)remote;
|
|
|
|
net_ipv6addr_copy(raddr, inaddr->sin6_addr.s6_addr16);
|
2018-06-22 16:19:17 +02:00
|
|
|
}
|
2018-06-25 15:51:21 +02:00
|
|
|
else
|
|
|
|
{
|
2023-02-09 08:35:00 +01:00
|
|
|
net_ipv6addr_copy(raddr, conn->u.ipv6.raddr);
|
2018-06-25 15:51:21 +02:00
|
|
|
}
|
2023-02-09 08:35:00 +01:00
|
|
|
|
|
|
|
/* Normal lookup using the verified remote address */
|
|
|
|
|
|
|
|
return netdev_findby_ripv6addr(conn->u.ipv6.laddr, raddr);
|
2015-05-29 18:45:41 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* CONFIG_NET && CONFIG_NET_UDP */
|