]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/net/common/v2_0/tests/ping_lo_test.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / net / common / v2_0 / tests / ping_lo_test.c
1 //==========================================================================
2 //
3 //      tests/ping_lo_test.c
4 //
5 //      Simple test of PING (ICMP) and networking support
6 //
7 //==========================================================================
8 //####BSDCOPYRIGHTBEGIN####
9 //
10 // -------------------------------------------
11 //
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.
14 //
15 // -------------------------------------------
16 //
17 //####BSDCOPYRIGHTEND####
18 //==========================================================================
19 //#####DESCRIPTIONBEGIN####
20 //
21 // Author(s):    gthomas, sorin@netappi.com
22 // Contributors: gthomas, sorin@netappi.com, andrew.lunn@ascom.ch
23 // Date:         2000-01-10
24 // Purpose:      
25 // Description:  
26 //              
27 //
28 //####DESCRIPTIONEND####
29 //
30 //==========================================================================
31
32 // PING test code
33
34 #include <network.h>
35 #ifdef CYGPKG_NET_INET6
36 #include <netinet/ip6.h>
37 #include <netinet/icmp6.h>
38 #endif
39
40 #include <cyg/infra/testcase.h>
41
42 #ifndef CYGPKG_LIBC_STDIO
43 #define perror(s) diag_printf(#s ": %s\n", strerror(errno))
44 #endif
45
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;
50
51 #define NUM_PINGS 16
52 #define MAX_PACKET 4096
53 static unsigned char pkt1[MAX_PACKET], pkt2[MAX_PACKET];
54
55 #define UNIQUEID 0x1234
56
57 void
58 pexit(char *s)
59 {
60     CYG_TEST_FAIL_FINISH( s );
61 }
62
63 // Compute INET checksum
64 int
65 inet_cksum(u_short *addr, int len)
66 {
67     register int nleft = len;
68     register u_short *w = addr;
69     register u_short answer;
70     register u_int sum = 0;
71     u_short odd_byte = 0;
72
73     /*
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
77      *  16 bits.
78      */
79     while( nleft > 1 )  {
80         sum += *w++;
81         nleft -= 2;
82     }
83
84     /* mop up an odd byte, if necessary */
85     if( nleft == 1 ) {
86         *(u_char *)(&odd_byte) = *(u_char *)w;
87         sum += odd_byte;
88     }
89
90     /*
91      * add back carry outs from top 16 bits to low 16 bits
92      */
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 */
96     return (answer);
97 }
98
99 static int
100 show_icmp(unsigned char *pkt, int len, 
101           struct sockaddr_in *from, struct sockaddr_in *to)
102 {
103     cyg_tick_count_t *tp, tv;
104     struct ip *ip;
105     struct icmp *icmp;
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);
111         return 0;
112     }
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);
119         return 0;
120     }
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);
124     }
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);
129 }
130
131 static void
132 ping_host(int s, struct sockaddr_in *host)
133 {
134     struct icmp *icmp = (struct icmp *)pkt1;
135     int icmp_len = 64;
136     int seq, ok_recv, bogus_recv;
137     cyg_tick_count_t *tp;
138     long *dp;
139     struct sockaddr_in from;
140     int i, len;
141     socklen_t fromlen;
142
143     ok_recv = 0;
144     bogus_recv = 0;
145     diag_printf("PING server %s\n", inet_ntoa(host->sin_addr));
146     for (seq = 0;  seq < NUM_PINGS;  seq++) {
147         // Build ICMP packet
148         icmp->icmp_type = ICMP_ECHO;
149         icmp->icmp_code = 0;
150         icmp->icmp_cksum = 0;
151         icmp->icmp_seq = seq;
152         icmp->icmp_id = UNIQUEID;
153         // Set up ping data
154         tp = (cyg_tick_count_t *)&icmp->icmp_data;
155         *tp++ = cyg_current_time();
156         dp = (long *)tp;
157         for (i = sizeof(*tp);  i < icmp_len;  i += sizeof(*dp)) {
158             *dp++ = i;
159         }
160         // Add checksum
161         icmp->icmp_cksum = inet_cksum( (u_short *)icmp, icmp_len+8);
162         // Send it off
163         if (sendto(s, icmp, icmp_len+8, 0, (struct sockaddr *)host, sizeof(*host)) < 0) {
164             perror("sendto");
165             continue;
166         }
167         // Wait for a response
168         fromlen = sizeof(from);
169         len = recvfrom(s, pkt2, sizeof(pkt2), 0, (struct sockaddr *)&from, &fromlen);
170         if (len < 0) {
171             perror("recvfrom");
172         } else {
173             if (show_icmp(pkt2, len, &from, host)) {
174                 ok_recv++;
175             } else {
176                 bogus_recv++;
177             }
178         }
179     }
180     diag_printf("Sent %d packets, received %d OK, %d bad\n", NUM_PINGS, ok_recv, bogus_recv);
181 }
182
183 static void
184 ping_test_loopback( int lo )
185 {
186     struct protoent *p;
187     struct timeval tv;
188     struct sockaddr_in host;
189     int s;
190
191     if ((p = getprotobyname("icmp")) == (struct protoent *)0) {
192         perror("getprotobyname");
193         return;
194     }
195     s = socket(AF_INET, SOCK_RAW, p->p_proto);
196     if (s < 0) {
197         perror("socket");
198         return;
199     }
200     tv.tv_sec = 1;
201     tv.tv_usec = 0;
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));
207     host.sin_port = 0;
208     ping_host(s, &host);
209     // Now try a bogus host
210     host.sin_addr.s_addr = htonl(ntohl(host.sin_addr.s_addr) + 32);
211     ping_host(s, &host);
212 }
213
214 #ifdef CYGPKG_NET_INET6
215 static int
216 show6_icmp(unsigned char *pkt, int len, 
217           const struct sockaddr_in6 *from, const struct sockaddr_in6 *to)
218 {
219     cyg_tick_count_t *tp, tv;
220     struct icmp6_hdr *icmp;
221     char fromnamebuf[128];
222     char tonamebuf[128];
223     int error;
224
225     error = getnameinfo((struct sockaddr *)from,sizeof(*from), 
226                         fromnamebuf, sizeof(fromnamebuf), 
227                         NULL, 0,
228                         NI_NUMERICHOST);
229     if (error) {
230       perror ("getnameinfo(from)");
231       return 0;
232     }
233
234     error = getnameinfo((struct sockaddr *)to,sizeof(*to), 
235                         tonamebuf, sizeof(tonamebuf), 
236                         NULL, 0,
237                         NI_NUMERICHOST);
238     if (error) {
239       perror ("getnameinfo(to)");
240       return 0;
241     }
242
243     tv = cyg_current_time();
244     icmp = (struct icmp6_hdr *)pkt;
245     tp = (cyg_tick_count_t *)&icmp->icmp6_data8[4];
246    
247     if (icmp->icmp6_type != ICMP6_ECHO_REPLY) {
248         return 0;
249     }
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);
253     }
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)));
258 }
259
260 static void
261 ping6_host(int s, const struct sockaddr_in6 *host)
262 {
263     struct icmp6_hdr *icmp = (struct icmp6_hdr *)pkt1;
264     int icmp_len = 64;
265     int seq, ok_recv, bogus_recv;
266     cyg_tick_count_t *tp;
267     long *dp;
268     struct sockaddr_in6 from;
269     int i, len, fromlen;
270     char namebuf[128];
271     int error;
272     int echo_responce;
273
274     ok_recv = 0;
275     bogus_recv = 0;
276     error = getnameinfo((struct sockaddr *)host,sizeof(*host), 
277                         namebuf, sizeof(namebuf), 
278                         NULL, 0,
279                         NI_NUMERICHOST);
280     if (error) {
281       perror ("getnameinfo");
282     } else {
283       diag_printf("PING6 server %s\n", namebuf);
284     }
285     for (seq = 0;  seq < NUM_PINGS;  seq++) {
286         // Build ICMP packet
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;
292
293         // Set up ping data
294         tp = (cyg_tick_count_t *)&icmp->icmp6_data8[4];
295         *tp++ = cyg_current_time();
296         dp = (long *)tp;
297         for (i = sizeof(*tp);  i < icmp_len;  i += sizeof(*dp)) {
298             *dp++ = i;
299         }
300         // Add checksum
301         icmp->icmp6_cksum = inet_cksum( (u_short *)icmp, icmp_len+8);
302         // Send it off
303         if (sendto(s, icmp, icmp_len+8, 0, (struct sockaddr *)host, sizeof(*host)) < 0) {
304             perror("sendto");
305             continue;
306         }
307         // Wait for a response. We get our own ECHO_REQUEST and the responce
308         echo_responce = 0;
309         while (!echo_responce) {
310           fromlen = sizeof(from);
311           len = recvfrom(s, pkt2, sizeof(pkt2), 0, (struct sockaddr *)&from, &fromlen);
312           if (len < 0) {
313             perror("recvfrom");
314             echo_responce=1;
315           } else {
316             if (show6_icmp(pkt2, len, &from, host)) {
317               ok_recv++;
318               echo_responce=1;
319             }
320           }
321         }
322     }
323     diag_printf("Sent %d packets, received %d OK, %d bad\n", NUM_PINGS, ok_recv, bogus_recv);
324 }
325
326 static void
327 ping6_test_loopback( int lo )
328 {
329     struct protoent *p;
330     struct timeval tv;
331     struct sockaddr_in6 host;
332     int s;
333
334     if ((p = getprotobyname("ipv6-icmp")) == (struct protoent *)0) {
335         perror("getprotobyname");
336         return;
337     }
338     s = socket(AF_INET6, SOCK_RAW, p->p_proto);
339     if (s < 0) {
340         perror("socket");
341         return;
342     }
343     tv.tv_sec = 1;
344     tv.tv_usec = 0;
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;
350     host.sin6_port = 0;
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);
355 }
356 #endif
357
358 void
359 net_test(cyg_addrword_t p)
360 {
361     int i;
362     diag_printf("Start PING test\n");
363
364     init_all_network_interfaces();
365 #if NLOOP > 0
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 );
373 #endif
374     CYG_TEST_PASS_FINISH( "Done pinging loopback" );
375 #endif
376     CYG_TEST_NA( "No loopback devs" );
377 }
378
379 void
380 cyg_start(void)
381 {
382     CYG_TEST_INIT();
383
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
386                       net_test,                 // entry
387                       0,                        // entry parameter
388                       "Loopback ping  test",    // Name
389                       &stack[0],                // Stack
390                       STACK_SIZE,               // Size
391                       &thread_handle,           // Handle
392                       &thread_data              // Thread data structure
393             );
394     cyg_thread_resume(thread_handle);           // Start it
395     cyg_scheduler_start();
396 }