• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  * Description: shell cmds APIs implementation about ping and ping6
15  * Author: none
16  * Create: 2020
17  */
18 
19 #include "lwip/nettool/ping.h"
20 #include "lwip/icmp.h"
21 #include "lwip/icmp6.h"
22 #include "lwip/sockets.h"
23 #include "lwip/ip.h"
24 #include "lwip/inet_chksum.h"
25 #include "lwip/nettool/utility.h"
26 #include "lwip/netdb.h"
27 #include "netif/ifaddrs.h"
28 #include "lwip/sys.h"
29 #if LWIP_LITEOS_COMPAT
30 #include "los_config.h"
31 #include <td_base.h>
32 #endif
33 
34 
35 #if LWIP_ENABLE_BASIC_SHELL_CMD
36 
37 /** LWIP_SHELL_CMD_PING_TIMEOUT: Ping cmd waiting timeout max(in millisec) to receive ping response */
38 #if !defined LWIP_SHELL_CMD_PING_TIMEOUT_MAX || defined __DOXYGEN__
39 #define LWIP_SHELL_CMD_PING_TIMEOUT_MAX 10000
40 #endif
41 
42 /** LWIP_SHELL_CMD_PING_TIMEOUT: Ping cmd waiting timeout min(in millisec) to receive ping response */
43 #if !defined LWIP_SHELL_CMD_PING_TIMEOUT_MIN || defined __DOXYGEN__
44 #define LWIP_SHELL_CMD_PING_TIMEOUT_MIN 1000
45 #endif
46 
47 #ifdef CUSTOM_AT_COMMAND
48 #define LWIP_PING_TASK_PRIO 5
49 #define LWIP_PING_MAX_PKT_LEN 7360
50 #else
51 #define LWIP_PING_TASK_PRIO 4
52 #endif
53 
54 #define LWIP_PING_INTERFACE_ARG       1
55 #define LWIP_PING_HOSTNAME_ARG        2
56 #define LWIP_PING_DEFAULT_SOCKET      4
57 #define PERCENT 100
58 
59 /* Maximum tick value that can be generated by sys_now() */
60 #define LWIP_MAX_TICK                 0xFFFFFFFF
61 #define LWIP_MAX_TICK_U64             0xFFFFFFFFFFFFFFFFLLU
62 #define LWIP_DEFAULT_PING_TASK_ID     0xFFFFFFFF
63 
64 static uint32_t ping_taskid = LWIP_DEFAULT_PING_TASK_ID;
65 static int ping_kill = 0;
66 static u8_t ping_task_running = 0;
67 #define PING_ZERO_DATA_LEN 8
68 #define SEC_TO_US   1000000
69 #define US_TO_NSEC  1000
70 
71 static void
lwip_ping_usage(u32_t is_v6)72 lwip_ping_usage(u32_t is_v6)
73 {
74 #ifndef CUSTOM_AT_COMMAND
75   char *ping = is_v6 ? "ping6" : "ping";
76   LWIP_PLATFORM_PRINT("Usage:"\
77          CRLF"  %s"
78          CRLF"  %s [-6] [-n cnt] [-w interval] [-l len] dest"
79          CRLF"  %s [-I iface/ipaddr] [-t] [-w interval] [-W timeout] dest"
80          CRLF"  %s -k  use -k to stop"
81          CRLF"  %s -t  ping forever"CRLF, ping, ping, ping, ping, ping);
82 #else
83   (void)is_v6;
84 #endif
85 }
86 
87 #if LWIP_LITEOS_TASK
88 /* help convert ptr to u32 array(if 64bit platfrom) */
89 union los_ptr_args {
90   void *ptr;
91   u32_t args[2];
92 };
93 #endif
94 
95 struct ping_run_ctx {
96   int sfd;
97   u32_t is_v6;
98   struct sockaddr_storage to;
99   struct icmp_echo_hdr *iecho;
100   struct icmp_echo_hdr *iecho_resp;
101   struct ip_hdr *iphdr_resp;
102   u32_t iecho_len;
103   s16_t ip_hlen;
104   u16_t i;
105   u32_t forever;
106   u32_t succ_cnt;
107   u32_t failed_cnt;
108 #if LWIP_LITEOS_TASK
109   u64_t start_us;
110   u64_t end_us;
111   u64_t timout_end_us;
112 #else
113   u32_t start_ms;
114   u32_t end_ms;
115   u32_t timout_end_ms;
116 #endif
117 
118 #ifdef CUSTOM_AT_COMMAND
119   s32_t rtt_sum;
120   s32_t rtt_min;
121   s32_t rtt_max;
122 #endif
123 
124   s32_t timout_ms;
125 #if LWIP_SOCKET_POLL && !LWIP_EXT_POLL_SUPPORT
126   struct pollfd pfd;
127 #else
128   fd_set read_set;
129   struct timeval time_val;
130 #endif
131   s32_t rtt;
132   u32_t intrvl;
133   char *data_buf;
134   struct sockaddr_storage dst;
135   u32_t socklen;
136   u32_t cnt;
137   u32_t timout;
138   u32_t interval;
139   u32_t data_len;
140 };
141 
142 #define PING_ADDR_STR_LEN IPADDR_STRLEN_MAX
143 
144 struct ping_cfg {
145   u32_t count;
146   u32_t interval;
147   u32_t timeout;
148   u32_t data_len;
149   struct sockaddr_storage dst;
150   u8_t src_type;
151   u32_t is_v6;
152   char src_iface[NETIF_NAMESIZE];
153   struct sockaddr_storage src;
154 };
155 
156 #ifdef CONFIG_SIGMA_SUPPORT
157 ping_result_callback upload_ping_result = NULL;
ping_add_ext_callback(ping_result_callback func)158 void ping_add_ext_callback(ping_result_callback func)
159 {
160   upload_ping_result = func;
161 }
162 #endif
163 
164 LWIP_STATIC void
ping_req_init(struct ping_run_ctx * ctx)165 ping_req_init(struct ping_run_ctx *ctx)
166 {
167   u32_t i;
168   if (ctx->data_len > PING_ZERO_DATA_LEN) {
169     (void)memset_s(ctx->iecho, sizeof(struct icmp_echo_hdr) + PING_ZERO_DATA_LEN, 0,
170                    sizeof(struct icmp_echo_hdr) + PING_ZERO_DATA_LEN);
171     ctx->data_buf = (char *)ctx->iecho + sizeof(struct icmp_echo_hdr) + PING_ZERO_DATA_LEN;
172     for (i = 0; i < ctx->data_len - PING_ZERO_DATA_LEN; i++) {
173       *(ctx->data_buf + i) = i + 0x10;
174     }
175   } else {
176     (void)memset_s(ctx->iecho, sizeof(struct icmp_echo_hdr) + ctx->data_len, 0,
177                    sizeof(struct icmp_echo_hdr) + ctx->data_len);
178   }
179   ctx->iecho->id = LWIP_RAND();
180 
181 #if LWIP_IPV6
182   if (ctx->is_v6) {
183     ICMPH_TYPE_SET(ctx->iecho, (u8_t)ICMP6_TYPE_EREQ);
184   } else
185 #endif
186   {
187     ICMPH_TYPE_SET(ctx->iecho, (u8_t)ICMP_ECHO);
188   }
189 }
190 
191 LWIP_STATIC int
ping_ctx_init(struct ping_run_ctx * ctx,struct ping_cfg * cfg)192 ping_ctx_init(struct ping_run_ctx *ctx, struct ping_cfg *cfg)
193 {
194   ctx->sfd = -1;
195   ctx->is_v6 = cfg->is_v6;
196   ctx->iecho = NULL;
197   ctx->iecho_resp = NULL;
198   ctx->iphdr_resp = NULL;
199   ctx->succ_cnt = 0;
200   ctx->failed_cnt = 0;
201 
202 #ifdef CUSTOM_AT_COMMAND
203   ctx->rtt_sum = 0;
204   ctx->rtt_min = 0;
205   ctx->rtt_max = 0;
206 #endif
207   ctx->data_buf = NULL;
208   ctx->dst = cfg->dst;
209 #if LWIP_IPV6
210   ctx->socklen = (ctx->dst.ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
211 #else
212   ctx->socklen = sizeof(struct sockaddr_in);
213 #endif
214   ctx->cnt = cfg->count;
215   ctx->interval = cfg->interval;
216   ctx->timout = cfg->timeout;
217   ctx->data_len = cfg->data_len;
218 
219   ctx->iecho_len = sizeof(struct icmp_echo_hdr) + ctx->data_len;
220   ctx->iphdr_resp = (struct ip_hdr *)mem_malloc(ctx->iecho_len + IP_HLEN_MAX);
221   if (ctx->iphdr_resp == NULL) {
222 #ifdef CUSTOM_AT_COMMAND
223     (void)uapi_at_printf("Ping: malloc fail"CRLF);
224 #else
225     LWIP_PLATFORM_PRINT("Ping: malloc fail"CRLF);
226 #endif
227     return -1;
228   }
229   ctx->iecho = (struct icmp_echo_hdr *)mem_malloc(ctx->iecho_len);
230   if (ctx->iecho == NULL) {
231 #ifdef CUSTOM_AT_COMMAND
232     (void)uapi_at_printf("Ping: request malloc fail"CRLF);
233 #else
234     LWIP_PLATFORM_PRINT("Ping: request malloc fail"CRLF);
235 #endif
236     return -1;
237   }
238   ctx->to = cfg->dst;
239   ctx->forever = (ctx->cnt ? 0 : 1);
240   ctx->i = 0;
241   ping_req_init(ctx);
242   return 0;
243 }
244 
245 
246 LWIP_STATIC void
ping_resp_code_print(u8_t iecho_resp)247 ping_resp_code_print(u8_t iecho_resp)
248 {
249   const char *printstr = NULL;
250   LWIP_STATIC const char *icmp_code_str[] = {
251     "icmp reply", /* ICMP_ER */
252     NULL,
253     NULL,
254     "destination host unreachable", /* ICMP_DUR */
255     "source quench", /* ICMP_SQ */
256     "redirect", /* ICMP_RD */
257     NULL,
258     NULL,
259     NULL,
260     NULL,
261     NULL,
262     "time exceeded", /* ICMP_TE */
263     "parameter problem" /* ICMP_PP */
264   };
265 
266   if (iecho_resp < LWIP_ARRAYSIZE(icmp_code_str)) {
267     printstr = icmp_code_str[iecho_resp];
268   }
269 
270   if (printstr == NULL) {
271     printstr = "unknow error";
272   }
273 #ifdef CUSTOM_AT_COMMAND
274   (void)uapi_at_printf("Ping: %s: "CRLF, printstr);
275 #else
276   LWIP_PLATFORM_PRINT("Ping: %s: "CRLF, printstr);
277 #endif
278 }
279 
280 LWIP_STATIC void
ping_resp_process(struct ping_run_ctx * ctx)281 ping_resp_process(struct ping_run_ctx *ctx)
282 {
283   u8_t af = AF_INET;
284   const char *ipstr = NULL;
285   char str_buf[PING_ADDR_STR_LEN];
286   const void *src = &(((struct sockaddr_in *)&ctx->to)->sin_addr);
287 
288 #if LWIP_IPV6
289   if (ctx->is_v6) {
290     af = AF_INET6;
291     src = &(((struct sockaddr_in6 *)&ctx->to)->sin6_addr);
292   }
293 #endif
294   ipstr = lwip_inet_ntop(af, src, str_buf, PING_ADDR_STR_LEN);
295   if (ipstr == NULL) {
296     ipstr = "****";
297   }
298 
299 #ifdef CUSTOM_AT_COMMAND
300 #if LWIP_IPV6
301   if (ctx->is_v6) {
302     (void)uapi_at_printf("%u bytes from %s: icmp_seq=%u ", ctx->data_len, ipstr, ctx->i);
303     if (ctx->rtt < 1) {
304       (void)uapi_at_printf("time<1ms"CRLF);
305     } else {
306       (void)uapi_at_printf("time=%ims"CRLF, ctx->rtt);
307     }
308   } else
309 #endif
310   {
311     (void)uapi_at_printf("[%u]Reply from %s:", ctx->i, ipstr);
312     if (ctx->rtt < 1) {
313       (void)uapi_at_printf("time<1ms ");
314     } else {
315       (void)uapi_at_printf("time=%dms ", ctx->rtt);
316     }
317     (void)uapi_at_printf("TTL=%u"CRLF, ctx->iphdr_resp->_ttl);
318   }
319 #else
320   LWIP_PLATFORM_PRINT("[%u]Reply from %s: ", ctx->i, ipstr);
321   if (ctx->rtt < 1) {
322     LWIP_PLATFORM_PRINT("time<1 ms ");
323   } else {
324     LWIP_PLATFORM_PRINT("time=%i ms ", ctx->rtt);
325   }
326   if (ctx->is_v6 == 0) {
327     LWIP_PLATFORM_PRINT("TTL=%u"CRLF, ctx->iphdr_resp->_ttl);
328   } else {
329     LWIP_PLATFORM_PRINT(CRLF);
330   }
331 #endif
332 
333   /* delay 1s for every successful ping */
334   ctx->intrvl = ctx->interval;
335   if (((ctx->succ_cnt + ctx->failed_cnt + 1) < ctx->cnt) || ctx->forever) {
336     do {
337       if (ctx->intrvl < MS_PER_SECOND) {
338         sys_msleep(ctx->intrvl);
339         break;
340       }
341       ctx->intrvl -= MS_PER_SECOND;
342       sys_msleep(MS_PER_SECOND);
343       if (ping_kill == 1) {
344         break;
345       }
346     } while (ctx->intrvl > 0);
347   }
348   ctx->succ_cnt++;
349 #ifdef CUSTOM_AT_COMMAND
350   if (ctx->rtt >= 1) {
351     ctx->rtt_sum += ctx->rtt;
352   }
353   if ((ctx->rtt < ctx->rtt_min) || (ctx->succ_cnt == 1)) {
354     ctx->rtt_min = ctx->rtt;
355   }
356   if ((ctx->rtt > ctx->rtt_max) || (ctx->succ_cnt == 1)) {
357     ctx->rtt_max = ctx->rtt;
358   }
359 #endif
360 }
361 
362 #if LWIP_LITEOS_TASK
uapi_get_us(td_void)363 td_u64 uapi_get_us(td_void)
364 {
365     struct timespec tp;
366 
367     if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
368         return (td_u64)(td_u32)tp.tv_sec * SEC_TO_US + (td_u32)tp.tv_nsec / US_TO_NSEC;
369     } else {
370         return (td_u64)(EXT_ERR_FAILURE);
371     }
372 }
373 #endif
374 
375 LWIP_STATIC void
ping_rcv_rtt_calc(struct ping_run_ctx * ctx)376 ping_rcv_rtt_calc(struct ping_run_ctx *ctx)
377 {
378 #if LWIP_LITEOS_TASK
379   ctx->timout_end_us = uapi_get_us();
380   if (ctx->timout_end_us < ctx->start_us) {
381     /* Incase of wraparoud of ticks */
382     ctx->rtt = (s32_t)(ctx->timout_end_us / US_PER_MSECOND + ((LWIP_MAX_TICK_U64 - ctx->start_us) / US_PER_MSECOND));
383   } else {
384     ctx->rtt = (s32_t)(ctx->timout_end_us / US_PER_MSECOND - ctx->start_us / US_PER_MSECOND);
385   }
386 #else
387   ctx->timout_end_ms = sys_now();
388   ctx->rtt = (s32_t)(ctx->timout_end_ms - ctx->start_ms);
389   if (ctx->rtt < 0) {
390     ctx->rtt = (s32_t)(ctx->timout_end_ms + (LWIP_MAX_TICK - ctx->start_ms));
391   }
392 #endif
393 }
394 
395 #if LWIP_IPV6
convert_icmpv6_err_to_string(u8_t err_type)396 LWIP_STATIC const char *convert_icmpv6_err_to_string(u8_t err_type)
397 {
398   switch (err_type) {
399     case ICMP6_TYPE_DUR:
400       return "Destination Unreachable";
401     case ICMP6_TYPE_PTB:
402       return "Packet too big";
403     case ICMP6_TYPE_TE:
404       return "Time Exceeded";
405     case ICMP6_TYPE_PP:
406       return "Parameter Problem";
407     default:
408       break;
409   }
410   return NULL;
411 }
412 #endif
413 
414 LWIP_STATIC int
ping_rcv_check(struct ping_run_ctx * ctx,int len)415 ping_rcv_check(struct ping_run_ctx *ctx, int len)
416 {
417 #if LWIP_IPV6
418   int ip_hlen_min = ctx->is_v6 ? 0 : IP_HLEN;
419 #else
420   int ip_hlen_min = IP_HLEN;
421 #endif
422 
423   if ((u32_t)len < sizeof(struct icmp_echo_hdr) + ip_hlen_min) {
424 #ifdef CUSTOM_AT_COMMAND
425     /* Drop the packet if its too short [Doesnot contain even the header !!] */
426     (void)uapi_at_printf("ping: received ICMP echo response too short for less icmp header\n");
427 #else
428     LWIP_PLATFORM_PRINT("Ping: received ICMP echo response too short for less icmp header\n");
429 #endif
430     return -1;
431   }
432 
433   /* Accessing ip header and icmp header */
434 #if LWIP_IPV6
435   ctx->ip_hlen = ctx->is_v6 ? 0 : (IPH_HL(ctx->iphdr_resp) << 2);
436 #else
437   ctx->ip_hlen = (IPH_HL(ctx->iphdr_resp) << 2);
438 #endif
439   if ((u32_t)len < sizeof(struct icmp_echo_hdr) + ctx->ip_hlen) {
440 #ifdef CUSTOM_AT_COMMAND
441     /* Drop the packet if its too short [Doesnot contain send len !!] */
442     (void)uapi_at_printf("ping : received ICMP echo response too short for not equal send len\n");
443 #else
444     LWIP_PLATFORM_PRINT("Ping: received ICMP echo response too short for not equal send len\n");
445 #endif
446     return -1;
447   }
448 
449 #if LWIP_IPV6
450   if (ctx->is_v6) {
451     ctx->iecho_resp = (struct icmp_echo_hdr *)((char *)ctx->iphdr_resp);
452   } else
453 #endif
454   {
455     struct sockaddr_in *sin = (struct sockaddr_in *)&ctx->to;
456     if (sin->sin_addr.s_addr != ctx->iphdr_resp->src.addr) {
457       return -1;
458     }
459     ctx->iecho_resp = (struct icmp_echo_hdr *)((char *)ctx->iphdr_resp + ctx->ip_hlen);
460   }
461 
462 #if LWIP_IPV6
463   if (ctx->is_v6) {
464      if (ICMPH_TYPE(ctx->iecho_resp) != ICMP6_TYPE_EREP) {
465         const char *err_str = convert_icmpv6_err_to_string(ICMPH_TYPE(ctx->iecho_resp));
466         if (err_str != NULL) {
467 #ifdef CUSTOM_AT_COMMAND
468           (void)uapi_at_printf("ping: %s"CRLF, err_str);
469 #else
470           LWIP_PLATFORM_PRINT("ping: %s"CRLF, err_str);
471 #endif
472         }
473         return -1;
474      }
475   } else
476 #endif
477   {
478     if (ICMPH_TYPE(ctx->iecho_resp) == ICMP_ECHO) {
479       /* skip loopback ICMP_ECHO */
480       return -1;
481     } else if (ICMPH_TYPE(ctx->iecho_resp) != ICMP_ER) {
482       ping_resp_code_print(ICMPH_TYPE(ctx->iecho_resp));
483       return -1;
484     }
485   }
486 
487   if (ctx->iecho_resp->id != ctx->iecho->id) {
488 #ifdef CUSTOM_AT_COMMAND
489     (void)uapi_at_printf("Ping : recv id unmatch"CRLF);
490 #else
491     LWIP_PLATFORM_PRINT("Ping: recv id unmatch %u %u"CRLF, ctx->iecho_resp->id, ctx->iecho->id);
492 #endif
493     return -1;
494   }
495 
496   if (ntohs(ctx->iecho_resp->seqno) != ctx->i) {
497 #ifndef CUSTOM_AT_COMMAND
498     LWIP_PLATFORM_PRINT("Ping: recv seqno unmatch"CRLF);
499 #endif
500     return -1;
501   }
502 
503   return 0;
504 }
505 
506 LWIP_STATIC int
ping_rcv_poll(struct ping_run_ctx * ctx)507 ping_rcv_poll(struct ping_run_ctx *ctx)
508 {
509 #if LWIP_SOCKET_POLL && !LWIP_EXT_POLL_SUPPORT
510   /* poll for ICMP echo response msg */
511   ctx->pfd.fd = ctx->sfd;
512   ctx->pfd.events = POLLIN;
513   ctx->pfd.revents = 0;
514   return poll(&ctx->pfd, 1, ctx->timout_ms);
515 #else
516   /* Wait in select for ICMP response msg */
517   FD_ZERO(&ctx->read_set);
518   FD_SET(ctx->sfd, &ctx->read_set);
519   ctx->time_val.tv_sec = ctx->timout_ms / MS_PER_SECOND;
520   ctx->time_val.tv_usec = (ctx->timout_ms % MS_PER_SECOND) * US_PER_MSECOND;
521   return lwip_select(ctx->sfd + 1, &ctx->read_set, 0, 0, &ctx->time_val);
522 #endif
523 }
524 
525 LWIP_STATIC int
ping_rcv(struct ping_run_ctx * ctx)526 ping_rcv(struct ping_run_ctx *ctx)
527 {
528   int ret;
529   /* capture the start ms to calculate RTT */
530 #if LWIP_LITEOS_TASK
531   ctx->start_us = uapi_get_us();
532 #else
533   ctx->start_ms = sys_now();
534 #endif
535   ctx->timout_ms = (s32_t)ctx->timout;
536 
537   do {
538     ret = ping_rcv_poll(ctx);
539     if (ret < 0) {
540 #ifdef CUSTOM_AT_COMMAND
541       (void)uapi_at_printf("ping : poll/select failure, errno = %d"CRLF, errno);
542 #else
543       LWIP_PLATFORM_PRINT("ping : poll/select failure, errno = %d"CRLF, errno);
544 #endif
545       return -1;
546     } else if (ret == 0) {
547       /* first type timeout event */
548       break;
549     }
550 
551     /* construct timeout event if poll lose efficacy when other host ping us */
552     ret = recv(ctx->sfd, ctx->iphdr_resp, ctx->iecho_len + IP_HLEN_MAX, MSG_DONTWAIT);
553     if (ret < 0) {
554 #ifdef CUSTOM_AT_COMMAND
555       (void)uapi_at_printf(CRLF"Recv failed errno = %d"CRLF, errno);
556 #else
557       LWIP_PLATFORM_PRINT(CRLF"Recv failed errno = %d"CRLF, errno);
558 #endif
559       return -1;
560     }
561     ping_rcv_rtt_calc(ctx);
562     ctx->timout_ms = ctx->timout - ctx->rtt;
563     if (ping_rcv_check(ctx, ret) == 0) {
564       ping_resp_process(ctx);
565       ctx->i++;
566       return 0;
567     }
568   } while (ctx->timout_ms > 0);
569 
570   /* all timeout events are true timeout */
571   ctx->i++;
572   ctx->failed_cnt++;
573 #ifdef CUSTOM_AT_COMMAND
574   (void)uapi_at_printf(CRLF"Ping: destination unreachable"CRLF);
575 #else
576   LWIP_PLATFORM_PRINT("Ping: destination unreachable"CRLF);
577 #endif
578   return 0;
579 }
580 
581 LWIP_STATIC void
ping_result_print(struct ping_run_ctx * ctx)582 ping_result_print(struct ping_run_ctx *ctx)
583 {
584 #ifdef CUSTOM_AT_COMMAND
585   (void)uapi_at_printf("%u packets transmitted, %u received, ", ctx->succ_cnt + ctx->failed_cnt, ctx->succ_cnt);
586 #if LWIP_IPV6
587   if (ctx->is_v6) {
588     float loss = ((float)ctx->failed_cnt * PERCENT) / (ctx->succ_cnt + ctx->failed_cnt);
589     (void)uapi_at_printf("%.2f%% loss", loss);
590   } else
591 #endif
592   {
593     (void)uapi_at_printf("%u loss", ctx->failed_cnt);
594   }
595 
596   if (ctx->succ_cnt > 0) {
597     s32_t rtt_ave = ctx->rtt_sum / (s32_t)ctx->succ_cnt;
598     (void)uapi_at_printf(", rtt min/avg/max = %d/%d/%d ms"CRLF, ctx->rtt_min, rtt_ave, ctx->rtt_max);
599     (void)uapi_at_printf(CRLF"OK"CRLF);
600   } else {
601     (void)uapi_at_printf(CRLF"ERROR"CRLF);
602   }
603 #else
604   u8_t af = AF_INET;
605   const char *ipstr = NULL;
606   char str_buf[PING_ADDR_STR_LEN];
607   const void *src = &(((struct sockaddr_in *)&ctx->to)->sin_addr);
608 
609 #if LWIP_IPV6
610   if (ctx->is_v6) {
611     af = AF_INET6;
612     src = &(((struct sockaddr_in6 *)&ctx->to)->sin6_addr);
613   }
614 #endif
615   ipstr = lwip_inet_ntop(af, src, str_buf, PING_ADDR_STR_LEN);
616   if (ipstr == NULL) {
617     ipstr = "****";
618   }
619 
620   LWIP_PLATFORM_PRINT(CRLF"--- %s ping statistics ---"CRLF, ipstr);
621   LWIP_PLATFORM_PRINT("%u packets transmitted, %u received, %u loss"CRLF, ctx->succ_cnt + ctx->failed_cnt,
622          ctx->succ_cnt, ctx->failed_cnt);
623   LWIP_PLATFORM_PRINT(CRLF"OK"CRLF);
624 #endif
625 }
626 
ping_setsockopt(struct ping_run_ctx * ctx,struct ping_cfg * cfg)627 LWIP_STATIC int ping_setsockopt(struct ping_run_ctx *ctx, struct ping_cfg *cfg)
628 {
629   int ret;
630   if (cfg->src_type == LWIP_PING_HOSTNAME_ARG) {
631     ret = lwip_bind(ctx->sfd, (struct sockaddr *)&cfg->src, (socklen_t)ctx->socklen);
632     if (ret == -1) {
633 #if CUSTOM_AT_COMMAND
634       (void)uapi_at_printf("ping bind fail errno = %d"CRLF, errno);
635 #else
636       LWIP_PLATFORM_PRINT("ping bind fail errno = %d"CRLF, errno);
637 #endif
638       return -1;
639     }
640   } else if (cfg->src_type == LWIP_PING_INTERFACE_ARG) {
641     struct ifreq req;
642     (void)memset_s(&req, sizeof(req), 0, sizeof(req));
643     ret = memcpy_s(req.ifr_ifrn.ifrn_name, sizeof(req.ifr_ifrn.ifrn_name) - 1, cfg->src_iface, strlen(cfg->src_iface));
644     if (ret != EOK) {
645       (void)lwip_close(ctx->sfd);
646       return -1;
647     }
648 
649     /* Binding socket to the provided netif */
650     ret = lwip_setsockopt(ctx->sfd, SOL_SOCKET, SO_BINDTODEVICE, &req, sizeof(req));
651     if (ret == -1) {
652       LWIP_PLATFORM_PRINT("ping: unknown iface %s errno %d"CRLF, cfg->src_iface, errno);
653       return -1;
654     }
655   }
656 
657 #if LWIP_IPV6 && LWIP_SOCK_OPT_ICMP6_FILTER
658   if (ctx->is_v6) {
659     struct icmp6_filter icmp6_sock_filter;
660     /* Setting socket filter since we are interested only in ECHO REPLY and ERROR messages */
661     ICMP6_FILTER_SETBLOCKALL(&icmp6_sock_filter);
662     ICMP6_FILTER_SETPASS(ICMP6_TYPE_EREP, &icmp6_sock_filter);
663     ICMP6_FILTER_SETPASS(ICMP6_TYPE_DUR, &icmp6_sock_filter);
664     ICMP6_FILTER_SETPASS(ICMP6_TYPE_PTB, &icmp6_sock_filter);
665     ICMP6_FILTER_SETPASS(ICMP6_TYPE_TE, &icmp6_sock_filter);
666 
667     ret = lwip_setsockopt(ctx->sfd, IPPROTO_ICMPV6, ICMP6_FILTER, &icmp6_sock_filter, sizeof(struct icmp6_filter));
668     if (ret == -1) {
669       LWIP_PLATFORM_PRINT("ping : setsockopt: errno %d"CRLF, errno);
670       return -1;
671     }
672   }
673 #endif /* LWIP_SOCK_OPT_ICMP6_FILTER */
674   return 0;
675 }
676 
677 /* as this is not an internal function removing static keyword */
678 LWIP_STATIC void
os_ping_func(void * para)679 os_ping_func(void* para)
680 {
681   LWIP_ERROR("os_ping_func para is null\n", para != NULL, return;);
682   struct ping_cfg *cfg = (struct ping_cfg *)para;
683 
684   struct ping_run_ctx ctx;
685   int ret = -1;
686 
687   if (ping_ctx_init(&ctx, cfg) != 0) {
688     mem_free(cfg);
689     goto FAILURE;
690   }
691 
692   if (ctx.is_v6 == 0) {
693     ctx.sfd = lwip_socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
694   }
695 #if LWIP_IPV6
696   else {
697     ctx.sfd = lwip_socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
698   }
699 #endif
700   if (ctx.sfd < 0) {
701 #ifdef CUSTOM_AT_COMMAND
702     (void)uapi_at_printf("Ping socket create fail, errno = %d"CRLF, errno);
703 #else
704     LWIP_PLATFORM_PRINT("Ping socket create fail, errno = %d"CRLF, errno);
705 #endif
706     mem_free(cfg);
707     goto FAILURE;
708   }
709 
710   if (ping_setsockopt(&ctx, cfg) == -1) {
711     mem_free(cfg);
712     goto FAILURE;
713   }
714 
715   mem_free(cfg);
716 #ifdef CUSTOM_AT_COMMAND
717   if (ctx.is_v6 == 0) {
718     (void)uapi_at_printf("+PING:"CRLF);
719   } else {
720     (void)uapi_at_printf("+PING6:"CRLF);
721   }
722 #endif
723   ping_task_running = 1;
724   while ((ping_kill == 0) && ((ctx.forever != 0) || ((ctx.succ_cnt + ctx.failed_cnt) < ctx.cnt))) {
725     ctx.iecho->seqno = htons((u16_t)ctx.i);
726     ctx.iecho->chksum = 0;
727     ctx.iecho->chksum = inet_chksum((void *)ctx.iecho, ctx.iecho_len);
728     ret = sendto(ctx.sfd, ctx.iecho, ctx.iecho_len, 0, (struct sockaddr *)&ctx.to, (socklen_t)ctx.socklen);
729     if (ret < 0) {
730 #ifdef CUSTOM_AT_COMMAND
731       (void)uapi_at_printf("Ping: sending ICMP echo request fail errno %d"CRLF, errno);
732 #else
733       LWIP_PLATFORM_PRINT("Ping: sending ICMP echo request fail errno %d"CRLF, errno);
734 #endif
735       goto FAILURE;
736     }
737 
738     if (ping_rcv(&ctx) != 0) {
739       break;
740     }
741   }
742 
743   ping_result_print(&ctx);
744 #ifdef CONFIG_SIGMA_SUPPORT
745   if(upload_ping_result) {
746     upload_ping_result(ctx.succ_cnt, ctx.failed_cnt);
747   }
748 #endif
749   ret = (ctx.succ_cnt > 0) ? 0 : -1;
750 FAILURE:
751   ping_kill = 0;
752   ping_taskid = LWIP_DEFAULT_PING_TASK_ID;
753   ping_task_running = 0;
754   if (ctx.sfd >= 0) {
755     (void)lwip_close(ctx.sfd);
756   }
757   if (ctx.iphdr_resp != NULL) {
758     mem_free(ctx.iphdr_resp);
759   }
760   if (ctx.iecho != NULL) {
761     mem_free(ctx.iecho);
762   }
763 }
764 
765 #if LWIP_LITEOS_TASK
766 static void
ping_cmd(unsigned int p0,unsigned int p1,unsigned int p2,unsigned int p3)767 ping_cmd(unsigned int p0, unsigned int p1, unsigned int p2, unsigned int p3)
768 {
769   union los_ptr_args ptr_args;
770 
771   ptr_args.args[0] = p0;
772   ptr_args.args[1] = p1;
773   os_ping_func((struct ping_cfg *)ptr_args.ptr);
774 
775   ping_taskid = LWIP_DEFAULT_PING_TASK_ID;
776   (void)p2;
777   (void)p3;
778 }
779 #endif
780 
781 struct ping_cfg_handle {
782   const char *key;
783   u32_t *data;
784   int min;
785   int max;
786   int arg_num;
787   int (*handle)(struct ping_cfg_handle *src_handle, const char *arg);
788 };
789 
790 LWIP_STATIC int
ping_cfg_parse_daddr(const char * daddr,struct sockaddr_storage * dst_ipaddr,u32_t is_v6)791 ping_cfg_parse_daddr(const char *daddr, struct sockaddr_storage *dst_ipaddr, u32_t is_v6)
792 {
793   dst_ipaddr->ss_family = AF_INET;
794 #if LWIP_IPV6
795   if (is_v6) {
796     dst_ipaddr->ss_family = AF_INET6;
797   }
798 #endif
799   /* initialize dst IP address */
800 #if LWIP_DNS
801   struct addrinfo hints_structure;
802   struct addrinfo *res = NULL;
803 
804   /* Resolve the given hostname */
805   hints_structure.ai_family = dst_ipaddr->ss_family;
806   hints_structure.ai_flags = 0;
807   if (lwip_getaddrinfo(daddr, NULL, &hints_structure, &res) != ERR_OK) {
808     goto fail;
809   }
810 
811 #if LWIP_IPV6
812   if (is_v6) {
813     struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)dst_ipaddr;
814     sin6->sin6_addr = ((struct sockaddr_in6 *)(res->ai_addr))->sin6_addr;
815     sin6->sin6_family = AF_INET6;
816     sin6->sin6_port = 0;
817     sin6->sin6_scope_id = 0;
818     sin6->sin6_flowinfo = 0;
819   } else
820 #endif
821   {
822     struct sockaddr_in *sin = (struct sockaddr_in *)dst_ipaddr;
823     sin->sin_addr = ((struct sockaddr_in *)(res->ai_addr))->sin_addr;
824     sin->sin_family = AF_INET;
825     sin->sin_port = 0;
826   }
827   lwip_freeaddrinfo(res);
828 #else /* LWIP_DNS */
829   void *buf = NULL;
830 #if LWIP_IPV6
831   if (is_v6) {
832     buf = &(((struct sockaddr_in6 *)dst_ipaddr)->sin6_addr);
833   } else
834 #endif
835   {
836     buf = &(((struct sockaddr_in *)dst_ipaddr)->sin_addr);
837   }
838 
839   if (lwip_inet_pton(dst_ipaddr->ss_family, daddr, buf) != 1) {
840     goto fail;
841   }
842 #endif /* LWIP_DNS */
843 
844 #if LWIP_IPV6
845   if (is_v6) {
846     ip6_addr_t ip6;
847     inet6_addr_to_ip6addr(&ip6, &((struct sockaddr_in6 *)dst_ipaddr)->sin6_addr);
848     if (ip6_addr_isany(&ip6) || ip6_addr_isnone(&ip6)) {
849       goto fail;
850     }
851   } else
852 #endif
853   {
854     ip4_addr_t ip4;
855     ip4.addr = ((struct sockaddr_in *)dst_ipaddr)->sin_addr.s_addr;
856     if ((ip4.addr == IPADDR_NONE) || (ip4.addr == IPADDR_ANY)) {
857       goto fail;
858     }
859   }
860   return 0;
861 
862 fail:
863 #ifdef CUSTOM_AT_COMMAND
864   (void)uapi_at_printf("Host:%s can't be resolved to IP"CRLF, daddr);
865 #else
866   LWIP_PLATFORM_PRINT("Host:%s can't be resolved to IP"CRLF, daddr);
867 #endif
868   return -1;
869 }
870 
ping_cfg_handle_src_addr(struct ping_cfg_handle * src_handle,const char * arg)871 LWIP_STATIC int ping_cfg_handle_src_addr(struct ping_cfg_handle *src_handle, const char *arg)
872 {
873   struct ping_cfg *cfg = (struct ping_cfg *)src_handle->data;
874   u16_t family = AF_INET;
875   void *buf = &(((struct sockaddr_in *)&cfg->src)->sin_addr);
876 
877 #if LWIP_IPV6
878   if (cfg->is_v6) {
879     family = AF_INET6;
880     buf = &(((struct sockaddr_in6 *)&cfg->src)->sin6_addr);
881   }
882 #endif
883   if (lwip_inet_pton(family, arg, buf) != 1) {
884     if (strcpy_s(cfg->src_iface, NETIF_NAMESIZE, arg) != EOK) {
885       return -1;
886     }
887 
888     cfg->src_type = LWIP_PING_INTERFACE_ARG;
889     return 0;
890   }
891 
892   struct sockaddr_in *sin = (struct sockaddr_in *)&cfg->src;
893   sin->sin_family = family;
894   cfg->src_type = LWIP_PING_HOSTNAME_ARG;
895   return 0;
896 }
897 
898 LWIP_STATIC int
ping_cfg_parse(int argc,const char ** argv,struct ping_cfg * cfg,u32_t * ping_kill_flag)899 ping_cfg_parse(int argc, const char **argv, struct ping_cfg *cfg, u32_t *ping_kill_flag)
900 {
901   u32_t ping_forever = 0;
902   u32_t i = 0;
903   u32_t j = 0;
904   s64_t ret;
905   struct ping_cfg_handle handle[] = {
906     {
907       .key = "-k",
908       .data = ping_kill_flag,
909       .min = 0,
910       .max = INT_MAX,
911       .arg_num = 0,
912       .handle = NULL,
913     },
914     {
915       .key = "-n",
916       .data = &cfg->count,
917       .min = 1,
918       .max = INT_MAX,
919       .arg_num = 1,
920       .handle = NULL,
921     },
922     {
923       .key = "-c",
924       .data = &cfg->count,
925       .min = 1,
926       .max = INT_MAX,
927       .arg_num = 1,
928       .handle = NULL,
929     },
930     {
931       .key = "-t",
932       .data = &ping_forever,
933       .min = 0,
934       .max = INT_MAX,
935       .arg_num = 0,
936       .handle = NULL,
937     },
938     {
939       .key = "-w",
940       .data = &cfg->interval,
941       .min = 1,
942       .max = INT_MAX,
943       .arg_num = 1,
944       .handle = NULL,
945     },
946     {
947       .key = "-W",
948       .data = &cfg->timeout,
949       .min = LWIP_SHELL_CMD_PING_TIMEOUT_MIN,
950       .max = LWIP_SHELL_CMD_PING_TIMEOUT_MAX,
951       .arg_num = 1,
952       .handle = NULL,
953     },
954     {
955       .key = "-l",
956       .data = &cfg->data_len,
957       .min = 0,
958 #ifndef CUSTOM_AT_COMMAND
959       .max = (int)(LWIP_MAX_UDP_RAW_SEND_SIZE - sizeof(struct icmp_echo_hdr)) - PBUF_ZERO_COPY_RESERVE,
960 #else
961       .max = LWIP_PING_MAX_PKT_LEN,
962 #endif
963       .arg_num = 1,
964       .handle = NULL,
965     },
966     {
967       .key = "-6",
968       .data = &cfg->is_v6,
969       .min = 0,
970       .max = INT_MAX,
971       .arg_num = 0,
972       .handle = NULL,
973     },
974     {
975       .key = "-I",
976       .data = (u32_t *)cfg,
977       .min = 0,
978       .max = INT_MAX,
979       .arg_num = 1,
980       .handle = ping_cfg_handle_src_addr,
981     },
982   };
983   cfg->count = LWIP_SHELL_CMD_PING_RETRY_TIMES;
984   cfg->is_v6 = 0;
985   /* could add more param support */
986   while (argc > 0) {
987     u8_t match = 0;
988     for (j = 0; j < LWIP_ARRAYSIZE(handle); j++) {
989       if (strcmp(argv[i], handle[j].key) == 0) {
990         if ((handle[j].arg_num + 1) > argc) {
991           goto param_error;
992         }
993 
994         if (handle[j].arg_num == 0) {
995           *(handle[j].data) = 1;
996           if (ping_kill_flag == handle[j].data) {
997             return 0;
998           }
999         } else if (handle[j].handle != NULL) {
1000           ret = (*handle[j].handle)(&handle[j], argv[i + 1]);
1001           if (ret != 0) {
1002 #ifdef CUSTOM_AT_COMMAND
1003             (void)uapi_at_printf("Ping %s arg error"CRLF, handle[j].key);
1004 #else
1005             LWIP_PLATFORM_PRINT("Ping %s arg error"CRLF, handle[j].key);
1006 #endif
1007             return -1;
1008           }
1009         } else {
1010           char *invalid_ptr;
1011           ret = strtoll(argv[i + 1], &invalid_ptr, 10);
1012           if(invalid_ptr && strlen(invalid_ptr) != 0) {
1013             LWIP_PLATFORM_PRINT("Invalid parameter: |%s|\n", argv[i + 1]);
1014             return -1;
1015           }
1016 
1017           if ((ret < (s64_t)handle[j].min) || (ret > (s64_t)handle[j].max)) {
1018 #ifdef CUSTOM_AT_COMMAND
1019             (void)uapi_at_printf("Ping %s arg error, range:[%d, %d] "CRLF,
1020                                handle[j].key, handle[j].min, handle[j].max);
1021 #else
1022             LWIP_PLATFORM_PRINT("Ping %s arg error, range:[%d, %d] "CRLF,
1023                    handle[j].key, handle[j].min, handle[j].max);
1024 #endif
1025             return -1;
1026           }
1027           *(handle[j].data) = (u32_t)ret;
1028         }
1029         i += handle[j].arg_num + 1;
1030         argc -= handle[j].arg_num + 1;
1031         match = 1;
1032         break;
1033       }
1034     }
1035 
1036     if (match == 0) {
1037       break;
1038     }
1039   }
1040 
1041   if (argc != 1) {
1042 param_error:
1043 #ifdef CUSTOM_AT_COMMAND
1044     (void)uapi_at_printf("Invalid param"CRLF);
1045 #else
1046     LWIP_PLATFORM_PRINT("Invalid param"CRLF);
1047 #endif
1048     return -1;
1049   }
1050 
1051   if (ping_cfg_parse_daddr(argv[i], &cfg->dst, cfg->is_v6) == -1) {
1052     return -1;
1053   }
1054 
1055   if (ping_forever == 1) {
1056     cfg->count = 0;
1057   }
1058   return 0;
1059 }
1060 
1061 #if LWIP_LITEOS_TASK
ping_task_create(struct ping_cfg * cfg,u16_t prio)1062 LWIP_STATIC u32_t ping_task_create(struct ping_cfg *cfg, u16_t prio)
1063 {
1064   UINT32 los_ret;
1065   TSK_INIT_PARAM_S st_ping_task;
1066   union los_ptr_args ptr_args = {0};
1067 
1068   /* start one task if ping forever or ping count greater than 60 */
1069   if (ping_taskid != LWIP_DEFAULT_PING_TASK_ID) {
1070 #ifdef CUSTOM_AT_COMMAND
1071     (void)uapi_at_printf("Ping task is running"CRLF);
1072 #else
1073     LWIP_PLATFORM_PRINT("Ping task is running"CRLF);
1074 #endif
1075     return OS_NOK;
1076   }
1077   ptr_args.ptr = cfg;
1078 
1079   st_ping_task.pfnTaskEntry = (TSK_ENTRY_FUNC)ping_cmd;
1080   st_ping_task.uwStackSize  = 4096;
1081   st_ping_task.pcName = "ping_task";
1082   st_ping_task.usTaskPrio = prio; /* equal lwip */
1083   st_ping_task.uwResved = LOS_TASK_STATUS_DETACHED;
1084 #ifdef LOSCFG_OBSOLETE_API
1085   st_ping_task.auwArgs[0] = ptr_args.args[0];
1086   st_ping_task.auwArgs[1] = ptr_args.args[1];
1087   st_ping_task.auwArgs[2] = 0;
1088   st_ping_task.auwArgs[3] = 0;
1089 #else
1090   st_ping_task.pArgs=(void*)(ptr_args.args[0]);
1091 #endif
1092   los_ret = LOS_TaskCreate((UINT32 *)(&ping_taskid), &st_ping_task);
1093   if (los_ret != OS_OK) {
1094 #ifdef CUSTOM_AT_COMMAND
1095     (void)uapi_at_printf("ping_task create fail 0x%08x."CRLF, los_ret);
1096 #else
1097     LWIP_PLATFORM_PRINT("ping_task create fail 0x%08x."CRLF, los_ret);
1098 #endif
1099     return OS_NOK;
1100   }
1101   return OS_OK;
1102 }
1103 #endif
1104 
ping_exec(struct ping_cfg * cfg)1105 LWIP_STATIC u32_t ping_exec(struct ping_cfg *cfg)
1106 {
1107 #ifdef CUSTOM_AT_COMMAND
1108 #if LWIP_LITEOS_TASK
1109   u32_t ret = ping_task_create(cfg, LWIP_PING_TASK_PRIO);
1110   if (ret != OS_OK) {
1111     mem_free(cfg);
1112   }
1113   return ret;
1114 #endif
1115 #else
1116 #if LWIP_LITEOS_TASK
1117   /* start one task if ping forever or ping count greater than 60 */
1118   if ((cfg->count == 0) || (cfg->count > LWIP_SHELL_CMD_PING_RETRY_TIMES)) {
1119     u32_t ret = ping_task_create(cfg, LWIP_PING_TASK_PRIO);
1120     if ((ret == OS_NOK) || (ping_taskid == LWIP_DEFAULT_PING_TASK_ID)) {
1121       cfg->count = LWIP_SHELL_CMD_PING_RETRY_TIMES;
1122     } else {
1123       return OS_OK;
1124     }
1125   }
1126 #endif
1127   /* Use threads to perform ping operations. */
1128   ping_taskid = sys_thread_new("ping_thread", os_ping_func, (void*)cfg, TCPIP_THREAD_STACKSIZE, 8);
1129 #if !LWIP_FREERTOS_COMPAT
1130   /* Bugfix: The processing of the thread return is slower than that of the os_ping_func function. */
1131   ping_taskid = ping_task_running == 0 ? LWIP_DEFAULT_PING_TASK_ID : ping_taskid;
1132 #endif
1133   return OS_OK;
1134 #endif
1135 }
1136 
1137 u32_t
os_shell_ping(int argc,const char ** argv)1138 os_shell_ping(int argc, const char **argv)
1139 {
1140   struct ping_cfg *cfg = NULL;
1141   u32_t ping_kill_flag = 0;
1142 
1143   if (tcpip_init_finish == 0) {
1144 #ifdef CUSTOM_AT_COMMAND
1145     (void)uapi_at_printf("shell_ping tcpip_init have not been called"CRLF);
1146 #else
1147     LWIP_PLATFORM_PRINT("shell_ping tcpip_init have not been called"CRLF);
1148 #endif
1149     return OS_NOK;
1150   }
1151 
1152   cfg = mem_malloc(sizeof(struct ping_cfg));
1153   if (cfg == NULL) {
1154 #ifdef CUSTOM_AT_COMMAND
1155     (void)uapi_at_printf("shell_ping malloc fail"CRLF);
1156 #else
1157     LWIP_PLATFORM_PRINT("shell_ping malloc fail"CRLF);
1158 #endif
1159     return OS_NOK;
1160   }
1161   cfg->count = 0;
1162   cfg->interval = 1000; /* default ping interval */
1163   cfg->timeout = LWIP_SHELL_CMD_PING_TIMEOUT;
1164   cfg->data_len = 48; /* default data length */
1165   cfg->src_type = LWIP_PING_DEFAULT_SOCKET;
1166   cfg->is_v6 = 0;
1167 
1168   if ((argc < 1) || (argv == NULL)) {
1169 #ifdef CUSTOM_AT_COMMAND
1170     (void)uapi_at_printf("Ping: require dest ipaddr at least "CRLF);
1171 #else
1172     LWIP_PLATFORM_PRINT("Ping: require dest ipaddr at least "CRLF);
1173 #endif
1174     goto ping_error;
1175   }
1176   if (ping_cfg_parse(argc, argv, cfg, &ping_kill_flag) == -1) {
1177     goto ping_error;
1178   }
1179 
1180   if (ping_kill_flag == 1) {
1181     u32_t is_v6 = cfg->is_v6;
1182     mem_free(cfg);
1183     if (ping_taskid != LWIP_DEFAULT_PING_TASK_ID) {
1184       ping_kill = 1; /* stop the current ping task */
1185 #ifdef CUSTOM_AT_COMMAND
1186       (void)uapi_at_printf("+PING%s:"CRLF"OK"CRLF, is_v6 ? "6" : "");
1187 #else
1188       LWIP_UNUSED_ARG(is_v6);
1189 #endif
1190       return (int)OS_OK;
1191     } else {
1192       LWIP_PLATFORM_PRINT("No ping task running"CRLF);
1193       return (int)OS_NOK;
1194     }
1195   }
1196 
1197   if(ping_task_running == 1) {
1198     LWIP_PLATFORM_PRINT("Now ping task is running"CRLF);
1199     mem_free(cfg);
1200     return OS_NOK;
1201   }
1202 
1203   return ping_exec(cfg);
1204 ping_error:
1205   lwip_ping_usage(cfg->is_v6);
1206   mem_free(cfg);
1207   return OS_NOK;
1208 }
1209 
1210 #if LWIP_IPV6
os_shell_ping6(int argc,const char ** argv)1211 u32_t os_shell_ping6(int argc, const char **argv)
1212 {
1213     int i;
1214     u32_t ret;
1215     const char **argv6 = mem_malloc(sizeof(char *) * (argc + 1));
1216     if (argv6 == NULL) {
1217 #ifdef CUSTOM_AT_COMMAND
1218       (void)uapi_at_printf("ping6 malloc fail"CRLF);
1219 #else
1220       LWIP_PLATFORM_PRINT("ping6 malloc fail"CRLF);
1221 #endif
1222       return OS_NOK;
1223     }
1224 
1225     argv6[0] = "-6";
1226     for (i = 0; i < argc; i++) {
1227       argv6[i + 1] = argv[i];
1228     }
1229     argc++;
1230     ret = os_shell_ping(argc, argv6);
1231     mem_free(argv6);
1232     return ret;
1233 }
1234 #endif /* LWIP_IPV6 */
1235 
1236 #endif /* LWIP_ENABLE_BASIC_SHELL_CMD */
1237