diff --git a/arch/sim/src/sim/up_usrsock_host.h b/arch/sim/src/sim/up_usrsock_host.h index 1374d2cdd2c..748cb668e19 100644 --- a/arch/sim/src/sim/up_usrsock_host.h +++ b/arch/sim/src/sim/up_usrsock_host.h @@ -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 diff --git a/boards/risc-v/litex/arty_a7/configs/netnsh/defconfig b/boards/risc-v/litex/arty_a7/configs/netnsh/defconfig index af2375b8694..ea217366959 100644 --- a/boards/risc-v/litex/arty_a7/configs/netnsh/defconfig +++ b/boards/risc-v/litex/arty_a7/configs/netnsh/defconfig @@ -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 diff --git a/include/net/if.h b/include/net/if.h index 56525768d75..05b4ab32697 100644 --- a/include/net/if.h +++ b/include/net/if.h @@ -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) diff --git a/include/netinet/udp.h b/include/netinet/udp.h index 663606aa0b9..756b8d26e90 100644 --- a/include/netinet/udp.h +++ b/include/netinet/udp.h @@ -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 */ diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h index 43a10d7eb9a..4f0bc45c18c 100644 --- a/include/nuttx/net/net.h +++ b/include/nuttx/net/net.h @@ -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 */ diff --git a/include/sys/socket.h b/include/sys/socket.h index 7c866264596..5569630375c 100644 --- a/include/sys/socket.h +++ b/include/sys/socket.h @@ -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 diff --git a/net/devif/ipv4_input.c b/net/devif/ipv4_input.c index 22719e0d669..6f3dd14dd90 100644 --- a/net/devif/ipv4_input.c +++ b/net/devif/ipv4_input.c @@ -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 diff --git a/net/devif/ipv6_input.c b/net/devif/ipv6_input.c index 19a6b0924d3..a380dd201f3 100644 --- a/net/devif/ipv6_input.c +++ b/net/devif/ipv6_input.c @@ -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... diff --git a/net/socket/Kconfig b/net/socket/Kconfig index 39d1c46b36f..23a45cf3866 100644 --- a/net/socket/Kconfig +++ b/net/socket/Kconfig @@ -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 diff --git a/net/socket/setsockopt.c b/net/socket/setsockopt.c index a8ccb541282..9fcac5ade9c 100644 --- a/net/socket/setsockopt.c +++ b/net/socket/setsockopt.c @@ -34,6 +34,7 @@ #include #include +#include #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 */ diff --git a/net/socket/socket.h b/net/socket/socket.h index e00bd457b35..b453a8d4242 100644 --- a/net/socket/socket.h +++ b/net/socket/socket.h @@ -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 */ diff --git a/net/udp/Kconfig b/net/udp/Kconfig index 24e05366b59..030a0e6cba9 100644 --- a/net/udp/Kconfig +++ b/net/udp/Kconfig @@ -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 diff --git a/net/udp/udp.h b/net/udp/udp.h index b4bcdf52f47..2fa40251904 100644 --- a/net/udp/udp.h +++ b/net/udp/udp.h @@ -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 diff --git a/net/udp/udp_close.c b/net/udp/udp_close.c index f2b4ed7027e..d2a0320837a 100644 --- a/net/udp/udp_close.c +++ b/net/udp/udp_close.c @@ -29,14 +29,10 @@ #include #include -#include - #include -#include #include #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. */ diff --git a/net/udp/udp_conn.c b/net/udp/udp_conn.c index dc01f88276d..52d4ac64de1 100644 --- a/net/udp/udp_conn.c +++ b/net/udp/udp_conn.c @@ -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; diff --git a/net/udp/udp_finddev.c b/net/udp/udp_finddev.c index 3cacdb2bd49..e47a19b651f 100644 --- a/net/udp/udp_finddev.c +++ b/net/udp/udp_finddev.c @@ -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; } } diff --git a/net/udp/udp_setsockopt.c b/net/udp/udp_setsockopt.c index bd5bd997c8f..de449fb1623 100644 --- a/net/udp/udp_setsockopt.c +++ b/net/udp/udp_setsockopt.c @@ -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 */