net/udp: Finish support for the UDP_BINDTODEVICE protocol socket option

This commit is contained in:
Sebastien Lorquet 2018-06-25 15:07:53 -06:00 committed by Gregory Nutt
parent 2a29fe0223
commit 65be13bffe
7 changed files with 103 additions and 16 deletions

View File

@ -46,6 +46,8 @@
* Pre-processor Definitions
****************************************************************************/
/* UDP protocol (SOL_UDP) socket options */
#define UDP_BINDTODEVICE (__SO_PROTOCOL + 0) /* Bind this UDP socket to a
* specific network device.
*/

View File

@ -30,6 +30,12 @@ config NET_TCPPROTO_OPTIONS
---help---
Enable or disable support for TCP protocol level socket options.
config NET_UDPPROTO_OPTIONS
bool
default n
---help---
Enable or disable support for UDP protocol level socket options.
if NET_SOCKOPTS
config NET_SOLINGER

View File

@ -25,6 +25,7 @@ config NET_UDP_BINDTODEVICE
bool "UDP Bind-to-device support"
default n
select NET_UDPPROTO_OPTIONS
select NETDEV_IFINDEX
---help---
Enable support for the UDP_BINDTODEVICE socket option.
Linux has SO_BINDTODEVICE but in NuttX this option is instead

View File

@ -112,6 +112,11 @@ struct udp_conn_s
uint8_t ttl; /* Default time-to-live */
uint8_t crefs; /* Reference counts on this instance */
#ifdef CONFIG_NET_UDP_BINDTODEVICE
uint8_t boundto; /* Index of the interface we are bound to.
* Unbound: 0, Bound: 1-MAX_IFINDEX */
#endif
#ifdef CONFIG_NET_UDP_READAHEAD
/* Read-ahead buffering.
*

View File

@ -579,12 +579,15 @@ FAR struct udp_conn_s *udp_alloc(uint8_t domain)
{
/* Make sure that the connection is marked as uninitialized */
conn->flags = 0;
conn->flags = 0;
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
conn->domain = domain;
conn->domain = domain;
#endif
conn->lport = 0;
conn->ttl = IP_TTL;
#ifdef CONFIG_NET_UDP_BINDTODEVICE
conn->boundto = 0; /* Not bound to any interface */
#endif
conn->lport = 0;
conn->ttl = IP_TTL;
#ifdef CONFIG_NET_UDP_WRITE_BUFFERS
/* Initialize the write buffer lists */

View File

@ -167,7 +167,17 @@ FAR struct net_driver_s *udp_find_raddr_device(FAR struct udp_conn_s *conn)
if (conn->u.ipv4.laddr == 0) /* INADDR_ANY */
{
return NULL;
FAR struct net_driver_s *dev = NULL;
#ifdef CONFIG_NET_UDP_BINDTODEVICE
if (conn->boundto != 0)
{
/* This socket has been bound to an interface */
dev = netdev_findbyindex(conn->boundto);
}
#endif
return dev;
}
else
{
@ -189,9 +199,19 @@ FAR struct net_driver_s *udp_find_raddr_device(FAR struct udp_conn_s *conn)
}
else
{
FAR struct net_driver_s *dev = NULL;
/* Not a suitable IPv4 unicast address for device lookup */
return NULL;
#ifdef CONFIG_NET_UDP_BINDTODEVICE
if (conn->boundto != 0)
{
/* This socket has been bound to an interface */
dev = netdev_findbyindex(conn->boundto);
}
#endif
return dev;
}
}
#endif
@ -216,7 +236,17 @@ FAR struct net_driver_s *udp_find_raddr_device(FAR struct udp_conn_s *conn)
if (net_ipv6addr_cmp(conn->u.ipv6.laddr, g_ipv6_unspecaddr))
{
return NULL;
FAR struct net_driver_s *dev = NULL;
#ifdef CONFIG_NET_UDP_BINDTODEVICE
if (conn->boundto != 0)
{
/* This socket has been bound to an interface */
dev = netdev_findbyindex(conn->boundto);
}
#endif
return dev;
}
else
{
@ -238,9 +268,19 @@ FAR struct net_driver_s *udp_find_raddr_device(FAR struct udp_conn_s *conn)
}
else
{
FAR struct net_driver_s *dev = NULL;
/* Not a suitable IPv6 unicast address for device lookup */
return NULL;
#ifdef CONFIG_NET_UDP_BINDTODEVICE
if (conn->boundto != 0)
{
/* This socket has been bound to an interface */
dev = netdev_findbyindex(conn->boundto);
}
#endif
return dev;
}
}
#endif

View File

@ -53,6 +53,7 @@
#include "socket/socket.h"
#include "utils/utils.h"
#include "netdev/netdev.h"
#include "udp/udp.h"
#ifdef CONFIG_NET_UDPPROTO_OPTIONS
@ -104,27 +105,55 @@ int udp_setsockopt(FAR struct socket *psock, int option,
* already configured.
*/
if (psock->s_type != SOCK_STREAM)
if (psock->s_type != SOCK_DGRAM)
{
nerr("ERROR: Not a UDP socket\n");
return -ENOTCONN;
}
/* Handle the Keep-Alive option */
/* Handle the UDP-protocol options */
switch (option)
{
/* Handle the SO_KEEPALIVE socket-level option.
#ifdef CONFIG_NET_UDP_BINDTODEVICE
/* Handle the UDP_BINDTODEVICE socket-level option.
*
* NOTE: SO_KEEPALIVE is not really a socket-level option; it is a
* protocol-level option. A given UDP connection may service multiple
* sockets (via dup'ing of the socket). There is, however, still only
* one connection to be monitored and that is a global attribute across
* all of the clones that may use the underlying connection.
* NOTE: UDP_BINDTODEVICE is declared in linux as SO_BINDTODEVICE,
* but this option only makes sense for UDP sockets trying to broadcast
* while their local address is not set, eg, with DHCP requests.
* The problem is that we are not able to determine the interface to be
* used for sending packets when multiple interfaces do not have a local
* address yet. This option can be used to "force" the interface used to
* send the UDP traffic in this connection. Note that it does NOT only
* apply to broadcast packets.
*/
case UDP_BINDTODEVICE: /* Bind socket to a specific network device */
if (value == NULL || value_len == 0 ||
(value_len > 0 && ((FAR char *)value)[0] == 0))
{
conn->boundto = 0; /* This interface is no longer bound */
}
else
{
int ifindex;
/* Get the interface index corresponding to the interface name */
ifindex = netdev_nametoindex(value);
if (ifindex >= 0)
{
DEBUGASSERT(ifindex > 0 && ifindex < MAX_IFINDEX);
conn->boundto = ifindex;
}
else
{
ret = ifindex;
}
}
break;
#endif
default:
nerr("ERROR: Unrecognized UDP option: %d\n", option);
@ -139,3 +168,4 @@ int udp_setsockopt(FAR struct socket *psock, int option,
}
#endif /* CONFIG_NET_UDPPROTO_OPTIONS */