diff --git a/include/net/if.h b/include/net/if.h index a709815be9..e12a590b37 100644 --- a/include/net/if.h +++ b/include/net/if.h @@ -177,6 +177,21 @@ struct lifreq #define lifr_mii_val_in lifr_ifru.lifru_mii_data.val_in /* PHY input data */ #define lifr_mii_val_out lifr_ifru.lifru_mii_data.val_out /* PHY output data */ +/* Used only with the SIOCGLIFCONF IOCTL commnd*/ + +struct lifconf +{ + size_t lifc_len; /* Size of buffer */ + union + { + FAR char *lifcu_buf; /* Buffer address */ + FAR struct lifreq *lifcu_req; /* Array of ifreq structures */ + } lifc_ifcu; +}; + +#define lifc_buf lifc_ifcu.lifcu_buf /* Buffer address */ +#define lifc_req lifc_ifcu.lifcu_req /* Array of ifreq structures */ + /* This is the I/F request that should be used with IPv4. */ struct ifreq @@ -213,6 +228,21 @@ struct ifreq #define ifr_mii_val_in ifr_ifru.ifru_mii_data.val_in /* PHY input data */ #define ifr_mii_val_out ifr_ifru.ifru_mii_data.val_out /* PHY output data */ +/* Used only with the SIOCGIFCONF IOCTL commnd*/ + +struct ifconf +{ + size_t ifc_len; /* Size of buffer */ + union + { + FAR char *ifcu_buf; /* Buffer address */ + FAR struct ifreq *ifcu_req; /* Array of ifreq structures */ + } ifc_ifcu; +}; + +#define ifc_buf ifc_ifcu.ifcu_buf /* Buffer address */ +#define ifc_req ifc_ifcu.ifcu_req /* Array of ifreq structures */ + /******************************************************************************************* * Public Function Prototypes *******************************************************************************************/ diff --git a/include/nuttx/net/ioctl.h b/include/nuttx/net/ioctl.h index 7debbf66c0..c94c02d156 100644 --- a/include/nuttx/net/ioctl.h +++ b/include/nuttx/net/ioctl.h @@ -82,50 +82,52 @@ #define SIOCSIFHWADDR _SIOC(0x0015) /* Set hardware address */ #define SIOCDIFADDR _SIOC(0x0016) /* Delete IP address (IPv4 and IPv6) */ #define SIOCGIFCOUNT _SIOC(0x0017) /* Get number of devices */ +#define SIOCGIFCONF _SIOC(0x0018) /* Return an interface list (IPv4) */ +#define SIOCGLIFCONF _SIOC(0x0019) /* Return an interface list (IPv6) */ /* Interface flags */ -#define SIOCSIFFLAGS _SIOC(0x0018) /* Sets the interface flags */ -#define SIOCGIFFLAGS _SIOC(0x0019) /* Gets the interface flags */ +#define SIOCSIFFLAGS _SIOC(0x001a) /* Sets the interface flags */ +#define SIOCGIFFLAGS _SIOC(0x001b) /* Gets the interface flags */ -#define SIOCGIPMSFILTER _SIOC(0x001a) /* Retrieve source filter addresses */ -#define SIOCSIPMSFILTER _SIOC(0x001b) /* Set source filter content */ +#define SIOCGIPMSFILTER _SIOC(0x001c) /* Retrieve source filter addresses */ +#define SIOCSIPMSFILTER _SIOC(0x001d) /* Set source filter content */ /* ARP Table. Argument is a reference to sruct arpreq as defined * include/nuttx/net/arp.h */ -#define SIOCSARP _SIOC(0x001c) /* Set an ARP mapping */ -#define SIOCDARP _SIOC(0x001d) /* Delete an ARP mapping */ -#define SIOCGARP _SIOC(0x001e) /* Get an ARP mapping */ +#define SIOCSARP _SIOC(0x001e) /* Set an ARP mapping */ +#define SIOCDARP _SIOC(0x001f) /* Delete an ARP mapping */ +#define SIOCGARP _SIOC(0x0020) /* Get an ARP mapping */ /* Routing table. Argument is a reference to struct rtentry as defined in * include/net/route.h */ -#define SIOCADDRT _SIOC(0x001f) /* Add an entry to the routing table */ -#define SIOCDELRT _SIOC(0x0020) /* Delete an entry from the routing table */ +#define SIOCADDRT _SIOC(0x0021) /* Add an entry to the routing table */ +#define SIOCDELRT _SIOC(0x0022) /* Delete an entry from the routing table */ /* MDIO/MCD *****************************************************************/ -#define SIOCMIINOTIFY _SIOC(0x0021) /* Receive notificaion via signal on +#define SIOCMIINOTIFY _SIOC(0x0023) /* Receive notificaion via signal on * PHY state change */ -#define SIOCGMIIPHY _SIOC(0x0022) /* Get address of MII PHY in use */ -#define SIOCGMIIREG _SIOC(0x0023) /* Get a MII register via MDIO */ -#define SIOCSMIIREG _SIOC(0x0024) /* Set a MII register via MDIO */ +#define SIOCGMIIPHY _SIOC(0x0024) /* Get address of MII PHY in use */ +#define SIOCGMIIREG _SIOC(0x0025) /* Get a MII register via MDIO */ +#define SIOCSMIIREG _SIOC(0x0026) /* Set a MII register via MDIO */ /* Unix domain sockets ******************************************************/ -#define SIOCINQ _SIOC(0x0025) /* Returns the amount of queued unread +#define SIOCINQ _SIOC(0x0027) /* Returns the amount of queued unread * data in the receive */ /* TUN/TAP driver ***********************************************************/ -#define TUNSETIFF _SIOC(0x0026) /* Set TUN/TAP interface */ +#define TUNSETIFF _SIOC(0x0028) /* Set TUN/TAP interface */ /* Telnet driver ************************************************************/ -#define SIOCTELNET _SIOC(0x0027) /* Create a Telnet sessions. +#define SIOCTELNET _SIOC(0x0029) /* Create a Telnet sessions. * See include/nuttx/net/telnet.h */ /**************************************************************************** diff --git a/net/netdev/Make.defs b/net/netdev/Make.defs index 3719861eda..e4237aa54c 100644 --- a/net/netdev/Make.defs +++ b/net/netdev/Make.defs @@ -37,9 +37,9 @@ NETDEV_CSRCS += netdev_register.c netdev_ioctl.c netdev_txnotify.c NETDEV_CSRCS += netdev_findbyname.c netdev_findbyaddr.c netdev_findbyindex.c -NETDEV_CSRCS += netdev_count.c netdev_foreach.c netdev_unregister.c -NETDEV_CSRCS += netdev_carrier.c netdev_default.c netdev_verify.c -NETDEV_CSRCS += netdev_lladdrsize.c +NETDEV_CSRCS += netdev_count.c netdev_ifconf.c netdev_foreach.c +NETDEV_CSRCS += netdev_unregister.c netdev_carrier.c netdev_default.c +NETDEV_CSRCS += netdev_verify.c netdev_lladdrsize.c # Include netdev build support diff --git a/net/netdev/netdev.h b/net/netdev/netdev.h index fc1290d845..ebf57f6866 100644 --- a/net/netdev/netdev.h +++ b/net/netdev/netdev.h @@ -344,6 +344,54 @@ void netdev_txnotify_dev(FAR struct net_driver_s *dev); int netdev_count(void); #endif +/**************************************************************************** + * Name: netdev_ipv4_ifconf + * + * Description: + * Return the IPv4 configuration of each network adaptor + * + * Parameters: + * ifc - A reference to the instance of struct ifconf in which to return + * the information. + * + * Returned Value: + * Zero is returned on success; a negated errno value is returned on any + * failure. + * + * Assumptions: + * The nework is locked + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv4 +struct ifconf; /* Forward reference */ +int netdev_ipv4_ifconf(FAR struct ifconf *ifc); +#endif + +/**************************************************************************** + * Name: netdev_ipv6_ifconf + * + * Description: + * Return the IPv6 configuration of each network adaptor + * + * Parameters: + * lifc - A reference to the instance of struct lifconf in which to return + * the information. + * + * Returned Value: + * Zero is returned on success; a negated errno value is returned on any + * failure. + * + * Assumptions: + * The nework is locked + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv6 +struct lifconf; /* Forward reference */ +int netdev_ipv6_ifconf(FAR struct lifconf *lifc); +#endif + /**************************************************************************** * Name: netdev_dev_lladdrsize * diff --git a/net/netdev/netdev_ifconf.c b/net/netdev/netdev_ifconf.c new file mode 100644 index 0000000000..44efdea4a1 --- /dev/null +++ b/net/netdev/netdev_ifconf.c @@ -0,0 +1,287 @@ +/**************************************************************************** + * net/netdev/netdev_ifconf.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +#include "inet/inet.h" +#include "utils/utils.h" +#include "netdev/netdev.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* The form of information passed with netdev_foreach() callback */ + +#ifdef CONFIG_NET_IPv4 +struct ifconf_ipv4_info_s +{ + size_t bufsize; + FAR struct ifconf *ifc; +}; +#endif + +#ifdef CONFIG_NET_IPv6 +struct ifconf_ipv6_info_s +{ + size_t bufsize; + FAR struct lifconf *lifc; +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ifconf_ipv4_callback + * + * Description: + * Callback from netdev_foreach() that does the real implementation of + * netdev_ipv4_ifconf + * + * Parameters: + * dev - The network device for this callback. + * arg - User callback argument + * + * Returned Value: + * Zero is returned on success; a negated errno value is returned on any + * failure. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv4 +static int ifconf_ipv4_callback(FAR struct net_driver_s *dev, FAR void *arg) +{ + FAR struct ifconf_ipv4_info_s *info = (FAR struct ifconf_ipv4_info_s *)arg; + FAR struct ifconf *ifc; + + DEBUGASSERT(dev != NULL && info != NULL && info->ifc != NULL); + ifc = info->ifc; + + /* Check if this adaptor has an IPv4 address assigned */ + + if (!net_ipv4addr_cmp(dev->d_ipaddr, INADDR_ANY)) + { + /* Check if we would exceed the buffer space provided by the caller. + * NOTE: A common usage model is: + * + * 1) Provide no buffer with the first SIOCGIFCONF command. In this + * case, only the size of the buffer needed for all of IPv4 + * capable interface information is returned. + * 2) Allocate a buffer of that size + * 3) Then use the allocated buffer to receive all of the IPv4 + * interface information on the second SIOCGIFCONF command. + * + * CAUTION: The number of IPv6 capable interface may change between + * calls. It is the callers responsibility to behave sanely in such + * cases. + */ + + if (ifc->ifc_len + sizeof(struct ifreq) <= info->bufsize) + { + FAR struct ifreq *req = + (FAR struct ifreq *)&ifc->ifc_buf[ifc->ifc_len]; + FAR struct sockaddr_in *inaddr = + (FAR struct sockaddr_in *)&req->ifr_addr; + + /* There is space for information about another adaptor. Within + * each ifreq structure, ifr_name will receive the interface name + * and ifr_addr the address. The actual number of bytes + * transferred is returned in ifc_len. + */ + + strncpy(req->ifr_name, dev->d_ifname, IFNAMSIZ); + net_ipv4addr_copy(inaddr->sin_addr.s_addr, dev->d_ipaddr); + } + + /* Increment the size of the buffer in any event */ + + ifc->ifc_len += sizeof(struct ifreq); + } + + return 0; +} +#endif + +/**************************************************************************** + * Name: ifconf_ipv6_callback + * + * Description: + * Callback from netdev_foreach() that does the real implementation of + * netdev_ipv6_ifconf + * + * Parameters: + * dev - The network device for this callback. + * arg - User callback argument + * + * Returned Value: + * Zero is returned on success; a negated errno value is returned on any + * failure. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv6 +static int ifconf_ipv6_callback(FAR struct net_driver_s *dev, FAR void *arg) +{ + FAR struct ifconf_ipv6_info_s *info = (FAR struct ifconf_ipv6_info_s *)arg; + FAR struct lifconf *lifc; + + DEBUGASSERT(dev != NULL && info != NULL && info->lifc != NULL); + lifc = info->lifc; + + /* Check if this adaptor has an IPv6 address assigned */ + + if (!net_ipv6addr_cmp(dev->d_ipv6addr, g_ipv6_allzeroaddr)) + { + /* Check if we would exceed the buffer space provided by the caller. + * NOTE: A common usage model is: + * + * 1) Provide no buffer with the first SIOCGLIFCONF command. In this + * case, only the size of the buffer needed for all of IPv6 + * capable interface information is returned. + * 2) Allocate a buffer of that size + * 3) Then use the allocated buffer to receive all of the IPv6 + * interface information on the second SIOCGLIFCONF command. + * + * CAUTION: The number of IPv6 capable interface may change between + * calls. It is the callers responsibility to behave sanely in such + * cases. + */ + + if (lifc->lifc_len + sizeof(struct lifreq) <= info->bufsize) + { + FAR struct lifreq *req = + (FAR struct lifreq *)&lifc->lifc_buf[lifc->lifc_len]; + FAR struct sockaddr_in6 *inaddr = + (FAR struct sockaddr_in6 *)&req->lifr_addr; + + /* There is space for information about another adaptor. Within + * each ifreq structure, lifr_name will receive the interface + * name and lifr_addr the address. The actual number of bytes + * transferred is returned in lifc_len. + */ + + strncpy(req->lifr_name, dev->d_ifname, IFNAMSIZ); + net_ipv6addr_copy(inaddr->sin6_addr.s6_addr16, dev->d_ipv6addr); + } + + /* Increment the size of the buffer in any event */ + + lifc->lifc_len += sizeof(struct lifreq); + } + + return 0; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: netdev_ipv4_ifconf + * + * Description: + * Return the IPv4 configuration of each network adaptor + * + * Parameters: + * ifc - A reference to the instance of struct ifconf in which to return + * the information. + * + * Returned Value: + * Zero is returned on success; a negated errno value is returned on any + * failure. + * + * Assumptions: + * The nework is locked + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv4 +int netdev_ipv4_ifconf(FAR struct ifconf *ifc) +{ + struct ifconf_ipv4_info_s info; + + info.bufsize = ifc->ifc_len; + info.ifc = ifc; + ifc->ifc_len = 0; + + return netdev_foreach(ifconf_ipv4_callback, (FAR void *)&info); +} +#endif + +/**************************************************************************** + * Name: netdev_ipv6_ifconf + * + * Description: + * Return the IPv6 configuration of each network adaptor + * + * Parameters: + * lifc - A reference to the instance of struct lifconf in which to return + * the information. + * + * Returned Value: + * Zero is returned on success; a negated errno value is returned on any + * failure. + * + * Assumptions: + * The nework is locked + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv6 +int netdev_ipv6_ifconf(FAR struct lifconf *lifc) +{ + struct ifconf_ipv6_info_s info; + + info.bufsize = lifc->lifc_len; + info.lifc = lifc; + lifc->lifc_len = 0; + + return netdev_foreach(ifconf_ipv6_callback, (FAR void *)&info); +} +#endif diff --git a/net/netdev/netdev_ioctl.c b/net/netdev/netdev_ioctl.c index 37d11c8807..6870d4a426 100644 --- a/net/netdev/netdev_ioctl.c +++ b/net/netdev/netdev_ioctl.c @@ -915,6 +915,22 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, } break; +#ifdef CONFIG_NET_IPv4 + case SIOCGIFCONF: /* Return an interface list (IPv4) */ + { + ret = netdev_ipv4_ifconf((FAR struct ifconf *)req); + } + break; +#endif + +#ifdef CONFIG_NET_IPv6 + case SIOCGLIFCONF: /* Return an interface list (IPv6) */ + { + ret = netdev_ipv6_ifconf((FAR struct lifconf *)req); + } + break; +#endif + #if defined(CONFIG_NETDEV_IOCTL) && defined(CONFIG_NETDEV_PHY_IOCTL) #ifdef CONFIG_ARCH_PHY_INTERRUPT case SIOCMIINOTIFY: /* Set up for PHY event notifications */