From 951f1300a0a789f46f8b2660ad68318f3843a5ba Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Wed, 3 Feb 2016 16:04:32 +0100 Subject: [PATCH] sys: shell: ping6: require device parameter for link-local addresses --- sys/shell/commands/sc_icmpv6_echo.c | 49 +++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/sys/shell/commands/sc_icmpv6_echo.c b/sys/shell/commands/sc_icmpv6_echo.c index 5a61a2df97..c418e06396 100644 --- a/sys/shell/commands/sc_icmpv6_echo.c +++ b/sys/shell/commands/sc_icmpv6_echo.c @@ -38,9 +38,10 @@ static char ipv6_str[IPV6_ADDR_MAX_STR_LEN]; static void usage(char **argv) { - printf("%s [] [] [] []\n", argv[0]); + printf("%s [] [%%] [] [] []\n", argv[0]); puts("defaults:"); puts(" count = 3"); + puts(" interface = first interface if only one present, only needed for link-local addresses"); puts(" payload_len = 4"); puts(" delay = 1000"); puts(" stats interval = count"); @@ -148,6 +149,7 @@ int _icmpv6_ping(int argc, char **argv) uint32_t delay = 1 * SEC_IN_MS; char *addr_str; ipv6_addr_t addr; + kernel_pid_t src_iface; msg_t msg; gnrc_netreg_entry_t *ipv6_entry, my_entry = { NULL, ICMPV6_ECHO_REP, thread_getpid() }; @@ -170,7 +172,6 @@ int _icmpv6_ping(int argc, char **argv) stat_interval = count; addr_str = argv[1 + param_offset]; - if (argc > (2 + param_offset)) { payload_len = atoi(argv[2 + param_offset]); } @@ -186,11 +187,43 @@ int _icmpv6_ping(int argc, char **argv) return 1; } + src_iface = ipv6_addr_split_iface(addr_str); + if (src_iface == -1) { + src_iface = KERNEL_PID_UNDEF; + } + if (ipv6_addr_from_str(&addr, addr_str) == NULL) { puts("error: malformed address"); return 1; } + if (ipv6_addr_is_link_local(&addr) || (src_iface != KERNEL_PID_UNDEF)) { + kernel_pid_t ifs[GNRC_NETIF_NUMOF]; + size_t ifnum = gnrc_netif_get(ifs); + if (src_iface == KERNEL_PID_UNDEF) { + if (ifnum == 1) { + src_iface = ifs[0]; + } + else { + puts("error: link local target needs interface parameter (use \"
%\")\n"); + return 1; + } + } + else { + int valid = 0; + for (size_t i = 0; i < ifnum && i < GNRC_NETIF_NUMOF; i++) { + if (ifs[i] == src_iface) { + valid = 1; + break; + } + } + if (!valid) { + printf("error: %"PRIkernel_pid" is not a valid interface.\n", src_iface); + return 1; + } + } + } + if (gnrc_netreg_register(GNRC_NETTYPE_ICMPV6, &my_entry) < 0) { puts("error: network registry is full"); return 1; @@ -229,6 +262,18 @@ int _icmpv6_ping(int argc, char **argv) continue; } + if (src_iface != KERNEL_PID_UNDEF) { + pkt = gnrc_pktbuf_add(pkt, NULL, sizeof(gnrc_netif_hdr_t), + GNRC_NETTYPE_NETIF); + + if (pkt == NULL) { + puts("error: packet buffer full"); + continue; + } + + ((gnrc_netif_hdr_t *)pkt->data)->if_pid = src_iface; + } + start = xtimer_now(); if (gnrc_netapi_send(ipv6_entry->pid, pkt) < 1) { puts("error: unable to send ICMPv6 echo request\n");