]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/net/common/v2_0/tests/ping_test.c
ea1060cc69299bbe4380ea5b6e1570683bec67a7
[karo-tx-redboot.git] / packages / net / common / v2_0 / tests / ping_test.c
1 //==========================================================================
2 //
3 //      tests/ping_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
22 // Contributors: gthomas, 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 <pkgconf/system.h>
41 #include <pkgconf/net.h>
42
43 #include <cyg/infra/testcase.h>
44
45 #ifdef CYGBLD_DEVS_ETH_DEVICE_H    // Get the device config if it exists
46 #include CYGBLD_DEVS_ETH_DEVICE_H  // May provide CYGTST_DEVS_ETH_TEST_NET_REALTIME
47 #endif
48
49 #ifdef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS // do we use the rt test?
50 # ifdef CYGTST_DEVS_ETH_TEST_NET_REALTIME // Get the test ancilla if it exists
51 #  include CYGTST_DEVS_ETH_TEST_NET_REALTIME
52 # endif
53 #endif
54
55 // Fill in the blanks if necessary
56 #ifndef TNR_OFF
57 # define TNR_OFF()
58 #endif
59 #ifndef TNR_ON
60 # define TNR_ON()
61 #endif
62 #ifndef TNR_INIT
63 # define TNR_INIT()
64 #endif
65 #ifndef TNR_PRINT_ACTIVITY
66 # define TNR_PRINT_ACTIVITY()
67 #endif
68
69
70
71 #ifndef CYGPKG_LIBC_STDIO
72 #define perror(s) diag_printf(#s ": %s\n", strerror(errno))
73 #endif
74
75 #define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
76 static char stack[STACK_SIZE];
77 static cyg_thread thread_data;
78 static cyg_handle_t thread_handle;
79
80 #define NUM_PINGS 16
81 #define MAX_PACKET 4096
82 #define MIN_PACKET   64
83 #define MAX_SEND   4000
84
85 #define PACKET_ADD  ((MAX_SEND - MIN_PACKET)/NUM_PINGS)
86 #define nPACKET_ADD  1 
87
88 static unsigned char pkt1[MAX_PACKET], pkt2[MAX_PACKET];
89
90 #define UNIQUEID 0x1234
91
92 void
93 pexit(char *s)
94 {
95     CYG_TEST_FAIL_FINISH(s);
96 }
97
98 // Compute INET checksum
99 int
100 inet_cksum(u_short *addr, int len)
101 {
102     register int nleft = len;
103     register u_short *w = addr;
104     register u_short answer;
105     register u_int sum = 0;
106     u_short odd_byte = 0;
107
108     /*
109      *  Our algorithm is simple, using a 32 bit accumulator (sum),
110      *  we add sequential 16 bit words to it, and at the end, fold
111      *  back all the carry bits from the top 16 bits into the lower
112      *  16 bits.
113      */
114     while( nleft > 1 )  {
115         sum += *w++;
116         nleft -= 2;
117     }
118
119     /* mop up an odd byte, if necessary */
120     if( nleft == 1 ) {
121         *(u_char *)(&odd_byte) = *(u_char *)w;
122         sum += odd_byte;
123     }
124
125     /*
126      * add back carry outs from top 16 bits to low 16 bits
127      */
128     sum = (sum >> 16) + (sum & 0x0000ffff); /* add hi 16 to low 16 */
129     sum += (sum >> 16);                     /* add carry */
130     answer = ~sum;                          /* truncate to 16 bits */
131     return (answer);
132 }
133
134 static int
135 show_icmp(unsigned char *pkt, int len, 
136           struct sockaddr_in *from, struct sockaddr_in *to)
137 {
138     cyg_tick_count_t *tp, tv;
139     struct ip *ip;
140     struct icmp *icmp;
141     tv = cyg_current_time();
142     ip = (struct ip *)pkt;
143     if ((len < sizeof(*ip)) || ip->ip_v != IPVERSION) {
144         diag_printf("%s: Short packet or not IP! - Len: %d, Version: %d\n", 
145                     inet_ntoa(from->sin_addr), len, ip->ip_v);
146         return 0;
147     }
148     icmp = (struct icmp *)(pkt + sizeof(*ip));
149     len -= (sizeof(*ip) + 8);
150     tp = (cyg_tick_count_t *)&icmp->icmp_data;
151     if (icmp->icmp_type != ICMP_ECHOREPLY) {
152         diag_printf("%s: Invalid ICMP - type: %d\n", 
153                     inet_ntoa(from->sin_addr), icmp->icmp_type);
154         return 0;
155     }
156     if (icmp->icmp_id != UNIQUEID) {
157         diag_printf("%s: ICMP received for wrong id - sent: %x, recvd: %x\n", 
158                     inet_ntoa(from->sin_addr), UNIQUEID, icmp->icmp_id);
159     }
160     diag_printf("%d bytes from %s: ", len, inet_ntoa(from->sin_addr));
161     diag_printf("icmp_seq=%d", icmp->icmp_seq);
162     diag_printf(", time=%dms\n", (int)(tv - *tp)*10);
163     return (from->sin_addr.s_addr == to->sin_addr.s_addr);
164 }
165
166 static void
167 ping_host(int s, struct sockaddr_in *host)
168 {
169     struct icmp *icmp = (struct icmp *)pkt1;
170     int icmp_len = MIN_PACKET;
171     int seq, ok_recv, bogus_recv;
172     cyg_tick_count_t *tp;
173     long *dp;
174     struct sockaddr_in from;
175     int i, len, fromlen;
176
177     ok_recv = 0;
178     bogus_recv = 0;
179     diag_printf("PING server %s\n", inet_ntoa(host->sin_addr));
180     for (seq = 0;  seq < NUM_PINGS;  seq++, icmp_len += PACKET_ADD ) {
181         TNR_ON();
182         // Build ICMP packet
183         icmp->icmp_type = ICMP_ECHO;
184         icmp->icmp_code = 0;
185         icmp->icmp_cksum = 0;
186         icmp->icmp_seq = seq;
187         icmp->icmp_id = 0x1234;
188         // Set up ping data
189         tp = (cyg_tick_count_t *)&icmp->icmp_data;
190         *tp++ = cyg_current_time();
191         dp = (long *)tp;
192         for (i = sizeof(*tp);  i < icmp_len;  i += sizeof(*dp)) {
193             *dp++ = i;
194         }
195         // Add checksum
196         icmp->icmp_cksum = inet_cksum( (u_short *)icmp, icmp_len+8);
197         // Send it off
198         if (sendto(s, icmp, icmp_len+8, 0, (struct sockaddr *)host, sizeof(*host)) < 0) {
199             TNR_OFF();
200             perror("sendto");
201             continue;
202         }
203         // Wait for a response
204         fromlen = sizeof(from);
205         len = recvfrom(s, pkt2, sizeof(pkt2), 0, (struct sockaddr *)&from, &fromlen);
206         TNR_OFF();
207         if (len < 0) {
208             perror("recvfrom");
209             icmp_len = MIN_PACKET - PACKET_ADD; // just in case - long routes
210         } else {
211             if (show_icmp(pkt2, len, &from, host)) {
212                 ok_recv++;
213             } else {
214                 bogus_recv++;
215             }
216         }
217     }
218     TNR_OFF();
219     diag_printf("Sent %d packets, received %d OK, %d bad\n", NUM_PINGS, ok_recv, bogus_recv);
220 }
221
222 #ifdef CYGPKG_NET_INET6
223 static int
224 show6_icmp(unsigned char *pkt, int len, 
225           const struct sockaddr_in6 *from, const struct sockaddr_in6 *to)
226 {
227     cyg_tick_count_t *tp, tv;
228     struct icmp6_hdr *icmp;
229     char fromnamebuf[128];
230     char tonamebuf[128];
231     int error;
232
233     error = getnameinfo((struct sockaddr *)from,sizeof(*from), 
234                         fromnamebuf, sizeof(fromnamebuf), 
235                         NULL, 0,
236                         NI_NUMERICHOST);
237     if (error) {
238       perror ("getnameinfo(from)");
239       return 0;
240     }
241
242     error = getnameinfo((struct sockaddr *)to,sizeof(*to), 
243                         tonamebuf, sizeof(tonamebuf), 
244                         NULL, 0,
245                         NI_NUMERICHOST);
246     if (error) {
247       perror ("getnameinfo(to)");
248       return 0;
249     }
250
251     tv = cyg_current_time();
252     icmp = (struct icmp6_hdr *)pkt;
253     tp = (cyg_tick_count_t *)&icmp->icmp6_data8[4];
254    
255     if (icmp->icmp6_type != ICMP6_ECHO_REPLY) {
256         return 0;
257     }
258     if (icmp->icmp6_id != UNIQUEID) {
259         diag_printf("%s: ICMP received for wrong id - sent: %x, recvd: %x\n", 
260                     fromnamebuf, UNIQUEID, icmp->icmp6_id);
261     }
262     diag_printf("%d bytes from %s: ", len, fromnamebuf);
263     diag_printf("icmp_seq=%d", icmp->icmp6_seq);
264     diag_printf(", time=%dms\n", (int)(tv - *tp)*10);
265     return (!memcmp(&from->sin6_addr, &to->sin6_addr,sizeof(from->sin6_addr)));
266 }
267
268 static void
269 ping6_host(int s, const struct sockaddr_in6 *host)
270 {
271     struct icmp6_hdr *icmp = (struct icmp6_hdr *)pkt1;
272     int icmp_len = 64;
273     int seq, ok_recv, bogus_recv;
274     cyg_tick_count_t *tp;
275     long *dp;
276     struct sockaddr_in6 from;
277     int i, len, fromlen;
278     char namebuf[128];
279     int error;
280     int echo_responce;
281
282     ok_recv = 0;
283     bogus_recv = 0;
284     error = getnameinfo((struct sockaddr *)host,sizeof(*host), 
285                         namebuf, sizeof(namebuf), 
286                         NULL, 0,
287                         NI_NUMERICHOST);
288     if (error) {
289       perror ("getnameinfo");
290     } else {
291       diag_printf("PING6 server %s\n", namebuf);
292     }
293     for (seq = 0;  seq < NUM_PINGS;  seq++) {
294         // Build ICMP packet
295         icmp->icmp6_type = ICMP6_ECHO_REQUEST;
296         icmp->icmp6_code = 0;
297         icmp->icmp6_cksum = 0;
298         icmp->icmp6_seq = seq;
299         icmp->icmp6_id = UNIQUEID;
300
301         // Set up ping data
302         tp = (cyg_tick_count_t *)&icmp->icmp6_data8[4];
303         *tp++ = cyg_current_time();
304         dp = (long *)tp;
305         for (i = sizeof(*tp);  i < icmp_len;  i += sizeof(*dp)) {
306             *dp++ = i;
307         }
308         // Add checksum
309         icmp->icmp6_cksum = inet_cksum( (u_short *)icmp, icmp_len+8);
310         // Send it off
311         if (sendto(s, icmp, icmp_len+8, 0, (struct sockaddr *)host, 
312                    sizeof(*host)) < 0) {
313             perror("sendto");
314             continue;
315         }
316         // Wait for a response. We get our own ECHO_REQUEST and the responce
317         echo_responce = 0;
318         while (!echo_responce) {
319           fromlen = sizeof(from);
320           len = recvfrom(s, pkt2, sizeof(pkt2), 0, (struct sockaddr *)&from, 
321                          &fromlen);
322           if (len < 0) {
323             perror("recvfrom");
324             echo_responce=1;
325           } else {
326             if (show6_icmp(pkt2, len, &from, host)) {
327               ok_recv++;
328               echo_responce=1;
329             }
330           }
331         }
332     }
333     diag_printf("Sent %d packets, received %d OK, %d bad\n", NUM_PINGS, 
334                 ok_recv, bogus_recv);
335 }
336
337 static void
338 ping6_test( struct sockaddr_in6 *host)
339 {
340     struct protoent *p;
341     struct timeval tv;
342     struct sockaddr_in6 addr;
343     int s;
344
345     if ((p = getprotobyname("ipv6-icmp")) == (struct protoent *)0) {
346         perror("getprotobyname");
347         return;
348     }
349     s = socket(AF_INET6, SOCK_RAW, p->p_proto);
350     if (s < 0) {
351         perror("socket");
352         return;
353     }
354     tv.tv_sec = 1;
355     tv.tv_usec = 0;
356     setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
357
358     ping6_host(s, host);
359
360     // Now try a bogus host
361     memcpy(&addr,host,sizeof(addr));
362     addr.sin6_addr.s6_addr[15] = addr.sin6_addr.s6_addr[15] + 32;
363     ping6_host(s, &addr);
364 }
365 #endif
366
367 #ifdef CYGPKG_PROFILE_GPROF
368 #include <cyg/profile/profile.h>
369
370 extern char _stext, _etext;  // Defined by the linker
371
372 static void
373 start_profile(void)
374 {
375     // This starts up the system-wide profiling, gathering
376     // profile information on all of the code, with a 16 byte
377     // "bucket" size, at a rate of 100us/profile hit.
378     // Note: a bucket size of 16 will give pretty good function
379     //       resolution.  Much smaller and the buffer becomes
380     //       much too large for very little gain.
381     // Note: a timer period of 100us is also a reasonable
382     //       compromise.  Any smaller and the overhead of 
383     //       handling the timter (profile) interrupt could
384     //       swamp the system.  A fast processor might get
385     //       by with a smaller value, but a slow one could
386     //       even be swamped by this value.  If the value is
387     //       too large, the usefulness of the profile is reduced.
388     profile_on(&_stext, &_etext, 16, 100);
389 }
390 #endif
391
392 static void
393 ping_test(struct bootp *bp)
394 {
395     struct protoent *p;
396     struct timeval tv;
397     struct sockaddr_in host;
398     int s;
399
400     if ((p = getprotobyname("icmp")) == (struct protoent *)0) {
401         pexit("getprotobyname");
402         return;
403     }
404     s = socket(AF_INET, SOCK_RAW, p->p_proto);
405     if (s < 0) {
406         pexit("socket");
407         return;
408     }
409     tv.tv_sec = 1;
410     tv.tv_usec = 0;
411     setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
412     // Set up host address
413     host.sin_family = AF_INET;
414     host.sin_len = sizeof(host);
415     host.sin_addr = bp->bp_siaddr;
416     host.sin_port = 0;
417     ping_host(s, &host);
418     // Now try a bogus host
419     host.sin_addr.s_addr = htonl(ntohl(host.sin_addr.s_addr) + 32);
420     ping_host(s, &host);
421 }
422
423 void
424 net_test(cyg_addrword_t p)
425 {
426 #ifdef CYGPKG_NET_INET6
427     struct sockaddr_in6 ipv6router;
428 #endif
429
430     diag_printf("Start PING test\n");
431     TNR_INIT();
432     init_all_network_interfaces();
433 #ifdef CYGPKG_PROFILE_GPROF
434     start_profile();
435 #endif
436 #ifdef CYGHWR_NET_DRIVER_ETH0
437     if (eth0_up) {
438         ping_test(&eth0_bootp_data);
439     }
440 #endif
441 #ifdef CYGHWR_NET_DRIVER_ETH1
442     if (eth1_up) {
443         ping_test(&eth1_bootp_data);
444     }
445 #endif
446 #ifdef CYGPKG_NET_INET6
447     if (cyg_net_get_ipv6_advrouter(&ipv6router)) {
448       ping6_test(&ipv6router);
449     } else {
450       CYG_TEST_FAIL("No router advertisement recieved");
451     }
452 #endif
453     TNR_PRINT_ACTIVITY();
454     CYG_TEST_PASS_FINISH("Ping test OK");
455 }
456
457 void
458 cyg_start(void)
459 {
460     // Create a main thread, so we can run the scheduler and have time 'pass'
461     cyg_thread_create(10,                // Priority - just a number
462                       net_test,          // entry
463                       0,                 // entry parameter
464                       "Network test",    // Name
465                       &stack[0],         // Stack
466                       STACK_SIZE,        // Size
467                       &thread_handle,    // Handle
468                       &thread_data       // Thread data structure
469             );
470     cyg_thread_resume(thread_handle);  // Start it
471     cyg_scheduler_start();
472 }