diff --git a/include/netutils/netlib.h b/include/netutils/netlib.h index 5452c6756..6470e65ee 100644 --- a/include/netutils/netlib.h +++ b/include/netutils/netlib.h @@ -51,6 +51,7 @@ #include #include +#include #include #include @@ -60,6 +61,21 @@ * Pre-processor Definitions ****************************************************************************/ +#undef HAVE_ROUTE_PROCFS +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_NET_ROUTE) && \ + defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_ROUTE) +# define HAVE_ROUTE_PROCFS +#endif + +#ifdef HAVE_ROUTE_PROCFS +# ifndef CONFIG_NETLIB_PROCFS_MOUNTPT +# define CONFIG_NETLIB_PROCFS_MOUNTPT "/proc" +# endif + +# define IPv4_ROUTE_PATH CONFIG_NETLIB_PROCFS_MOUNTPT "/net/route/ipv4" +# define IPv6_ROUTE_PATH CONFIG_NETLIB_PROCFS_MOUNTPT "/net/route/ipv6" +#endif + /* SOCK_DGRAM is the preferred socket type to use when we just want a * socket for performing drive ioctls. However, we can't use SOCK_DRAM * if UDP is disabled. @@ -75,6 +91,38 @@ # define NETLIB_SOCK_IOCTL SOCK_RAW #endif +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifdef HAVE_ROUTE_PROCFS +/* Describes one entry from the IPv4 routing table. All addresses are in + * host byte order! + */ + +#ifdef CONFIG_NET_IPv4 +struct netlib_ipv4_route_s +{ + in_addr_t prefix; /* Routing prefix */ + in_addr_t netmask; /* Routing netmask */ + in_addr_t router; /* Router IPv4 address */ +}; +#endif + +/* Describes one entry from the IPv6 routing table. All addresses are in + * host byte order! + */ + +#ifdef CONFIG_NET_IPv6 +struct netlib_ipv6_route_s +{ + uint16_t prefix[8]; /* Routing prefix */ + uint16_t netmask[8]; /* Routing netmask */ + uint16_t router[8]; /* Router IPv6 address */ +}; +#endif +#endif /* HAVE_ROUTE_PROCFS */ + /**************************************************************************** * Public Data ****************************************************************************/ @@ -182,6 +230,25 @@ int netlib_set_arpmapping(FAR const struct sockaddr_in *inaddr, FAR const uint8_t *macaddr); #endif +#ifdef HAVE_ROUTE_PROCFS +# ifdef CONFIG_NET_IPv4 +# define netlib_open_ipv4route() fopen(IPv4_ROUTE_PATH, "r") +# define netlib_close_ipv4route(stream) fclose(stream) +ssize_t netlib_read_ipv4route(FILE *stream, + FAR struct netlib_ipv4_route_s *route); +int netlib_ipv4router(FAR const struct in_addr *destipaddr, + FAR struct in_addr *router); +# endif +# ifdef CONFIG_NET_IPv6 +# define netlib_open_ipv6route() fopen(IPv6_ROUTE_PATH, "r") +# define netlib_close_ipv6route(stream) fclose(stream) +ssize_t netlib_read_ipv6route(FILE *stream, + FAR struct netlib_ipv6_route_s *route); +int netlib_ipv6router(FAR const struct in6_addr *destipaddr, + FAR struct in6_addr *router); +# endif +#endif + #ifdef CONFIG_NET_ICMPv6_AUTOCONF /* ICMPv6 Autoconfiguration */ diff --git a/netutils/netlib/Makefile b/netutils/netlib/Makefile index 6cf90a49d..547e658c0 100644 --- a/netutils/netlib/Makefile +++ b/netutils/netlib/Makefile @@ -56,6 +56,9 @@ endif ifeq ($(CONFIG_NETDB_DNSCLIENT),y) CSRCS += netlib_setipv4dnsaddr.c endif +ifeq ($(CONFIG_NET_ROUTE),y) +CSRCS += netlib_ipv4route.c netlib_ipv4router.c +endif endif ifeq ($(CONFIG_NET_IPv6),y) @@ -66,6 +69,9 @@ CSRCS += netlib_ipv6adaptor.c ifeq ($(CONFIG_NET_ICMPv6_AUTOCONF),y) CSRCS += netlib_autoconfig.c endif +ifeq ($(CONFIG_NET_ROUTE),y) +CSRCS += netlib_ipv6route.c netlib_ipv6router.c +endif endif # These require TCP support diff --git a/netutils/netlib/netlib_ipv4adaptor.c b/netutils/netlib/netlib_ipv4adaptor.c index 7c3f97501..aa4d05b24 100644 --- a/netutils/netlib/netlib_ipv4adaptor.c +++ b/netutils/netlib/netlib_ipv4adaptor.c @@ -53,11 +53,11 @@ #ifdef CONFIG_NET_IPv4 /**************************************************************************** - * Public Functions + * Priver Functions ****************************************************************************/ /**************************************************************************** - * Name: netlib_ipv4adaptor + * Name: _netlib_ipv4adaptor * * Description: * Given the destination address, destipaddr, return the IP address @@ -87,7 +87,7 @@ * ****************************************************************************/ -int netlib_ipv4adaptor(in_addr_t destipaddr, FAR in_addr_t *srcipaddr) +static int _netlib_ipv4adaptor(in_addr_t destipaddr, FAR in_addr_t *srcipaddr) { FAR struct ifreq *ifr; struct ifconf ifc; @@ -209,4 +209,71 @@ errout_with_sd: return ret; } +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: netlib_ipv4adaptor + * + * Description: + * Given the destination address, destipaddr, return the IP address + * assigned to the network adaptor that connects the sub-net that + * includes destipaddr. + * + * If routing table support is enabled, then this logic will account for + * the case where the destination address is not locally accessible. In + * this case, it will return the IP address of the network adaptor that + * provides the correct router to handle that destination address. + * + * Input Parameters: + * destipaddr - The destination IPv4 address + * srcipaddr - The location to return that adaptor address that serves + * the sub-net that includes the destination address. + * + * Returned Value: + * Zero (OK) is returned on success with srcipaddr valid. A negated + * errno value is returned on any failure and in this case the srcipaddr + * is not valid. + * + ****************************************************************************/ + +int netlib_ipv4adaptor(in_addr_t destipaddr, FAR in_addr_t *srcipaddr) +{ + int ret; + + DEBUGASSERT(srcipaddr != NULL); + ret = _netlib_ipv4adaptor(destipaddr, srcipaddr); + +#ifdef HAVE_ROUTE_PROCFS + if (ret < 0) + { + struct in_addr router; + struct in_addr destinaddr; + + /* If the first adaptor look-up on the the destination IP address + * failed, then the IP address cannot be sent on any of the currently + * up network devices configured with an IPv4 address. + * + * But perhaps the destination address is on a sub-net that is + * accessible on a router that can be reached through a local network + * adaptor? + */ + + destinaddr.s_addr = destipaddr; + ret = netlib_ipv4router(&destinaddr, &router); + if (ret >= 0) + { + /* Yes... try again using the router address as the destination + * address. + */ + + ret = _netlib_ipv4adaptor(router.s_addr, srcipaddr); + } + } +#endif + + return ret; +} + #endif /* CONFIG_NET_IPv4 */ diff --git a/netutils/netlib/netlib_ipv4route.c b/netutils/netlib/netlib_ipv4route.c new file mode 100644 index 000000000..03a14ca22 --- /dev/null +++ b/netutils/netlib/netlib_ipv4route.c @@ -0,0 +1,193 @@ +/**************************************************************************** + * netutils/netlib/netlib_ipv4route.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. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "netutils/netlib.h" + +#if defined(CONFIG_NET_IPv4) && defined(HAVE_ROUTE_PROCFS) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Determines the size of an intermediate buffer that must be large enough + * to handle the longest line generated by this logic. + */ + +#define PROCFS_LINELEN 58 + +/* The form of the entry from the routing table file: + * + * 11111111112222222222333333333344444444444555 + * 12345678901234567890123456789012345678901234567890123 + * SEQ TARGET NETMASK ROUTER + * nnnn. xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx + */ + +#define TARGET_OFFSET 6 +#define NETMASK_OFFSET 22 +#define ROUTER_OFFSET 38 + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: set_nul_terminator + * + * Description: + * Make sure that the string is NUL terminated. + * + ****************************************************************************/ + +static void set_nul_terminator(FAR char *str) +{ + while ((*str >= '0' && *str <= '9') || *str == '.') + { + str++; + } + + *str = '\0'; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: netlib_read_ipv4route + * + * Description: + * Read the next entry from the IPv4 routing table. + * + * Input Parameters: + * fd - The open file descriptor to the procfs' IPv4 routing table. + * route - The location to return that the next routing table entry. + * + * Returned Value: + * sizeof(struct netlib_ipv4_route_s) is returned on success. Zero is + * returned if the end of file is encounterd. A negated errno value is + * returned on any failure. + * + ****************************************************************************/ + +ssize_t netlib_read_ipv4route(FILE *stream, + FAR struct netlib_ipv4_route_s *route) +{ + FAR char *prefix; + FAR char *netmask; + FAR char *router; + char line[PROCFS_LINELEN]; + int ret; + + DEBUGASSERT(stream != NULL && route != NULL); + + /* The form of the entry read from the routing table: + * + * 11111111112222222222333333333344444444444555 + * 12345678901234567890123456789012345678901234567890123 + * SEQ TARGET NETMASK ROUTER + * nnnn. xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx + */ + + if (fgets(line, PROCFS_LINELEN, stream) == NULL) + { + /* End of file (or possibly a read error?) */ + + return 0; + } + + /* Special case the first line of the file */ + + if (strncmp(line, "SEQ", 3) == 0) + { + /* Skip over the header and read the first real line of data */ + + if (fgets(line, PROCFS_LINELEN, stream) == NULL) + { + /* End of file (or possibly a read error?) */ + + return 0; + } + } + + /* Make certain that there is a NUL terminator */ + + line[PROCFS_LINELEN - 1] = '\0'; + + /* The format of the line we just read is very strict so we should be able + * dispense with parsing and force things as follows: + */ + + prefix = &line[TARGET_OFFSET]; + netmask = &line[NETMASK_OFFSET]; + router = &line[ROUTER_OFFSET]; + + /* Break up the strings in the line by adding NUL terminators */ + + set_nul_terminator(prefix); + set_nul_terminator(netmask); + set_nul_terminator(router); + + /* Return the converted versions of the addresses */ + + ret = inet_pton(AF_INET, prefix, &route->prefix); + if (ret == 1) + { + ret = inet_pton(AF_INET, netmask, &route->netmask); + if (ret == 1) + { + ret = inet_pton(AF_INET, router, &route->router); + if (ret == 1) + { + return sizeof(struct netlib_ipv4_route_s); + } + } + } + + return ret < 0 ? ret : -EINVAL; +} + +#endif /* CONFIG_NET_IPv4 && HAVE_ROUTE_PROCFS */ diff --git a/netutils/netlib/netlib_ipv4router.c b/netutils/netlib/netlib_ipv4router.c new file mode 100644 index 000000000..23a28d855 --- /dev/null +++ b/netutils/netlib/netlib_ipv4router.c @@ -0,0 +1,134 @@ +/**************************************************************************** + * netutils/netlib/netlib_ipv4router.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. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "netutils/netlib.h" + +#if defined(CONFIG_NET_IPv4) && defined(HAVE_ROUTE_PROCFS) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: netlib_ipv4router + * + * Description: + * Given a destination address that is no on a local network, query the + * IPv4 routing table, and return the IPv4 address of the routing that + * will provide access to the correct sub-net. + * + * Input Parameters: + * destipaddr - The destination address to use in the look-up (in network + * byte order). + * router - The location to return that the IP address of the router + * (in network byte order) + * + * Returned Value: + * Zero is returned on success; a negated errno value is returned on any + * failure. + * + ****************************************************************************/ + +int netlib_ipv4router(FAR const struct in_addr *destipaddr, + FAR struct in_addr *router) +{ + struct netlib_ipv4_route_s route; + FILE *stream; + in_addr_t hdest; + ssize_t nbytes; + int ret = -ENOENT; + + /* Open the routing table file */ + + stream = netlib_open_ipv4route(); + if (stream == NULL) + { + return -errno; + } + + /* Convert the destination IP address to host byte order for the + * comparison. + */ + + hdest = ntohl(destipaddr->s_addr); + + /* Find the routing table entry that provides the router for this sub-net. */ + + for (; ; ) + { + /* Read the route (in host byte order) */ + + nbytes = netlib_read_ipv4route(stream, &route); + if (nbytes == 0) + { + /* End of file with no match */ + + break; + } + else if (nbytes < 0) + { + /* Read error */ + + ret = (int)nbytes; + break; + } + + /* Compare the prefix and the destination address under the mask */ + + if (net_ipv4addr_maskcmp(route.prefix, hdest, route.netmask)) + { + /* Found it! Return the router address in network byte order */ + + router->s_addr = htonl(route.router); + ret = OK; + break; + } + } + + netlib_close_ipv4route(stream); + return ret; +} + +#endif /* CONFIG_NET_IPv4 && HAVE_ROUTE_PROCFS */ diff --git a/netutils/netlib/netlib_ipv6adaptor.c b/netutils/netlib/netlib_ipv6adaptor.c index 45a8ac0db..0ba3f7f6a 100644 --- a/netutils/netlib/netlib_ipv6adaptor.c +++ b/netutils/netlib/netlib_ipv6adaptor.c @@ -53,11 +53,11 @@ #ifdef CONFIG_NET_IPv6 /**************************************************************************** - * Public Functions + * Private Functions ****************************************************************************/ /**************************************************************************** - * Name: netlib_ipv6adaptor + * Name: _netlib_ipv6adaptor * * Description: * Given the destination address, destipaddr, return the IP address @@ -68,15 +68,15 @@ * appear in the routing table. A complete solution could involve three * steps: * - * 1. Call netlib_ipv4adaptor() to find the address of the network + * 1. Call netlib_ipv6adaptor() to find the address of the network * adaptor for the destination address. * 2. If this fails, then look up the router address in the routing table * that can forward to the destination address, then - * 3. Call netlib_ipv4adaptor() to find the address of the network + * 3. Call netlib_ipv6adaptor() to find the address of the network * adaptor for that router address. * * Input Parameters: - * destipaddr - The destination IPv4 address + * destipaddr - The destination IPv6 address * srcipaddr - The location to return that adaptor address that serves * the sub-net that includes the destination address. * @@ -87,8 +87,8 @@ * ****************************************************************************/ -int netlib_ipv6adaptor(FAR const struct in6_addr *destipaddr, - FAR struct in6_addr *srcipaddr) +static int _netlib_ipv6adaptor(FAR const struct in6_addr *destipaddr, + FAR struct in6_addr *srcipaddr) { FAR struct lifreq *lifr; struct lifconf lifc; @@ -213,4 +213,71 @@ errout_with_sd: return ret; } +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: netlib_ipv6adaptor + * + * Description: + * Given the destination address, destipaddr, return the IP address + * assigned to the network adaptor that connects the sub-net that + * includes destipaddr. + * + * If routing table support is enabled, then this logic will account for + * the case where the destination address is not locally accessible. In + * this case, it will return the IP address of the network adaptor that + * provides the correct router to handle that destination address. + * + * Input Parameters: + * destipaddr - The destination IPv6 address + * srcipaddr - The location to return that adaptor address that serves + * the sub-net that includes the destination address. + * + * Returned Value: + * Zero (OK) is returned on success with srcipaddr valid. A negated + * errno value is returned on any failure and in this case the srcipaddr + * is not valid. + * + ****************************************************************************/ + +int netlib_ipv6adaptor(FAR const struct in6_addr *destipaddr, + FAR struct in6_addr *srcipaddr) +{ + int ret; + + DEBUGASSERT(destipaddr != NULL && srcipaddr != NULL); + + ret = _netlib_ipv6adaptor(destipaddr, srcipaddr); + +#ifdef HAVE_ROUTE_PROCFS + if (ret < 0) + { + struct in6_addr router; + + /* If the first adaptor look-up on the the destination IP address + * failed, then the IP address cannot be sent on any of the + * currently up network devices configured with an IPv6 address. + * + * But perhaps the destination address is on a sub-net that is + * accessible on a router that can be reached through a local + * network adaptor? + */ + + ret = netlib_ipv6router(destipaddr, &router); + if (ret >= 0) + { + /* Yes... try again using the router address as the destination + * address. + */ + + ret = _netlib_ipv6adaptor(&router, srcipaddr); + } + } +#endif + + return ret; +} + #endif /* CONFIG_NET_IPv6 */ diff --git a/netutils/netlib/netlib_ipv6route.c b/netutils/netlib/netlib_ipv6route.c new file mode 100644 index 000000000..af8375fe5 --- /dev/null +++ b/netutils/netlib/netlib_ipv6route.c @@ -0,0 +1,241 @@ +/**************************************************************************** + * netutils/netlib/netlib_ipv6route.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. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "netutils/netlib.h" + +#if defined(CONFIG_NET_IPv6) && defined(HAVE_ROUTE_PROCFS) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Determines the size of an intermediate buffer that must be large enough + * to handle the longest line generated by this logic. + */ + +#define PROCFS_LINELEN 58 + +/* The form of the entry from the routing table file: + * + * 11111111112222222222333333333344444444445555 + * 12345678901234567890123456789012345678901234567890123 + * nnnn. target: xxxx:xxxx:xxxx:xxxxxxxx:xxxx:xxxx:xxxx + * netmask: xxxx:xxxx:xxxx:xxxxxxxx:xxxx:xxxx:xxxx + * router: xxxx:xxxx:xxxx:xxxxxxxx:xxxx:xxxx:xxxx + */ + +#define ADDR_OFFSET 15 + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: set_nul_terminator + * + * Description: + * Make sure that the string is NUL terminated. + * + ****************************************************************************/ + +static void set_nul_terminator(FAR char *str) +{ + while ((*str >= '0' && *str <= '9') || *str == '.') + { + str++; + } + + *str = '\0'; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: netlib_read_ipv6route + * + * Description: + * Read the next entry from the IPv6 routing table. + * + * Input Parameters: + * fd - The open file descriptor to the procfs' IPv6 routing table. + * route - The location to return that the next routing table entry. + * + * Returned Value: + * sizeof(struct netlib_ipv6_route_s) is returned on success. Zero is + * returned if the end of file is encounterd. A negated errno value is + * returned on any failure. + * + ****************************************************************************/ + +ssize_t netlib_read_ipv6route(FILE *stream, + FAR struct netlib_ipv6_route_s *route) +{ + char line[PROCFS_LINELEN]; + FAR char *addr; + int ret; + + DEBUGASSERT(stream != NULL && route != NULL); + + /* The form of the entries read from the routing table: + * + * 1111111111222222222233333333334444444444555 + * 1234567890123456789012345678901234567890123456789012 + * nnnn. target: xxxx:xxxx:xxxx:xxxxxxxx:xxxx:xxxx:xxxx + * netmask: xxxx:xxxx:xxxx:xxxxxxxx:xxxx:xxxx:xxxx + * router: xxxx:xxxx:xxxx:xxxxxxxx:xxxx:xxxx:xxxx + */ + + /* Read the first line from the file */ + + if (fgets(line, PROCFS_LINELEN, stream) == NULL) + { + /* End of file (or possibly a read error?) */ + + return 0; + } + + /* The first line of the group should consist of a number index */ + + if (line[0] < '0' || line[0] > 9) + { + return -EINVAL; + } + + /* Make certain that there is a NUL terminator */ + + line[PROCFS_LINELEN - 1] = '\0'; + + /* Convert the prefix address to binary */ + + addr = &line[ADDR_OFFSET]; + set_nul_terminator(addr); + + ret = inet_pton(AF_INET6, addr, &route->prefix); + if (ret < 0) + { + return ret; + } + else if (ret == 0) + { + return -EINVAL; + } + + /* Read the second line from the file */ + + if (fgets(line, PROCFS_LINELEN, stream) == NULL) + { + /* End of file (or possibly a read error?) */ + + return 0; + } + + /* The second line of the group should not include an index */ + + if (line[0] != ' ') + { + return -EINVAL; + } + + /* Make certain that there is a NUL terminator */ + + line[PROCFS_LINELEN - 1] = '\0'; + + /* Convert the prefix address to binary */ + + addr = &line[ADDR_OFFSET]; + set_nul_terminator(addr); + + ret = inet_pton(AF_INET6, addr, &route->netmask); + if (ret < 0) + { + return ret; + } + else if (ret == 0) + { + return -EINVAL; + } + + /* Read the third line from the file */ + + if (fgets(line, PROCFS_LINELEN, stream) == NULL) + { + /* End of file (or possibly a read error?) */ + + return 0; + } + + /* The third line of the group should not include an index */ + + if (line[0] != ' ') + { + return -EINVAL; + } + + /* Make certain that there is a NUL terminator */ + + line[PROCFS_LINELEN - 1] = '\0'; + + /* Convert the prefix address to binary */ + + addr = &line[ADDR_OFFSET]; + set_nul_terminator(addr); + + ret = inet_pton(AF_INET6, addr, &route->router); + if (ret < 0) + { + return ret; + } + else if (ret == 0) + { + return -EINVAL; + } + + return sizeof(struct netlib_ipv6_route_s); +} + +#endif /* CONFIG_NET_IPv6 && HAVE_ROUTE_PROCFS */ diff --git a/netutils/netlib/netlib_ipv6router.c b/netutils/netlib/netlib_ipv6router.c new file mode 100644 index 000000000..39647842e --- /dev/null +++ b/netutils/netlib/netlib_ipv6router.c @@ -0,0 +1,148 @@ +/**************************************************************************** + * netutils/netlib/netlib_ipv6router.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. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "netutils/netlib.h" + +#if defined(CONFIG_NET_IPv6) && defined(HAVE_ROUTE_PROCFS) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: netlib_ipv6router + * + * Description: + * Given a destination address that is no on a local network, query the + * IPv6 routing table, and return the IPv6 address of the routing that + * will provide access to the correct sub-net. + * + * Input Parameters: + * destipaddr - The destination address to use in the look-up (in network + * byte order). + * router - The location to return that the IP address of the router + * (in network byte order) + * + * Returned Value: + * Zero is returned on success; a negated errno value is returned on any + * failure. + * + ****************************************************************************/ + +int netlib_ipv6router(FAR const struct in6_addr *destipaddr, + FAR struct in6_addr *router) +{ + struct netlib_ipv6_route_s route; + FILE *stream; + uint16_t hdest[8]; + ssize_t nbytes; + int ret = -ENOENT; + + /* Open the routing table file */ + + stream = netlib_open_ipv6route(); + if (stream == NULL) + { + return -errno; + } + + /* Convert the destination IP address to host byte order for the + * comparison. + */ + + hdest[0] = ntohs(destipaddr->s6_addr16[0]); + hdest[1] = ntohs(destipaddr->s6_addr16[1]); + hdest[2] = ntohs(destipaddr->s6_addr16[2]); + hdest[3] = ntohs(destipaddr->s6_addr16[3]); + hdest[4] = ntohs(destipaddr->s6_addr16[4]); + hdest[5] = ntohs(destipaddr->s6_addr16[5]); + hdest[6] = ntohs(destipaddr->s6_addr16[6]); + hdest[7] = ntohs(destipaddr->s6_addr16[7]); + + /* Find the routing table entry that provides the router for this sub-net. */ + + for (; ; ) + { + /* Read the route (in host byte order) */ + + nbytes = netlib_read_ipv6route(stream, &route); + if (nbytes == 0) + { + /* End of file with no match */ + + break; + } + else if (nbytes < 0) + { + /* Read error */ + + ret = (int)nbytes; + break; + } + + /* Compare the prefix and the destination address under the mask */ + + if (net_ipv6addr_maskcmp(route.prefix, hdest, route.netmask)) + { + /* Found it! Return the router address in network byte order */ + + router->s6_addr16[0] = htons(route.router[0]); + router->s6_addr16[1] = htons(route.router[1]); + router->s6_addr16[2] = htons(route.router[2]); + router->s6_addr16[3] = htons(route.router[3]); + router->s6_addr16[4] = htons(route.router[4]); + router->s6_addr16[5] = htons(route.router[5]); + router->s6_addr16[6] = htons(route.router[6]); + router->s6_addr16[7] = htons(route.router[7]); + ret = OK; + break; + } + } + + netlib_close_ipv6route(stream); + return ret; +} + +#endif /* CONFIG_NET_IPv6 && HAVE_ROUTE_PROCFS */