diff --git a/include/netutils/netlib.h b/include/netutils/netlib.h index eb3933fe95d..50548deff76 100644 --- a/include/netutils/netlib.h +++ b/include/netutils/netlib.h @@ -561,12 +561,41 @@ int netlib_getifstatistics(FAR const char *ifname, int netlib_check_ifconflict(FAR const char *ifname); #endif -#ifdef CONFIG_NETUTILS_PING +/** + * @brief + * Check network connectivity by pinging a remote IP address. + * If ip is NULL, ping the gateway of each network interface, + * and optionally the routers from the routing table. If ping + * is disabled, just check the status of the IP network card. + * + * @param ip The ipv4 address to check, or NULL to ping gateways + * @param timeout The max timeout of each ping + * @param retry The retry times of ping + * + * @return + * nums of remote reply of ping; a negative on failure + */ + int netlib_check_ipconnectivity(FAR const char *ip, int timeout, int retry); + +#ifdef CONFIG_NETUTILS_PING + +/** + * @brief + * Check network connectivity by pinging the default gateway + * of the specified network interface. + * + * @param ifname The name of the interface to use + * @param timeout The timeout of ping + * @param retry The retry times of ping + * + * @return + * nums of gateway reply of ping; a negative on failure. + */ + int netlib_check_ifconnectivity(FAR const char *ifname, int timeout, int retry); #else -#define netlib_check_ipconnectivity(i, t, r) 1 #define netlib_check_ifconnectivity(i, t, r) 1 #endif diff --git a/netutils/netlib/CMakeLists.txt b/netutils/netlib/CMakeLists.txt index 2f0f11e0f06..0a6735121de 100644 --- a/netutils/netlib/CMakeLists.txt +++ b/netutils/netlib/CMakeLists.txt @@ -158,8 +158,10 @@ if(CONFIG_NETUTILS_NETLIB) list(APPEND SRCS netlib_getiobinfo.c) endif() + list(APPEND SRCS netlib_checkipconnectivity.c) + if(CONFIG_NETUTILS_PING) - list(APPEND SRCS netlib_checkipconnectivity.c netlib_checkifconnectivity.c) + list(APPEND SRCS netlib_checkifconnectivity.c) endif() list(APPEND SRCS netlib_checkhttpconnectivity.c) diff --git a/netutils/netlib/Makefile b/netutils/netlib/Makefile index 7bba856b7dc..5867d9190f0 100644 --- a/netutils/netlib/Makefile +++ b/netutils/netlib/Makefile @@ -157,8 +157,10 @@ ifeq ($(CONFIG_MM_IOB),y) CSRCS += netlib_getiobinfo.c endif +CSRCS += netlib_checkipconnectivity.c + ifeq ($(CONFIG_NETUTILS_PING),y) -CSRCS += netlib_checkipconnectivity.c netlib_checkifconnectivity.c +CSRCS += netlib_checkifconnectivity.c endif CSRCS += netlib_checkhttpconnectivity.c diff --git a/netutils/netlib/netlib_checkifconnectivity.c b/netutils/netlib/netlib_checkifconnectivity.c index bfc06001a5a..d0bc8c3e33c 100644 --- a/netutils/netlib/netlib_checkifconnectivity.c +++ b/netutils/netlib/netlib_checkifconnectivity.c @@ -48,7 +48,8 @@ * Name: netlib_check_ifconnectivity * * Description: - * Check network interface connectivity by pinging the gateway + * Check network connectivity by pinging the default gateway + * of the specified network interface. * * Parameters: * ifname The name of the interface to use @@ -56,7 +57,7 @@ * retry The retry times of ping * * Return: - * nums of gateway reply of ping; a nagtive on failure. + * nums of gateway reply of ping; a negative on failure. * ****************************************************************************/ @@ -86,4 +87,4 @@ int netlib_check_ifconnectivity(FAR const char *ifname, return netlib_check_ipconnectivity(destip, timeout, retry); } -#endif /* CONFIG_NETUTILS_PING */ \ No newline at end of file +#endif /* CONFIG_NETUTILS_PING */ diff --git a/netutils/netlib/netlib_checkipconnectivity.c b/netutils/netlib/netlib_checkipconnectivity.c index 04b3c3c0bc1..ce1a334b8ff 100644 --- a/netutils/netlib/netlib_checkipconnectivity.c +++ b/netutils/netlib/netlib_checkipconnectivity.c @@ -32,20 +32,22 @@ #include #include #include +#include #include #include -#include "netutils/icmp_ping.h" #include "netutils/netlib.h" - -#ifdef CONFIG_NETUTILS_PING +#include "netutils/icmp_ping.h" +#include "netutils/icmpv6_ping.h" /**************************************************************************** * Private Data ****************************************************************************/ -#define PING_IPADDR_DATALEN 80 +#define PING_IPADDR_DATALEN 56 + +#ifdef CONFIG_NETUTILS_PING /**************************************************************************** * Private Functions @@ -72,6 +74,243 @@ static void ping_ipaddr_callback(FAR const struct ping_result_s *result) } } +#endif /* CONFIG_NETUTILS_PING */ + +#ifdef CONFIG_NETUTILS_PING6 + +/**************************************************************************** + * Name: ping6_ipaddr_callback + * + * Description: + * ping6 ipaddr callback + * + * Parameters: + * result The result of ping6 + * + ****************************************************************************/ + +static void ping6_ipaddr_callback(FAR const struct ping6_result_s *result) +{ + FAR int *count = result->info->priv; + + if (result->code == ICMPv6_I_FINISH) + { + *count = result->nreplies; + } +} + +#endif /* CONFIG_NETUTILS_PING6 */ + +/**************************************************************************** + * Name: ping_gateway + * + * Description: + * Ping the default gateway of each network interface (IPv4 and IPv6). + * + * Parameters: + * info Pointer to the IPv4 ping info structure + * info6 Pointer to the IPv6 ping info structure + * + ****************************************************************************/ + +#ifdef CONFIG_NETDEV_IFINDEX +static void ping_gateway(FAR struct ping_info_s *info, + FAR struct ping6_info_s *info6) +{ + FAR int *replies = info->priv; + FAR struct ifaddrs *ifap; + FAR struct ifaddrs *ifa; + + if (getifaddrs(&ifap) < 0) + { + return; + } + + for (ifa = ifap; ifa != NULL && *replies == 0; ifa = ifa->ifa_next) + { + if (ifa->ifa_addr == NULL) + { + continue; + } + + /* Skip interfaces that are not up and running */ + + if ((ifa->ifa_flags & (IFF_UP | IFF_RUNNING)) != + (IFF_UP | IFF_RUNNING) || (ifa->ifa_flags & IFF_LOOPBACK) != 0) + { + continue; + } + + if (ifa->ifa_addr->sa_family == AF_INET) + { + FAR struct sockaddr_in *sin; + char destip[INET_ADDRSTRLEN]; + + /* Skip interfaces with INADDR_ANY address and loopback flag */ + + sin = (FAR struct sockaddr_in *)ifa->ifa_addr; + if (sin->sin_addr.s_addr == INADDR_ANY) + { + continue; + } + + /* No ARP means point-to-point or tunnel, treat as reachable */ + + if ((ifa->ifa_flags & IFF_NOARP) != 0) + { + (*replies)++; + break; + } + + sin = (FAR struct sockaddr_in *)ifa->ifa_dstaddr; + if (sin == NULL || + sin->sin_family != AF_INET || + sin->sin_addr.s_addr == INADDR_ANY) + { + continue; + } + + inet_ntop(AF_INET, &sin->sin_addr, destip, sizeof(destip)); + ninfo("ping gateway %s on %s\n", destip, ifa->ifa_name); + info->hostname = destip; +#ifdef CONFIG_NETUTILS_PING + icmp_ping(info); +#else + (*replies)++; +#endif + } + else if (ifa->ifa_addr->sa_family == AF_INET6) + { + FAR struct sockaddr_in6 *sin6; + char destip[INET6_ADDRSTRLEN]; + + /* Skip interfaces with unspecified address and loopback flag */ + + sin6 = (FAR struct sockaddr_in6 *)ifa->ifa_addr; + if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) + { + continue; + } + + /* No ARP means point-to-point or tunnel, treat as reachable */ + + if ((ifa->ifa_flags & IFF_NOARP) != 0) + { + (*replies)++; + break; + } + + sin6 = (FAR struct sockaddr_in6 *)ifa->ifa_dstaddr; + if (sin6 == NULL || + sin6->sin6_family != AF_INET6 || + IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) + { + continue; + } + + inet_ntop(AF_INET6, &sin6->sin6_addr, destip, sizeof(destip)); + ninfo("ping6 gateway %s on %s\n", destip, ifa->ifa_name); + info6->hostname = destip; +#ifdef CONFIG_NETUTILS_PING6 + icmp6_ping(info6); +#else + (*replies)++; +#endif + } + } + + freeifaddrs(ifap); +} +#endif /* CONFIG_NETDEV_IFINDEX */ + +/**************************************************************************** + * Name: ping_route + * + * Description: + * Ping the router addresses from the IPv4 routing table. + * + * Parameters: + * info Pointer to the ping info structure + * + ****************************************************************************/ + +#if defined(HAVE_ROUTE_PROCFS) && defined(CONFIG_NETUTILS_PING) +static void ping_route(FAR struct ping_info_s *info) +{ + FAR int *replies = info->priv; + FAR FILE *stream; + struct netlib_ipv4_route_s route; + + stream = netlib_open_ipv4route(); + if (stream == NULL) + { + return; + } + + while (*replies == 0 && netlib_read_ipv4route(stream, &route) > 0) + { + char destip[INET_ADDRSTRLEN]; + + if (route.router == INADDR_ANY) + { + continue; + } + + inet_ntop(AF_INET, &route.router, destip, sizeof(destip)); + ninfo("ping route gateway %s\n", destip); + info->hostname = destip; + icmp_ping(info); + } + + netlib_close_ipv4route(stream); +} +#endif /* HAVE_ROUTE_PROCFS && CONFIG_NETUTILS_PING */ + +/**************************************************************************** + * Name: ping6_route + * + * Description: + * Ping the router addresses from the IPv6 routing table. + * + * Parameters: + * info6 Pointer to the ping6 info structure + * + ****************************************************************************/ + +#if defined(HAVE_ROUTE_PROCFS) && defined(CONFIG_NETUTILS_PING6) +static void ping6_route(FAR struct ping6_info_s *info6) +{ + FAR int *replies = info6->priv; + FAR FILE *stream; + struct netlib_ipv6_route_s route; + + stream = netlib_open_ipv6route(); + if (stream == NULL) + { + return; + } + + while (*replies == 0 && netlib_read_ipv6route(stream, &route) > 0) + { + char destip[INET6_ADDRSTRLEN]; + struct in6_addr router; + + memcpy(&router, route.router, sizeof(router)); + if (IN6_IS_ADDR_UNSPECIFIED(&router)) + { + continue; + } + + inet_ntop(AF_INET6, &router, destip, sizeof(destip)); + ninfo("ping6 route gateway %s\n", destip); + info6->hostname = destip; + icmp6_ping(info6); + } + + netlib_close_ipv6route(stream); +} +#endif /* HAVE_ROUTE_PROCFS && CONFIG_NETUTILS_PING6 */ + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -80,59 +319,107 @@ static void ping_ipaddr_callback(FAR const struct ping_result_s *result) * Name: netlib_check_ipconnectivity * * Description: - * Get the network dns status + * Check network connectivity by pinging a remote IP address. + * If ip is NULL, ping the gateway of each network interface, + * and optionally the routers from the routing table. If ping + * is disabled, just check the status of the IP network card. * * Parameters: - * ip The ipv4 address to check + * ip The ipv4 address to check, or NULL to ping gateways * timeout The max timeout of each ping * retry The retry times of ping * * Return: - * nums of remote reply of ping; a nagtive on failure + * nums of remote reply of ping; a negative or ZERO on failure * ****************************************************************************/ int netlib_check_ipconnectivity(FAR const char *ip, int timeout, int retry) { int replies = 0; -#ifdef CONFIG_NETDB_DNSSERVER_IPv4ADDR - char ip_str[INET_ADDRSTRLEN]; - struct in_addr addr; -#endif +#if defined(CONFIG_NETDEV_IFINDEX) || defined(CONFIG_NETUTILS_PING) struct ping_info_s info; +#endif +#if defined(CONFIG_NETDEV_IFINDEX) || defined(CONFIG_NETUTILS_PING6) + struct ping6_info_s info6; +#endif +#ifdef CONFIG_NETUTILS_PING info.count = retry; info.datalen = PING_IPADDR_DATALEN; info.delay = 0; info.timeout = timeout; info.callback = ping_ipaddr_callback; - info.priv = &replies; -#ifdef CONFIG_NET_BINDTODEVICE + info.hostname = ip; +# ifdef CONFIG_NET_BINDTODEVICE info.devname = NULL; +# endif +#endif +#if defined(CONFIG_NETDEV_IFINDEX) || defined(CONFIG_NETUTILS_PING) + info.priv = &replies; #endif - /* if ip is NULL we use default DNS server */ +#ifdef CONFIG_NETUTILS_PING6 + info6.count = retry; + info6.datalen = PING_IPADDR_DATALEN; + info6.delay = 0; + info6.timeout = timeout; + info6.hostname = ip; + info6.callback = ping6_ipaddr_callback; +# ifdef CONFIG_NET_BINDTODEVICE + info6.devname = NULL; +# endif +#endif +#if defined(CONFIG_NETDEV_IFINDEX) || defined(CONFIG_NETUTILS_PING6) + info6.priv = &replies; +#endif - if (ip == NULL) + if (ip != NULL) { -#ifdef CONFIG_NETDB_DNSSERVER_IPv4ADDR - addr.s_addr = HTONL(CONFIG_NETDB_DNSSERVER_IPv4ADDR); - inet_ntop(AF_INET, &addr, ip_str, INET_ADDRSTRLEN); - info.hostname = ip_str; + struct in6_addr addr6; + + ninfo("ping ipaddr test %s\n", ip); + if (inet_pton(AF_INET6, ip, &addr6) == 1) + { +#ifdef CONFIG_NETUTILS_PING6 + icmp6_ping(&info6); + return replies; +#else + /* Fallback to network card status check */ +#endif + } + else + { +#ifdef CONFIG_NETUTILS_PING + icmp_ping(&info); + return replies; #else - nerr("ERROR: IP is NULL and no DNS server configured\n"); - return -EINVAL; + /* Fallback to network card status check */ #endif + } } - else + +#ifdef CONFIG_NETDEV_IFINDEX + ping_gateway(&info, &info6); +#endif + +#if defined(HAVE_ROUTE_PROCFS) && defined(CONFIG_NETUTILS_PING) + if (replies == 0) { - info.hostname = ip; + ping_route(&info); } +#endif - ninfo("ping ipaddr test %s \n", info.hostname); - icmp_ping(&info); +#if defined(HAVE_ROUTE_PROCFS) && defined(CONFIG_NETUTILS_PING6) + if (replies == 0) + { + ping6_route(&info6); + } +#endif + +#if !defined(CONFIG_NETDEV_IFINDEX) && !defined(HAVE_ROUTE_PROCFS) + replies = 1; +#endif return replies; } - -#endif /* CONFIG_NETUTILS_PING */ \ No newline at end of file diff --git a/netutils/netlib/netlib_ipv6route.c b/netutils/netlib/netlib_ipv6route.c index a0e10fa7c77..14bcc2e9fea 100644 --- a/netutils/netlib/netlib_ipv6route.c +++ b/netutils/netlib/netlib_ipv6route.c @@ -49,14 +49,14 @@ /* 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 + * 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 */ -#define ADDR_OFFSET 15 +#define ADDR_OFFSET 14 /**************************************************************************** * Private Functions