1 //==========================================================================
3 // tests/ping_lo_test.c
5 // Simple test of PING (ICMP) and networking support
7 //==========================================================================
8 //####BSDCOPYRIGHTBEGIN####
10 // -------------------------------------------
12 // Portions of this software may have been derived from OpenBSD or other sources,
13 // and are covered by the appropriate copyright disclaimers included herein.
15 // -------------------------------------------
17 //####BSDCOPYRIGHTEND####
18 //==========================================================================
19 //#####DESCRIPTIONBEGIN####
21 // Author(s): gthomas, sorin@netappi.com
22 // Contributors: gthomas, sorin@netappi.com, andrew.lunn@ascom.ch
28 //####DESCRIPTIONEND####
30 //==========================================================================
35 #ifdef CYGPKG_NET_INET6
36 #include <netinet/ip6.h>
37 #include <netinet/icmp6.h>
40 #include <cyg/infra/testcase.h>
42 #ifndef CYGPKG_LIBC_STDIO
43 #define perror(s) diag_printf(#s ": %s\n", strerror(errno))
46 #define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
47 static char stack[STACK_SIZE];
48 static cyg_thread thread_data;
49 static cyg_handle_t thread_handle;
52 #define MAX_PACKET 4096
53 static unsigned char pkt1[MAX_PACKET], pkt2[MAX_PACKET];
55 #define UNIQUEID 0x1234
60 CYG_TEST_FAIL_FINISH( s );
63 // Compute INET checksum
65 inet_cksum(u_short *addr, int len)
67 register int nleft = len;
68 register u_short *w = addr;
69 register u_short answer;
70 register u_int sum = 0;
74 * Our algorithm is simple, using a 32 bit accumulator (sum),
75 * we add sequential 16 bit words to it, and at the end, fold
76 * back all the carry bits from the top 16 bits into the lower
84 /* mop up an odd byte, if necessary */
86 *(u_char *)(&odd_byte) = *(u_char *)w;
91 * add back carry outs from top 16 bits to low 16 bits
93 sum = (sum >> 16) + (sum & 0x0000ffff); /* add hi 16 to low 16 */
94 sum += (sum >> 16); /* add carry */
95 answer = ~sum; /* truncate to 16 bits */
100 show_icmp(unsigned char *pkt, int len,
101 struct sockaddr_in *from, struct sockaddr_in *to)
103 cyg_tick_count_t *tp, tv;
106 tv = cyg_current_time();
107 ip = (struct ip *)pkt;
108 if ((len < sizeof(*ip)) || ip->ip_v != IPVERSION) {
109 diag_printf("%s: Short packet or not IP! - Len: %d, Version: %d\n",
110 inet_ntoa(from->sin_addr), len, ip->ip_v);
113 icmp = (struct icmp *)(pkt + sizeof(*ip));
114 len -= (sizeof(*ip) + 8);
115 tp = (cyg_tick_count_t *)&icmp->icmp_data;
116 if (icmp->icmp_type != ICMP_ECHOREPLY) {
117 diag_printf("%s: Invalid ICMP - type: %d\n",
118 inet_ntoa(from->sin_addr), icmp->icmp_type);
121 if (icmp->icmp_id != UNIQUEID) {
122 diag_printf("%s: ICMP received for wrong id - sent: %x, recvd: %x\n",
123 inet_ntoa(from->sin_addr), UNIQUEID, icmp->icmp_id);
125 diag_printf("%d bytes from %s: ", len, inet_ntoa(from->sin_addr));
126 diag_printf("icmp_seq=%d", icmp->icmp_seq);
127 diag_printf(", time=%dms\n", (int)(tv - *tp)*10);
128 return (from->sin_addr.s_addr == to->sin_addr.s_addr);
132 ping_host(int s, struct sockaddr_in *host)
134 struct icmp *icmp = (struct icmp *)pkt1;
136 int seq, ok_recv, bogus_recv;
137 cyg_tick_count_t *tp;
139 struct sockaddr_in from;
145 diag_printf("PING server %s\n", inet_ntoa(host->sin_addr));
146 for (seq = 0; seq < NUM_PINGS; seq++) {
148 icmp->icmp_type = ICMP_ECHO;
150 icmp->icmp_cksum = 0;
151 icmp->icmp_seq = seq;
152 icmp->icmp_id = UNIQUEID;
154 tp = (cyg_tick_count_t *)&icmp->icmp_data;
155 *tp++ = cyg_current_time();
157 for (i = sizeof(*tp); i < icmp_len; i += sizeof(*dp)) {
161 icmp->icmp_cksum = inet_cksum( (u_short *)icmp, icmp_len+8);
163 if (sendto(s, icmp, icmp_len+8, 0, (struct sockaddr *)host, sizeof(*host)) < 0) {
167 // Wait for a response
168 fromlen = sizeof(from);
169 len = recvfrom(s, pkt2, sizeof(pkt2), 0, (struct sockaddr *)&from, &fromlen);
173 if (show_icmp(pkt2, len, &from, host)) {
180 diag_printf("Sent %d packets, received %d OK, %d bad\n", NUM_PINGS, ok_recv, bogus_recv);
184 ping_test_loopback( int lo )
188 struct sockaddr_in host;
191 if ((p = getprotobyname("icmp")) == (struct protoent *)0) {
192 perror("getprotobyname");
195 s = socket(AF_INET, SOCK_RAW, p->p_proto);
202 setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
203 // Set up host address
204 host.sin_family = AF_INET;
205 host.sin_len = sizeof(host);
206 host.sin_addr.s_addr = htonl(INADDR_LOOPBACK + (0x100 * lo));
209 // Now try a bogus host
210 host.sin_addr.s_addr = htonl(ntohl(host.sin_addr.s_addr) + 32);
214 #ifdef CYGPKG_NET_INET6
216 show6_icmp(unsigned char *pkt, int len,
217 const struct sockaddr_in6 *from, const struct sockaddr_in6 *to)
219 cyg_tick_count_t *tp, tv;
220 struct icmp6_hdr *icmp;
221 char fromnamebuf[128];
225 error = getnameinfo((struct sockaddr *)from,sizeof(*from),
226 fromnamebuf, sizeof(fromnamebuf),
230 perror ("getnameinfo(from)");
234 error = getnameinfo((struct sockaddr *)to,sizeof(*to),
235 tonamebuf, sizeof(tonamebuf),
239 perror ("getnameinfo(to)");
243 tv = cyg_current_time();
244 icmp = (struct icmp6_hdr *)pkt;
245 tp = (cyg_tick_count_t *)&icmp->icmp6_data8[4];
247 if (icmp->icmp6_type != ICMP6_ECHO_REPLY) {
250 if (icmp->icmp6_id != UNIQUEID) {
251 diag_printf("%s: ICMP received for wrong id - sent: %x, recvd: %x\n",
252 fromnamebuf, UNIQUEID, icmp->icmp6_id);
254 diag_printf("%d bytes from %s: ", len, fromnamebuf);
255 diag_printf("icmp_seq=%d", icmp->icmp6_seq);
256 diag_printf(", time=%dms\n", (int)(tv - *tp)*10);
257 return (!memcmp(&from->sin6_addr, &to->sin6_addr,sizeof(from->sin6_addr)));
261 ping6_host(int s, const struct sockaddr_in6 *host)
263 struct icmp6_hdr *icmp = (struct icmp6_hdr *)pkt1;
265 int seq, ok_recv, bogus_recv;
266 cyg_tick_count_t *tp;
268 struct sockaddr_in6 from;
276 error = getnameinfo((struct sockaddr *)host,sizeof(*host),
277 namebuf, sizeof(namebuf),
281 perror ("getnameinfo");
283 diag_printf("PING6 server %s\n", namebuf);
285 for (seq = 0; seq < NUM_PINGS; seq++) {
287 icmp->icmp6_type = ICMP6_ECHO_REQUEST;
288 icmp->icmp6_code = 0;
289 icmp->icmp6_cksum = 0;
290 icmp->icmp6_seq = seq;
291 icmp->icmp6_id = UNIQUEID;
294 tp = (cyg_tick_count_t *)&icmp->icmp6_data8[4];
295 *tp++ = cyg_current_time();
297 for (i = sizeof(*tp); i < icmp_len; i += sizeof(*dp)) {
301 icmp->icmp6_cksum = inet_cksum( (u_short *)icmp, icmp_len+8);
303 if (sendto(s, icmp, icmp_len+8, 0, (struct sockaddr *)host, sizeof(*host)) < 0) {
307 // Wait for a response. We get our own ECHO_REQUEST and the responce
309 while (!echo_responce) {
310 fromlen = sizeof(from);
311 len = recvfrom(s, pkt2, sizeof(pkt2), 0, (struct sockaddr *)&from, &fromlen);
316 if (show6_icmp(pkt2, len, &from, host)) {
323 diag_printf("Sent %d packets, received %d OK, %d bad\n", NUM_PINGS, ok_recv, bogus_recv);
327 ping6_test_loopback( int lo )
331 struct sockaddr_in6 host;
334 if ((p = getprotobyname("ipv6-icmp")) == (struct protoent *)0) {
335 perror("getprotobyname");
338 s = socket(AF_INET6, SOCK_RAW, p->p_proto);
345 setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
346 // Set up host address
347 host.sin6_family = AF_INET6;
348 host.sin6_len = sizeof(host);
349 host.sin6_addr = in6addr_loopback;
351 ping6_host(s, &host);
352 // Now try a bogus host
353 host.sin6_addr.s6_addr[15] = host.sin6_addr.s6_addr[15] + 32;
354 ping6_host(s, &host);
359 net_test(cyg_addrword_t p)
362 diag_printf("Start PING test\n");
364 init_all_network_interfaces();
366 for ( i = 0; i < NLOOP; i++ )
367 ping_test_loopback( i );
368 for ( i = 0; i < NLOOP; i++ )
369 ping_test_loopback( i );
370 #ifdef CYGPKG_NET_INET6
371 for ( i = 0; i < NLOOP; i++ )
372 ping6_test_loopback( i );
374 CYG_TEST_PASS_FINISH( "Done pinging loopback" );
376 CYG_TEST_NA( "No loopback devs" );
384 // Create a main thread, so we can run the scheduler and have time 'pass'
385 cyg_thread_create(CYGPKG_NET_THREAD_PRIORITY-4,// Priority - just a number
387 0, // entry parameter
388 "Loopback ping test", // Name
391 &thread_handle, // Handle
392 &thread_data // Thread data structure
394 cyg_thread_resume(thread_handle); // Start it
395 cyg_scheduler_start();