From a750be83fc6d44839905b0f92d0e66295c96119b Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 23 Jan 2015 12:49:49 -0600 Subject: apps/nshlib: Add the ping6 command to support checking IPv6 networks. NSH logic is complete but still missing some network level support --- apps/nshlib/README.txt | 16 ++- apps/nshlib/nsh.h | 6 + apps/nshlib/nsh_command.c | 8 +- apps/nshlib/nsh_netcmds.c | 319 +++++++++++++++++++++++++++++++++++----------- 4 files changed, 265 insertions(+), 84 deletions(-) (limited to 'apps') diff --git a/apps/nshlib/README.txt b/apps/nshlib/README.txt index 01f2401bb..970d6e250 100644 --- a/apps/nshlib/README.txt +++ b/apps/nshlib/README.txt @@ -776,6 +776,7 @@ o ps nsh> o ping [-c ] [-i ] + ping6 [-c ] [-i ] Test the network communication with a remote peer. Example, @@ -794,6 +795,8 @@ o ping [-c ] [-i ] 10 packets transmitted, 10 received, 0% packet loss, time 10190 ms nsh> + ping6 differs from ping in that it uses IPv6 addressing. + o put [-b|-n] [-f ] -h Copy the file at to the host whose IP address is @@ -980,6 +983,7 @@ Command Dependencies on Configuration Settings mv (((!CONFIG_DISABLE_MOUNTPOINT && CONFIG_FS_WRITABLE) || !CONFIG_DISABLE_PSEUDOFS_OPERATIONS) && CONFIG_NFILE_DESCRIPTORS > 0) (see note 4) nfsmount !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NET && CONFIG_NFS ping CONFIG_NET && CONFIG_NET_ICMP && CONFIG_NET_ICMP_PING && !CONFIG_DISABLE_SIGNALS + ping6 CONFIG_NET && CONFIG_NET_ICMPv6 && CONFIG_NET_ICMPv6_PING && !CONFIG_DISABLE_SIGNALS ps -- put CONFIG_NET && CONFIG_NET_UDP && CONFIG_NFILE_DESCRIPTORS > 0 && MTU >= 558 (see note 1,2) pwd !CONFIG_DISABLE_ENVIRON && CONFIG_NFILE_DESCRIPTORS > 0 @@ -1023,12 +1027,12 @@ also allow it to squeeze into very small memory footprints. CONFIG_NSH_DISABLE_MKFATFS, CONFIG_NSH_DISABLE_MKFIFO, CONFIG_NSH_DISABLE_MKRD, CONFIG_NSH_DISABLE_MH, CONFIG_NSH_DISABLE_MOUNT, CONFIG_NSH_DISABLE_MW, CONFIG_NSH_DISABLE_MV, CONFIG_NSH_DISABLE_NFSMOUNT, CONFIG_NSH_DISABLE_PS, - CONFIG_NSH_DISABLE_PING, CONFIG_NSH_DISABLE_PUT, CONFIG_NSH_DISABLE_PWD, - CONFIG_NSH_DISABLE_RM, CONFIG_NSH_DISABLE_RMDIR, CONFIG_NSH_DISABLE_SET, - CONFIG_NSH_DISABLE_SH, CONFIG_NSH_DISABLE_SLEEP, CONFIG_NSH_DISABLE_TEST, - CONFIG_NSH_DISABLE_UMOUNT, CONFIG_NSH_DISABLE_UNSET, CONFIG_NSH_DISABLE_URLDECODE, - CONFIG_NSH_DISABLE_URLENCODE, CONFIG_NSH_DISABLE_USLEEP, CONFIG_NSH_DISABLE_WGET, - CONFIG_NSH_DISABLE_XD + CONFIG_NSH_DISABLE_PING, CONFIG_NSH_DISABLE_PING6, CONFIG_NSH_DISABLE_PUT, + CONFIG_NSH_DISABLE_PWD, CONFIG_NSH_DISABLE_RM, CONFIG_NSH_DISABLE_RMDIR, + CONFIG_NSH_DISABLE_SET, CONFIG_NSH_DISABLE_SH, CONFIG_NSH_DISABLE_SLEEP, + CONFIG_NSH_DISABLE_TEST, CONFIG_NSH_DISABLE_UMOUNT, CONFIG_NSH_DISABLE_UNSET, + CONFIG_NSH_DISABLE_URLDECODE, CONFIG_NSH_DISABLE_URLENCODE, CONFIG_NSH_DISABLE_USLEEP, + CONFIG_NSH_DISABLE_WGET, CONFIG_NSH_DISABLE_XD Verbose help output can be suppressed by defining CONFIG_NSH_HELP_TERSE. In that case, the help command is still available but will be slightly smaller. diff --git a/apps/nshlib/nsh.h b/apps/nshlib/nsh.h index 89c8763b2..1bd41f319 100644 --- a/apps/nshlib/nsh.h +++ b/apps/nshlib/nsh.h @@ -963,6 +963,12 @@ void nsh_usbtrace(void); int cmd_ping(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); # endif # endif +# if defined(CONFIG_NET_ICMPv6) && defined(CONFIG_NET_ICMPv6_PING) && \ + !defined(CONFIG_DISABLE_SIGNALS) +# ifndef CONFIG_NSH_DISABLE_PING6 + int cmd_ping6(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# endif # if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0 # ifndef CONFIG_NSH_DISABLE_PUT int cmd_put(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); diff --git a/apps/nshlib/nsh_command.c b/apps/nshlib/nsh_command.c index 3950b3379..fa8efa9c5 100644 --- a/apps/nshlib/nsh_command.c +++ b/apps/nshlib/nsh_command.c @@ -1,7 +1,7 @@ /**************************************************************************** * apps/nshlib/nsh_command.c * - * Copyright (C) 2007-2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -323,6 +323,12 @@ static const struct cmdmap_s g_cmdmap[] = # endif #endif +#if defined(CONFIG_NET) && defined(CONFIG_NET_ICMPv6) && defined(CONFIG_NET_ICMPv6_PING) && !defined(CONFIG_DISABLE_SIGNALS) +# ifndef CONFIG_NSH_DISABLE_PING6 + { "ping6", cmd_ping6, 2, 6, "[-c ] [-i ] " }, +# endif +#endif + #ifndef CONFIG_NSH_DISABLE_PS { "ps", cmd_ps, 1, 1, NULL }, #endif diff --git a/apps/nshlib/nsh_netcmds.c b/apps/nshlib/nsh_netcmds.c index e9315c4b5..8f6422de7 100644 --- a/apps/nshlib/nsh_netcmds.c +++ b/apps/nshlib/nsh_netcmds.c @@ -1,7 +1,7 @@ /**************************************************************************** * apps/nshlib/nsh_netcmds.c * - * Copyright (C) 2007-2012, 2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2012, 2014-2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -64,6 +64,8 @@ #include #include #include +#include +#include #if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \ !defined(CONFIG_DISABLE_SIGNALS) @@ -96,9 +98,22 @@ #include "nsh_console.h" /**************************************************************************** - * Definitions + * Pre-processor Definitions ****************************************************************************/ +#undef HAVE_PING +#undef HAVE_PING6 + +#if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \ + !defined(CONFIG_DISABLE_SIGNALS) && !defined(CONFIG_NSH_DISABLE_PING) +# define HAVE_PING +#endif + +#if defined(CONFIG_NET_ICMPv6) && defined(CONFIG_NET_ICMPv6_PING) && \ + !defined(CONFIG_DISABLE_SIGNALS) && !defined(CONFIG_NSH_DISABLE_PING6) +# define HAVE_PING6 +#endif + /* Size of the ECHO data */ #define DEFAULT_PING_DATALEN 56 @@ -132,8 +147,7 @@ struct tftpc_args_s * Private Data ****************************************************************************/ -#if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \ - !defined(CONFIG_DISABLE_SIGNALS) +#if defined(HAVE_PING) || defined(HAVE_PING6) static uint16_t g_pingid = 0; #endif @@ -149,16 +163,108 @@ static uint16_t g_pingid = 0; * Name: ping_newid ****************************************************************************/ -#if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \ - !defined(CONFIG_DISABLE_SIGNALS) -static inline uint16_t ping_newid(void) +#if defined(HAVE_PING) || defined(HAVE_PING6) +static uint16_t ping_newid(void) { irqstate_t save = irqsave(); uint16_t ret = ++g_pingid; irqrestore(save); return ret; } -#endif +#endif /* HAVE_PING || HAVE_PINg */ + +/**************************************************************************** + * Name: ping_options + ****************************************************************************/ + +#if defined(HAVE_PING) || defined(HAVE_PING6) +static int ping_options(FAR struct nsh_vtbl_s *vtbl, + int argc, FAR char **argv, + FAR int *count, FAR uint32_t *dsec, FAR char **staddr) +{ + FAR const char *fmt = g_fmtarginvalid; + bool badarg = false; + int option; + int tmp; + + /* Get the ping options */ + + while ((option = getopt(argc, argv, ":c:i:")) != ERROR) + { + switch (option) + { + case 'c': + tmp = atoi(optarg); + if (tmp < 1 || tmp > 10000) + { + nsh_output(vtbl, g_fmtargrange, argv[0]); + badarg = true; + } + else + { + *count = tmp; + } + break; + + case 'i': + tmp = atoi(optarg); + if (tmp < 1 || tmp >= 4294) + { + nsh_output(vtbl, g_fmtargrange, argv[0]); + badarg = true; + } + else + { + *dsec = 10 * tmp; + } + break; + + case ':': + nsh_output(vtbl, g_fmtargrequired, argv[0]); + badarg = true; + break; + + case '?': + default: + nsh_output(vtbl, g_fmtarginvalid, argv[0]); + badarg = true; + break; + } + } + + /* If a bad argument was encountered, then return without processing the + * command + */ + + if (badarg) + { + return ERROR; + } + + /* There should be exactly on parameter left on the command-line */ + + if (optind == argc-1) + { + *staddr = argv[optind]; + } + else if (optind >= argc) + { + fmt = g_fmttoomanyargs; + goto errout; + } + else + { + fmt = g_fmtargrequired; + goto errout; + } + + return OK; + +errout: + nsh_output(vtbl, fmt, argv[0]); + return ERROR; +} +#endif /* HAVE_PING || HAVE_PING6 */ /**************************************************************************** * Name: net_statistics @@ -963,97 +1069,158 @@ int cmd_ifconfig(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) * Name: cmd_ping ****************************************************************************/ -#if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \ - !defined(CONFIG_DISABLE_SIGNALS) -#ifndef CONFIG_NSH_DISABLE_PING +#ifdef HAVE_PING int cmd_ping(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { - FAR const char *fmt = g_fmtarginvalid; - const char *staddr; + FAR char *staddr; in_addr_t ipaddr; uint32_t start; uint32_t next; uint32_t dsec = 10; uint32_t maxwait; uint16_t id; - bool badarg = false; int count = 10; - int option; int seqno; int replies = 0; int elapsed; + int ret; int tmp; int i; /* Get the ping options */ - while ((option = getopt(argc, argv, ":c:i:")) != ERROR) + ret = ping_options(vtbl, argc, argv, &count, &dsec, &staddr); + if (ret < 0) { - switch (option) - { - case 'c': - count = atoi(optarg); - if (count < 1 || count > 10000) - { - nsh_output(vtbl, g_fmtargrange, argv[0]); - badarg = true; - } - break; - - case 'i': - tmp = atoi(optarg); - if (tmp < 1 || tmp >= 4294) - { - nsh_output(vtbl, g_fmtargrange, argv[0]); - badarg = true; - } - else - { - dsec = 10 * tmp; - } - break; - - case ':': - nsh_output(vtbl, g_fmtargrequired, argv[0]); - badarg = true; - break; - - case '?': - default: - nsh_output(vtbl, g_fmtarginvalid, argv[0]); - badarg = true; - break; - } + return ERROR; } - /* If a bad argument was encountered, then return without processing the - * command - */ + /* Get the IP address in binary form */ - if (badarg) + if (dns_gethostip(staddr, &ipaddr) < 0) { + nsh_output(vtbl, g_fmtarginvalid, argv[0]); return ERROR; } - /* There should be exactly on parameter left on the command-line */ + /* Get the ID to use */ - if (optind == argc-1) + id = ping_newid(); + + /* The maximum wait for a response will be the larger of the inter-ping + * time and the configured maximum round-trip time. + */ + + maxwait = MAX(dsec, CONFIG_NSH_MAX_ROUNDTRIP); + + /* Loop for the specified count */ + + nsh_output(vtbl, "PING %d.%d.%d.%d %d bytes of data\n", + (ipaddr ) & 0xff, (ipaddr >> 8 ) & 0xff, + (ipaddr >> 16 ) & 0xff, (ipaddr >> 24 ) & 0xff, + DEFAULT_PING_DATALEN); + + start = clock_systimer(); + for (i = 1; i <= count; i++) { - staddr = argv[optind]; - if (dns_gethostip(staddr, &ipaddr) < 0) + /* Send the ECHO request and wait for the response */ + + next = clock_systimer(); + seqno = icmp_ping(ipaddr, id, i, DEFAULT_PING_DATALEN, maxwait); + + /* Was any response returned? We can tell if a non-negative sequence + * number was returned. + */ + + if (seqno >= 0 && seqno <= i) { - goto errout; + /* Get the elapsed time from the time that the request was + * sent until the response was received. If we got a response + * to an earlier request, then fudge the elapsed time. + */ + + elapsed = TICK2MSEC(clock_systimer() - next); + if (seqno < i) + { + elapsed += 100 * dsec * (i - seqno); + } + + /* Report the receipt of the reply */ + + nsh_output(vtbl, "%d bytes from %s: icmp_seq=%d time=%d ms\n", + DEFAULT_PING_DATALEN, staddr, seqno, elapsed); + replies++; + } + + /* Wait for the remainder of the interval. If the last seqno= argc) + + /* Get the total elapsed time */ + + elapsed = TICK2MSEC(clock_systimer() - start); + + /* Calculate the percentage of lost packets */ + + tmp = (100*(count - replies) + (count >> 1)) / count; + + nsh_output(vtbl, "%d packets transmitted, %d received, %d%% packet loss, time %d ms\n", + count, replies, tmp, elapsed); + return OK; +} +#endif /* HAVE_PING */ + +/**************************************************************************** + * Name: cmd_ping6 + ****************************************************************************/ + +#ifdef HAVE_PING6 +int cmd_ping6(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + FAR char *staddr; + struct in6_addr ipaddr; + uint32_t start; + uint32_t next; + uint32_t dsec = 10; + uint32_t maxwait; + uint16_t id; + int count = 10; + int seqno; + int replies = 0; + int elapsed; + int ret; + int tmp; + int i; + + /* Get the ping options */ + + ret = ping_options(vtbl, argc, argv, &count, &dsec, &staddr); + if (ret < 0) { - fmt = g_fmttoomanyargs; - goto errout; + return ERROR; } - else + + /* Get the IP address in binary form + * REVISIT: DNS hostname look-up not yet supported + */ + +#if 0 + ret = dns_gethostip(staddr, &ipaddr); +#else + ret = inet_pton(AF_INET6, staddr, &ipaddr); +#endif + if (ret < 0) { - fmt = g_fmtargrequired; - goto errout; + nsh_output(vtbl, g_fmtarginvalid, argv[0]); + return ERROR; } /* Get the ID to use */ @@ -1068,10 +1235,13 @@ int cmd_ping(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) /* Loop for the specified count */ - nsh_output(vtbl, "PING %d.%d.%d.%d %d bytes of data\n", - (ipaddr ) & 0xff, (ipaddr >> 8 ) & 0xff, - (ipaddr >> 16 ) & 0xff, (ipaddr >> 24 ) & 0xff, - DEFAULT_PING_DATALEN); + nsh_output(vtbl, + "PING6 %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x %d bytes of data\n", + ntohs(ipaddr.s6_addr16[0]), ntohs(ipaddr.s6_addr16[1]), + ntohs(ipaddr.s6_addr16[2]), ntohs(ipaddr.s6_addr16[3]), + ntohs(ipaddr.s6_addr16[4]), ntohs(ipaddr.s6_addr16[5]), + ntohs(ipaddr.s6_addr16[6]), ntohs(ipaddr.s6_addr16[7]), + count); start = clock_systimer(); for (i = 1; i <= count; i++) @@ -1079,7 +1249,7 @@ int cmd_ping(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) /* Send the ECHO request and wait for the response */ next = clock_systimer(); - seqno = icmp_ping(ipaddr, id, i, DEFAULT_PING_DATALEN, maxwait); + seqno = icmpv6_ping(ipaddr.s6_addr16, id, i, DEFAULT_PING_DATALEN, maxwait); /* Was any response returned? We can tell if a non-negative sequence * number was returned. @@ -1128,13 +1298,8 @@ int cmd_ping(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) nsh_output(vtbl, "%d packets transmitted, %d received, %d%% packet loss, time %d ms\n", count, replies, tmp, elapsed); return OK; - -errout: - nsh_output(vtbl, fmt, argv[0]); - return ERROR; } -#endif -#endif /* CONFIG_NET_ICMP && CONFIG_NET_ICMP_PING */ +#endif /* CONFIG_NET_ICMPv6 && CONFIG_NET_ICMPv6_PING */ /**************************************************************************** * Name: cmd_put -- cgit v1.2.3