net/sockopt: move BINDTODEVICE to socket level

rename the UDP_BINDTODEVICE to SO_BINDTODEVICE to follow the linux
style to be compatible with non-UDP protocol binding requirements

Signed-off-by: chao.an <anchao@xiaomi.com>
This commit is contained in:
chao.an 2022-08-24 10:30:01 +08:00 committed by Xiang Xiao
parent 50177dbae1
commit 9cb17841d8
17 changed files with 76 additions and 185 deletions

View File

@ -143,6 +143,7 @@
#define NUTTX_SO_SNDTIMEO 14
#define NUTTX_SO_TYPE 15
#define NUTTX_SO_TIMESTAMP 16
#define NUTTX_SO_BINDTODEVICE 17
#define NUTTX_SO_SNDBUFFORCE 32
#define NUTTX_SO_RCVBUFFORCE 33

View File

@ -56,6 +56,7 @@ CONFIG_NETUTILS_TELNETC=y
CONFIG_NETUTILS_TELNETD=y
CONFIG_NET_ARP_IPIN=y
CONFIG_NET_ARP_SEND=y
CONFIG_NET_BINDTODEVICE=y
CONFIG_NET_BROADCAST=y
CONFIG_NET_ETH_PKTSIZE=1514
CONFIG_NET_GUARDSIZE=4
@ -71,7 +72,6 @@ CONFIG_NET_TCPBACKLOG=y
CONFIG_NET_TCP_NPOLLWAITERS=4
CONFIG_NET_TCP_WRITE_BUFFERS=y
CONFIG_NET_UDP=y
CONFIG_NET_UDP_BINDTODEVICE=y
CONFIG_NET_UDP_CHECKSUMS=y
CONFIG_NET_UDP_NPOLLWAITERS=8
CONFIG_NET_UDP_WRITE_BUFFERS=y

View File

@ -50,7 +50,6 @@
#define IFF_UP (1 << 1) /* Interface is up */
#define IFF_RUNNING (1 << 2) /* Carrier is available */
#define IFF_IPv6 (1 << 3) /* Configured for IPv6 packet (vs ARP or IPv4) */
#define IFF_BOUND (1 << 4) /* Bound to a socket */
#define IFF_LOOPBACK (1 << 5) /* Is a loopback net */
#define IFF_POINTOPOINT (1 << 6) /* Is point-to-point link */
#define IFF_NOARP (1 << 7) /* ARP is not required for this packet */
@ -61,7 +60,6 @@
#define IFF_SET_UP(f) do { (f) |= IFF_UP; } while (0)
#define IFF_SET_RUNNING(f) do { (f) |= IFF_RUNNING; } while (0)
#define IFF_SET_BOUND(f) do { (f) |= IFF_BOUND; } while (0)
#define IFF_SET_NOARP(f) do { (f) |= IFF_NOARP; } while (0)
#define IFF_SET_LOOPBACK(f) do { (f) |= IFF_LOOPBACK; } while (0)
#define IFF_SET_POINTOPOINT(f) do { (f) |= IFF_POINTOPOINT; } while (0)
@ -70,7 +68,6 @@
#define IFF_CLR_UP(f) do { (f) &= ~IFF_UP; } while (0)
#define IFF_CLR_RUNNING(f) do { (f) &= ~IFF_RUNNING; } while (0)
#define IFF_CLR_BOUND(f) do { (f) &= ~IFF_BOUND; } while (0)
#define IFF_CLR_NOARP(f) do { (f) &= ~IFF_NOARP; } while (0)
#define IFF_CLR_LOOPBACK(f) do { (f) &= ~IFF_LOOPBACK; } while (0)
#define IFF_CLR_POINTOPOINT(f) do { (f) &= ~IFF_POINTOPOINT; } while (0)
@ -79,7 +76,6 @@
#define IFF_IS_UP(f) (((f) & IFF_UP) != 0)
#define IFF_IS_RUNNING(f) (((f) & IFF_RUNNING) != 0)
#define IFF_IS_BOUND(f) (((f) & IFF_BOUND) != 0)
#define IFF_IS_NOARP(f) (((f) & IFF_NOARP) != 0)
#define IFF_IS_LOOPBACK(f) (((f) & IFF_LOOPBACK) != 0)
#define IFF_IS_POINTOPOINT(f) (((f) & IFF_POINTOPOINT) != 0)

View File

@ -31,10 +31,4 @@
* Pre-processor Definitions
****************************************************************************/
/* UDP protocol (SOL_UDP) socket options */
#define UDP_BINDTODEVICE (__SO_PROTOCOL + 0) /* Bind this UDP socket to a
* specific network device.
*/
#endif /* __INCLUDE_NETINET_UDP_H */

View File

@ -246,6 +246,10 @@ struct socket_conn_s
#ifdef CONFIG_NET_TIMESTAMP
int32_t s_timestamp; /* Socket timestamp enabled/disabled */
#endif
#ifdef CONFIG_NET_BINDTODEVICE
uint8_t s_boundto; /* Index of the interface we are bound to.
* Unbound: 0, Bound: 1-MAX_IFINDEX */
#endif
#endif
/* Connection-specific content may follow */

View File

@ -200,6 +200,8 @@
#define SO_TIMESTAMP 16 /* Generates a timestamp for each incoming packet
* arg: integer value
*/
#define SO_BINDTODEVICE 17 /* Bind this socket to a specific network device.
*/
/* The options are unsupported but included for compatibility
* and portability

View File

@ -297,13 +297,13 @@ int ipv4_input(FAR struct net_driver_s *dev)
}
else
#endif
#if defined(NET_UDP_HAVE_STACK) && defined(CONFIG_NET_UDP_BINDTODEVICE)
/* If the UDP protocol specific socket option UDP_BINDTODEVICE
#if defined(NET_UDP_HAVE_STACK) && defined(CONFIG_NET_BINDTODEVICE)
/* If the protocol specific socket option NET_BINDTODEVICE
* is selected, then we must forward all UDP packets to the bound
* socket.
*/
if (ipv4->proto != IP_PROTO_UDP || !IFF_IS_BOUND(dev->d_flags))
if (ipv4->proto != IP_PROTO_UDP)
#endif
{
/* Not destined for us and not forwardable... Drop the

View File

@ -379,13 +379,13 @@ int ipv6_input(FAR struct net_driver_s *dev)
}
else
#endif
#if defined(NET_UDP_HAVE_STACK) && defined(CONFIG_NET_UDP_BINDTODEVICE)
/* If the UDP protocol specific socket option UDP_BINDTODEVICE
#if defined(NET_UDP_HAVE_STACK) && defined(CONFIG_NET_BINDTODEVICE)
/* If the protocol specific socket option NET_BINDTODEVICE
* is selected, then we must forward all UDP packets to the bound
* socket.
*/
if (nxthdr != IP_PROTO_UDP || !IFF_IS_BOUND(dev->d_flags))
if (nxthdr != IP_PROTO_UDP)
#endif
{
/* Not destined for us and not forwardable...

View File

@ -56,6 +56,15 @@ config NET_TIMESTAMP
---help---
Enable or disable support for the SO_TIMESTAMP socket option. Currently only tested & implemented in SocketCAN but should work on all sockets
config NET_BINDTODEVICE
bool "SO_BINDTODEVICE socket option Bind-to-device support"
default n
select NETDEV_IFINDEX
---help---
Enable support for the NET_BINDTODEVICE socket option.
Linux has SO_BINDTODEVICE but in NuttX this option is instead
specific to the UDP protocol.
endif # NET_SOCKOPTS
endmenu # Socket Support

View File

@ -34,6 +34,7 @@
#include <arch/irq.h>
#include <nuttx/net/net.h>
#include <netdev/netdev.h>
#include "socket/socket.h"
#include "inet/inet.h"
@ -399,6 +400,51 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
}
#endif
#ifdef CONFIG_NET_BINDTODEVICE
/* Handle the SO_BINDTODEVICE socket-level option.
*
* NOTE: this option 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 SO_BINDTODEVICE: /* Bind socket to a specific network device */
{
FAR struct net_driver_s *dev;
/* Check if we are are unbinding the socket */
if (value == NULL || value_len == 0 ||
(value_len > 0 && ((FAR char *)value)[0] == 0))
{
conn->s_boundto = 0; /* This interface is no longer bound */
break;
}
/* No, we are binding a socket to the interface
* Find the interface device with this name.
*/
dev = netdev_findbyname(value);
if (dev == NULL)
{
return -ENODEV;
}
/* Bind the socket to the interface */
DEBUGASSERT(dev->d_ifindex > 0 &&
dev->d_ifindex <= MAX_IFINDEX);
conn->s_boundto = dev->d_ifindex;
break;
}
#endif
/* The following are not yet implemented */
case SO_RCVLOWAT: /* Sets the minimum number of bytes to input */

View File

@ -61,10 +61,12 @@
#define _SO_SNDLOWAT _SO_BIT(SO_SNDLOWAT)
#define _SO_SNDTIMEO _SO_BIT(SO_SNDTIMEO)
#define _SO_TYPE _SO_BIT(SO_TYPE)
#define _SO_TIMESTAMP _SO_BIT(SO_TIMESTAMP)
#define _SO_BINDTODEVICE _SO_BIT(SO_BINDTODEVICE)
/* This is the largest option value. REVISIT: belongs in sys/socket.h */
#define _SO_MAXOPT (16)
#define _SO_MAXOPT (18)
/* Macros to set, test, clear options */

View File

@ -32,16 +32,6 @@ endif # NET_UDP
if NET_UDP && !NET_UDP_NO_STACK
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
specific to the UDP protocol.
config NET_UDP_CHECKSUMS
bool "UDP checksums"
default y if NET_IPv6

View File

@ -112,10 +112,6 @@ 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
#if CONFIG_NET_RECV_BUFSIZE > 0
int32_t rcvbufs; /* Maximum amount of bytes queued in recv */
#endif

View File

@ -29,14 +29,10 @@
#include <debug.h>
#include <assert.h>
#include <net/if.h>
#include <nuttx/net/net.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/udp.h>
#include "devif/devif.h"
#include "netdev/netdev.h"
#include "udp/udp.h"
#include "socket/socket.h"
@ -106,28 +102,6 @@ int udp_close(FAR struct socket *psock)
nerr("ERROR: udp_txdrain() failed: %d\n", ret);
}
#ifdef CONFIG_NET_UDP_BINDTODEVICE
/* Is the socket bound to an interface device */
if (conn->boundto != 0)
{
FAR struct net_driver_s *dev;
/* Yes, get the interface that we are bound do. NULL would indicate
* that the interface no longer exists for some reason.
*/
dev = netdev_findbyindex(conn->boundto);
if (dev != NULL)
{
/* Clear the interface flag to unbind the device from the socket.
*/
IFF_CLR_BOUND(dev->d_flags);
}
}
#endif
#ifdef CONFIG_NET_UDP_WRITE_BUFFERS
/* Free any semi-permanent write buffer callback in place. */

View File

@ -619,9 +619,6 @@ FAR struct udp_conn_s *udp_alloc(uint8_t domain)
conn->flags = 0;
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
conn->domain = domain;
#endif
#ifdef CONFIG_NET_UDP_BINDTODEVICE
conn->boundto = 0; /* Not bound to any interface */
#endif
conn->lport = 0;
conn->ttl = IP_TTL_DEFAULT;

View File

@ -57,27 +57,27 @@
*
****************************************************************************/
#ifdef CONFIG_NET_UDP_BINDTODEVICE
#ifdef CONFIG_NET_BINDTODEVICE
static FAR struct net_driver_s *upd_bound_device(FAR struct udp_conn_s *conn)
{
FAR struct net_driver_s *dev = NULL;
/* Is the UDP socket bound to a device? */
if (conn->boundto != 0)
if (conn->sconn.s_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);
dev = netdev_findbyindex(conn->sconn.s_boundto);
if (dev == NULL)
{
/* No device? It must have been unregistered. Un-bind the UDP
* socket.
*/
conn->boundto = 0;
conn->sconn.s_boundto = 0;
}
}

View File

@ -74,127 +74,7 @@
int udp_setsockopt(FAR struct socket *psock, int option,
FAR const void *value, socklen_t value_len)
{
#ifdef CONFIG_NET_UDP_BINDTODEVICE
/* Keep alive options are the only UDP protocol socket option currently
* supported.
*/
FAR struct udp_conn_s *conn;
int ret;
DEBUGASSERT(psock != NULL && value != NULL && psock->s_conn != NULL);
conn = (FAR struct udp_conn_s *)psock->s_conn;
/* All of the UDP protocol options apply only UDP sockets. The sockets
* do not have to be connected.. that might occur later with the KeepAlive
* already configured.
*/
if (psock->s_type != SOCK_DGRAM)
{
nerr("ERROR: Not a UDP socket\n");
return -ENOTCONN;
}
/* Handle the UDP-protocol options */
switch (option)
{
#ifdef CONFIG_NET_UDP_BINDTODEVICE
/* Handle the UDP_BINDTODEVICE socket-level option.
*
* 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 */
{
FAR struct net_driver_s *dev;
/* Check if we are are unbinding the socket */
if (value == NULL || value_len == 0 ||
(value_len > 0 && ((FAR char *)value)[0] == 0))
{
/* Just report success if the socket is not bound to an
* interface.
*/
if (conn->boundto != 0)
{
/* Get the interface that we are bound do. NULL would
* indicate that the interface no longer exists for some
* reason.
*/
dev = netdev_findbyindex(conn->boundto);
if (dev != NULL)
{
/* Clear the interface flag to unbind the device from
* the socket.
*/
IFF_CLR_BOUND(dev->d_flags);
}
conn->boundto = 0; /* This interface is no longer bound */
}
ret = OK;
}
/* No, we are binding a socket to the interface. */
else
{
/* Find the interface device with this name */
dev = netdev_findbyname(value);
if (dev == NULL)
{
ret = -ENODEV;
}
/* An interface may be bound only to one socket. */
else if (IFF_IS_BOUND(dev->d_flags))
{
ret = -EBUSY;
}
else
{
/* Bind the interface to a socket */
IFF_SET_BOUND(dev->d_flags);
/* Bind the socket to the interface */
DEBUGASSERT(dev->d_ifindex > 0 &&
dev->d_ifindex <= MAX_IFINDEX);
conn->boundto = dev->d_ifindex;
ret = OK;
}
}
}
break;
#endif
default:
nerr("ERROR: Unrecognized UDP option: %d\n", option);
ret = -ENOPROTOOPT;
break;
}
return ret;
#else
return -ENOPROTOOPT;
#endif /* CONFIG_NET_UDP_BINDTODEVICE */
}
#endif /* CONFIG_NET_UDPPROTO_OPTIONS */