xref: /nrf52832-nimble/rt-thread/components/net/lwip-2.1.0/src/apps/ping/ping.c (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /*
2*10465441SEvalZero  * netutils: ping implementation
3*10465441SEvalZero  */
4*10465441SEvalZero 
5*10465441SEvalZero #include "lwip/opt.h"
6*10465441SEvalZero 
7*10465441SEvalZero #include "lwip/mem.h"
8*10465441SEvalZero #include "lwip/icmp.h"
9*10465441SEvalZero #include "lwip/netif.h"
10*10465441SEvalZero #include "lwip/sys.h"
11*10465441SEvalZero #include "lwip/sockets.h"
12*10465441SEvalZero #include "lwip/inet.h"
13*10465441SEvalZero #include "lwip/inet_chksum.h"
14*10465441SEvalZero #include "lwip/ip.h"
15*10465441SEvalZero 
16*10465441SEvalZero /**
17*10465441SEvalZero  * PING_DEBUG: Enable debugging for PING.
18*10465441SEvalZero  */
19*10465441SEvalZero #ifndef PING_DEBUG
20*10465441SEvalZero #define PING_DEBUG     LWIP_DBG_ON
21*10465441SEvalZero #endif
22*10465441SEvalZero 
23*10465441SEvalZero /** ping receive timeout - in milliseconds */
24*10465441SEvalZero #define PING_RCV_TIMEO rt_tick_from_millisecond(2000)
25*10465441SEvalZero /** ping delay - in milliseconds */
26*10465441SEvalZero #define PING_DELAY     rt_tick_from_millisecond(1000)
27*10465441SEvalZero 
28*10465441SEvalZero /** ping identifier - must fit on a u16_t */
29*10465441SEvalZero #ifndef PING_ID
30*10465441SEvalZero #define PING_ID        0xAFAF
31*10465441SEvalZero #endif
32*10465441SEvalZero 
33*10465441SEvalZero /** ping additional data size to include in the packet */
34*10465441SEvalZero #ifndef PING_DATA_SIZE
35*10465441SEvalZero #define PING_DATA_SIZE 32
36*10465441SEvalZero #endif
37*10465441SEvalZero 
38*10465441SEvalZero /* ping variables */
39*10465441SEvalZero static u16_t ping_seq_num;
40*10465441SEvalZero struct _ip_addr
41*10465441SEvalZero {
42*10465441SEvalZero     rt_uint8_t addr0, addr1, addr2, addr3;
43*10465441SEvalZero };
44*10465441SEvalZero 
45*10465441SEvalZero /** Prepare a echo ICMP request */
ping_prepare_echo(struct icmp_echo_hdr * iecho,u16_t len)46*10465441SEvalZero static void ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len)
47*10465441SEvalZero {
48*10465441SEvalZero     size_t i;
49*10465441SEvalZero     size_t data_len = len - sizeof(struct icmp_echo_hdr);
50*10465441SEvalZero 
51*10465441SEvalZero     ICMPH_TYPE_SET(iecho, ICMP_ECHO);
52*10465441SEvalZero     ICMPH_CODE_SET(iecho, 0);
53*10465441SEvalZero     iecho->chksum = 0;
54*10465441SEvalZero     iecho->id     = PING_ID;
55*10465441SEvalZero     iecho->seqno  = htons(++ping_seq_num);
56*10465441SEvalZero 
57*10465441SEvalZero     /* fill the additional data buffer with some data */
58*10465441SEvalZero     for(i = 0; i < data_len; i++)
59*10465441SEvalZero     {
60*10465441SEvalZero         ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i;
61*10465441SEvalZero     }
62*10465441SEvalZero 
63*10465441SEvalZero     iecho->chksum = inet_chksum(iecho, len);
64*10465441SEvalZero }
65*10465441SEvalZero 
66*10465441SEvalZero /* Ping using the socket ip */
ping_send(int s,ip_addr_t * addr,int size)67*10465441SEvalZero static err_t ping_send(int s, ip_addr_t *addr, int size)
68*10465441SEvalZero {
69*10465441SEvalZero     int err;
70*10465441SEvalZero     struct icmp_echo_hdr *iecho;
71*10465441SEvalZero     struct sockaddr_in to;
72*10465441SEvalZero     size_t ping_size = sizeof(struct icmp_echo_hdr) + size;
73*10465441SEvalZero     LWIP_ASSERT("ping_size is too big", ping_size <= 0xffff);
74*10465441SEvalZero 
75*10465441SEvalZero     iecho = rt_malloc(ping_size);
76*10465441SEvalZero     if (iecho == RT_NULL)
77*10465441SEvalZero     {
78*10465441SEvalZero         return ERR_MEM;
79*10465441SEvalZero     }
80*10465441SEvalZero 
81*10465441SEvalZero     ping_prepare_echo(iecho, (u16_t)ping_size);
82*10465441SEvalZero 
83*10465441SEvalZero     to.sin_len = sizeof(to);
84*10465441SEvalZero     to.sin_family = AF_INET;
85*10465441SEvalZero     to.sin_addr.s_addr = addr->addr;
86*10465441SEvalZero 
87*10465441SEvalZero     err = lwip_sendto(s, iecho, ping_size, 0, (struct sockaddr*)&to, sizeof(to));
88*10465441SEvalZero     rt_free(iecho);
89*10465441SEvalZero 
90*10465441SEvalZero     return (err == ping_size ? ERR_OK : ERR_VAL);
91*10465441SEvalZero }
92*10465441SEvalZero 
ping_recv(int s,int * ttl)93*10465441SEvalZero static int ping_recv(int s, int *ttl)
94*10465441SEvalZero {
95*10465441SEvalZero     char buf[64];
96*10465441SEvalZero     int fromlen = sizeof(struct sockaddr_in), len;
97*10465441SEvalZero     struct sockaddr_in from;
98*10465441SEvalZero     struct ip_hdr *iphdr;
99*10465441SEvalZero     struct icmp_echo_hdr *iecho;
100*10465441SEvalZero 
101*10465441SEvalZero     while((len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr*)&from, (socklen_t*)&fromlen)) > 0)
102*10465441SEvalZero     {
103*10465441SEvalZero         if (len >= (sizeof(struct ip_hdr)+sizeof(struct icmp_echo_hdr)))
104*10465441SEvalZero         {
105*10465441SEvalZero             iphdr = (struct ip_hdr *)buf;
106*10465441SEvalZero             iecho = (struct icmp_echo_hdr *)(buf+(IPH_HL(iphdr) * 4));
107*10465441SEvalZero             if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num)))
108*10465441SEvalZero             {
109*10465441SEvalZero                 *ttl = iphdr->_ttl;
110*10465441SEvalZero                 return len;
111*10465441SEvalZero             }
112*10465441SEvalZero         }
113*10465441SEvalZero     }
114*10465441SEvalZero 
115*10465441SEvalZero     return len;
116*10465441SEvalZero }
117*10465441SEvalZero 
ping(char * target,rt_uint32_t times,rt_size_t size)118*10465441SEvalZero rt_err_t ping(char* target, rt_uint32_t times, rt_size_t size)
119*10465441SEvalZero {
120*10465441SEvalZero     int s, ttl, recv_len;
121*10465441SEvalZero     struct timeval timeout = { PING_RCV_TIMEO / RT_TICK_PER_SECOND, PING_RCV_TIMEO % RT_TICK_PER_SECOND };
122*10465441SEvalZero     ip_addr_t ping_target;
123*10465441SEvalZero     rt_uint32_t send_times;
124*10465441SEvalZero     rt_tick_t recv_start_tick;
125*10465441SEvalZero     struct _ip_addr
126*10465441SEvalZero     {
127*10465441SEvalZero         rt_uint8_t addr0, addr1, addr2, addr3;
128*10465441SEvalZero     } *addr;
129*10465441SEvalZero 
130*10465441SEvalZero     send_times = 0;
131*10465441SEvalZero     ping_seq_num = 0;
132*10465441SEvalZero 
133*10465441SEvalZero     if(size == 0)
134*10465441SEvalZero         size = PING_DATA_SIZE;
135*10465441SEvalZero 
136*10465441SEvalZero     if (inet_aton(target, &ping_target) == 0)
137*10465441SEvalZero     {
138*10465441SEvalZero         rt_kprintf("ping: unknown host %s\n", target);
139*10465441SEvalZero         return -RT_ERROR;
140*10465441SEvalZero     }
141*10465441SEvalZero     addr = (struct _ip_addr*)&ping_target;
142*10465441SEvalZero 
143*10465441SEvalZero     if ((s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP)) < 0)
144*10465441SEvalZero     {
145*10465441SEvalZero         rt_kprintf("ping: create socket failled\n");
146*10465441SEvalZero         return -RT_ERROR;
147*10465441SEvalZero     }
148*10465441SEvalZero 
149*10465441SEvalZero     lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval));
150*10465441SEvalZero 
151*10465441SEvalZero     while (1)
152*10465441SEvalZero     {
153*10465441SEvalZero         if (ping_send(s, &ping_target, size) == ERR_OK)
154*10465441SEvalZero         {
155*10465441SEvalZero             recv_start_tick = rt_tick_get();
156*10465441SEvalZero             if ((recv_len = ping_recv(s, &ttl)) >= 0)
157*10465441SEvalZero             {
158*10465441SEvalZero                 rt_kprintf("%d bytes from %d.%d.%d.%d icmp_seq=%d ttl=%d time=%d ticks\n", recv_len, addr->addr0,
159*10465441SEvalZero                         addr->addr1, addr->addr2, addr->addr3, send_times, ttl, rt_tick_get() - recv_start_tick);
160*10465441SEvalZero             }
161*10465441SEvalZero             else
162*10465441SEvalZero             {
163*10465441SEvalZero                 rt_kprintf("From %d.%d.%d.%d icmp_seq=%d timeout\n", addr->addr0, addr->addr1, addr->addr2,
164*10465441SEvalZero                         addr->addr3, send_times);
165*10465441SEvalZero             }
166*10465441SEvalZero         }
167*10465441SEvalZero         else
168*10465441SEvalZero         {
169*10465441SEvalZero             rt_kprintf("Send %d.%d.%d.%d - error\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3);
170*10465441SEvalZero         }
171*10465441SEvalZero 
172*10465441SEvalZero         send_times ++;
173*10465441SEvalZero         if (send_times >= times) break; /* send ping times reached, stop */
174*10465441SEvalZero 
175*10465441SEvalZero         rt_thread_delay(PING_DELAY); /* take a delay */
176*10465441SEvalZero     }
177*10465441SEvalZero 
178*10465441SEvalZero     lwip_close(s);
179*10465441SEvalZero 
180*10465441SEvalZero     return RT_EOK;
181*10465441SEvalZero }
182*10465441SEvalZero #ifdef RT_USING_FINSH
183*10465441SEvalZero #include <finsh.h>
184*10465441SEvalZero 
185*10465441SEvalZero FINSH_FUNCTION_EXPORT(ping, ping network host);
186*10465441SEvalZero 
cmd_ping(int argc,char ** argv)187*10465441SEvalZero int cmd_ping(int argc, char **argv)
188*10465441SEvalZero {
189*10465441SEvalZero     if (argc == 1)
190*10465441SEvalZero     {
191*10465441SEvalZero         rt_kprintf("Please input: ping <host address>\n");
192*10465441SEvalZero     }
193*10465441SEvalZero     else
194*10465441SEvalZero     {
195*10465441SEvalZero         ping(argv[1], 4, 0);
196*10465441SEvalZero     }
197*10465441SEvalZero 
198*10465441SEvalZero     return 0;
199*10465441SEvalZero }
200*10465441SEvalZero FINSH_FUNCTION_EXPORT_ALIAS(cmd_ping, __cmd_ping, ping network host);
201*10465441SEvalZero #endif
202