]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/net/autotest/v2_0/tests/slowpingmux.c
Initial revision
[karo-tx-redboot.git] / packages / net / autotest / v2_0 / tests / slowpingmux.c
1 //==========================================================================
2 //
3 //      autotest/current/tests/slowpingmux.c
4 //
5 //      Simple pinging test, the server pings me and I ping her.
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // -------------------------------------------
37 //####ECOSGPLCOPYRIGHTEND####
38 //####BSDCOPYRIGHTBEGIN####
39 //
40 // -------------------------------------------
41 //
42 // Portions of this software may have been derived from OpenBSD or other sources,
43 // and are covered by the appropriate copyright disclaimers included herein.
44 //
45 // -------------------------------------------
46 //
47 //####BSDCOPYRIGHTEND####
48 //==========================================================================
49 //#####DESCRIPTIONBEGIN####
50 //
51 // Author(s):    hmt,gthomas
52 // Contributors: hmt,gthomas
53 // Date:         2000-10-23
54 // Purpose:      
55 // Description:  
56 //              
57 //
58 //####DESCRIPTIONEND####
59 //
60 //==========================================================================
61
62 #include <pkgconf/system.h>
63
64 #include <cyg/infra/testcase.h>         // testing infrastructure
65
66 #include <pkgconf/net.h>
67
68 #ifdef CYGBLD_DEVS_ETH_DEVICE_H    // Get the device config if it exists
69 #include CYGBLD_DEVS_ETH_DEVICE_H  // May provide CYGTST_DEVS_ETH_TEST_NET_REALTIME
70 #endif
71
72 #ifdef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS // do we use the rt test?
73 # ifdef CYGTST_DEVS_ETH_TEST_NET_REALTIME // Get the test ancilla if it exists
74 #  include CYGTST_DEVS_ETH_TEST_NET_REALTIME
75 # endif
76 #endif
77
78
79 // Fill in the blanks if necessary
80 #ifndef TNR_OFF
81 # define TNR_OFF()
82 #endif
83 #ifndef TNR_ON
84 # define TNR_ON()
85 #endif
86 #ifndef TNR_INIT
87 # define TNR_INIT()
88 #endif
89 #ifndef TNR_PRINT_ACTIVITY
90 # define TNR_PRINT_ACTIVITY()
91 #endif
92
93 // ------------------------------------------------------------------------
94
95 #include <errno.h>
96 #include <network.h>
97
98 #include "autohost.inl"
99
100
101 #define NUM_PINGS 16
102 #define MAX_PACKET 4096
103 #define MIN_PACKET   64
104 #define MAX_SEND   4000
105
106 #define PACKET_ADD  ((MAX_SEND - MIN_PACKET)/NUM_PINGS)
107 #define nPACKET_ADD  1 
108
109 static unsigned char pkt1[MAX_PACKET], pkt2[MAX_PACKET];
110
111 #define UNIQUEID 0x1234
112
113 // Compute INET checksum
114 int
115 inet_cksum(u_short *addr, int len)
116 {
117     register int nleft = len;
118     register u_short *w = addr;
119     register u_short answer;
120     register u_int sum = 0;
121     u_short odd_byte = 0;
122
123     /*
124      *  Our algorithm is simple, using a 32 bit accumulator (sum),
125      *  we add sequential 16 bit words to it, and at the end, fold
126      *  back all the carry bits from the top 16 bits into the lower
127      *  16 bits.
128      */
129     while( nleft > 1 )  {
130         sum += *w++;
131         nleft -= 2;
132     }
133
134     /* mop up an odd byte, if necessary */
135     if( nleft == 1 ) {
136         *(u_char *)(&odd_byte) = *(u_char *)w;
137         sum += odd_byte;
138     }
139
140     /*
141      * add back carry outs from top 16 bits to low 16 bits
142      */
143     sum = (sum >> 16) + (sum & 0x0000ffff); /* add hi 16 to low 16 */
144     sum += (sum >> 16);                     /* add carry */
145     answer = ~sum;                          /* truncate to 16 bits */
146     return (answer);
147 }
148
149 static int
150 show_icmp(unsigned char *pkt, int len, 
151           struct sockaddr_in *from, struct sockaddr_in *to)
152 {
153     cyg_tick_count_t *tp, tv;
154     struct ip *ip;
155     struct icmp *icmp;
156     tv = cyg_current_time();
157     ip = (struct ip *)pkt;
158     if ((len < sizeof(*ip)) || ip->ip_v != IPVERSION) {
159         diag_printf("%s: Short packet or not IP! - Len: %d, Version: %d\n", 
160                     inet_ntoa(from->sin_addr), len, ip->ip_v);
161         return 0;
162     }
163     icmp = (struct icmp *)(pkt + sizeof(*ip));
164     len -= (sizeof(*ip) + 8);
165     tp = (cyg_tick_count_t *)&icmp->icmp_data;
166     if (icmp->icmp_type != ICMP_ECHOREPLY) {
167         diag_printf("%s: Invalid ICMP - type: %d\n", 
168                     inet_ntoa(from->sin_addr), icmp->icmp_type);
169         return 0;
170     }
171     if (icmp->icmp_id != UNIQUEID) {
172         diag_printf("%s: ICMP received for wrong id - sent: %x, recvd: %x\n", 
173                     inet_ntoa(from->sin_addr), UNIQUEID, icmp->icmp_id);
174     }
175 //    diag_printf("%d bytes from %s: ", len, inet_ntoa(from->sin_addr));
176 //    diag_printf("icmp_seq=%d", icmp->icmp_seq);
177 //    diag_printf(", time=%dms\n", (int)(tv - *tp)*10);
178     return (from->sin_addr.s_addr == to->sin_addr.s_addr);
179 }
180
181 static void
182 ping_host(int s, struct sockaddr_in *host)
183 {
184     struct icmp *icmp = (struct icmp *)pkt1;
185     int icmp_len = MIN_PACKET;
186     int seq, ok_recv, bogus_recv;
187     cyg_tick_count_t *tp;
188     long *dp;
189     struct sockaddr_in from;
190     int i, len, fromlen;
191     int maxlen = 0;
192
193     ok_recv = 0;
194     bogus_recv = 0;
195     TNR_OFF();
196     diag_printf("PING server %s\n", inet_ntoa(host->sin_addr));
197     for (seq = 0;  seq < NUM_PINGS;  seq++, icmp_len += PACKET_ADD ) {
198         TNR_ON();
199         cyg_thread_delay( 47 ); // Half a second...
200         // Build ICMP packet
201         icmp->icmp_type = ICMP_ECHO;
202         icmp->icmp_code = 0;
203         icmp->icmp_cksum = 0;
204         icmp->icmp_seq = seq;
205         icmp->icmp_id = 0x1234;
206         // Set up ping data
207         tp = (cyg_tick_count_t *)&icmp->icmp_data;
208         *tp++ = cyg_current_time();
209         dp = (long *)tp;
210         for (i = sizeof(*tp);  i < icmp_len;  i += sizeof(*dp)) {
211             *dp++ = i;
212         }
213         // Add checksum
214         icmp->icmp_cksum = inet_cksum( (u_short *)icmp, icmp_len+8);
215         // Send it off
216         if (sendto(s, icmp, icmp_len+8, 0, (struct sockaddr *)host, sizeof(*host)) < 0) {
217             TNR_OFF();
218             perror("sendto");
219             continue;
220         }
221         // Wait for a response
222         fromlen = sizeof(from);
223         len = recvfrom(s, pkt2, sizeof(pkt2), 0, (struct sockaddr *)&from, &fromlen);
224         TNR_OFF();
225         if (len < 0) {
226 //            perror("recvfrom");
227             icmp_len = MIN_PACKET - PACKET_ADD; // just in case - long routes
228         } else {
229             if (show_icmp(pkt2, len, &from, host)) {
230                 ok_recv++;
231                 if ( len > maxlen )
232                     maxlen = len;
233             } else {
234                 bogus_recv++;
235             }
236         }
237     }
238     TNR_OFF();
239     diag_printf("Sent %d packets, received %d OK, %d bad max len %d\n",
240                 NUM_PINGS, ok_recv, bogus_recv, maxlen);
241 }
242
243 static void
244 ping_test(struct bootp *bp)
245 {
246     struct protoent *p;
247     struct timeval tv;
248     struct sockaddr_in host;
249     int s;
250
251     if ((p = getprotobyname("icmp")) == (struct protoent *)0) {
252         pexit("getprotobyname");
253         return;
254     }
255     s = socket(AF_INET, SOCK_RAW, p->p_proto);
256     if (s < 0) {
257         pexit("socket");
258         return;
259     }
260     tv.tv_sec = 1;
261     tv.tv_usec = 0;
262     setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
263     // Set up host address
264     host.sin_family = AF_INET;
265     host.sin_len = sizeof(host);
266     host.sin_addr = bp->bp_siaddr;
267     host.sin_port = 0;
268     ping_host(s, &host);
269     // Now try a bogus host
270     host.sin_addr.s_addr = htonl(ntohl(host.sin_addr.s_addr) + 32);
271     ping_host(s, &host);
272     close(s);
273 }
274
275 // ------------------------------------------------------------------------
276
277 #define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x10000)
278 static char stack[STACK_SIZE];
279 static cyg_thread thread_data;
280 static cyg_handle_t thread_handle;
281
282 static void
283 do_ping_tests(struct bootp *bp, int N, int testtime, int filesize)
284 {
285     int i;
286     char order[256];
287     diag_printf( "INFO: telling %s to run %d pings for %d seconds, %d bytes and up\n",
288           inet_ntoa(bp->bp_siaddr), N, testtime, filesize );
289
290     // For 2nd and subsequent orders, we vary the ping data size:
291     for ( i = 0; i < N; i++ ) {
292         sprintf( order, "%s %s %d %d", "SLOW_PING",
293                  inet_ntoa(bp->bp_yiaddr),
294                  testtime,
295                  filesize + 100 * i );
296         autohost_tell( bp, order );
297     }
298 }
299
300 #define TESTTIME (5 * 60) // Seconds
301
302 #define NUM_SESSIONS 10 // why not?
303
304 void
305 net_test(cyg_addrword_t param)
306 {
307     int i;
308     int numtests;
309     cyg_tick_count_t ticks;
310     CYG_TEST_INIT();
311     CYG_TEST_INFO("Start PING server test");
312     init_all_network_interfaces();
313
314     autohost_init();
315
316     TNR_INIT();
317     
318     numtests = NUM_SESSIONS; // The number of pingers started OK
319     i = numtests;
320     // Now command the host to do ping to us...
321 #ifdef CYGHWR_NET_DRIVER_ETH0
322     if (eth0_up) {
323         // 2 small tests by default and a couple of larger ones
324         do_ping_tests(&eth0_bootp_data, 1, TESTTIME, 64);
325         do_ping_tests(&eth0_bootp_data, 2, TESTTIME, 1000);
326         do_ping_tests(&eth0_bootp_data, 2, TESTTIME, 10000);
327         i -= 5;
328     }
329 #endif
330 #ifdef CYGHWR_NET_DRIVER_ETH1
331     if (eth1_up && i > 0) {
332         // rest of the tests depending...
333         do_ping_tests(&eth1_bootp_data, 2, TESTTIME, 64);
334         i -= 2;
335         do_ping_tests(&eth1_bootp_data, 1, TESTTIME, 4000);
336         i -= 1;
337         do_ping_tests(&eth1_bootp_data, i, TESTTIME, 1200);
338         i = 0; // Since we just used up the rest
339     }
340 #endif
341     numtests -= i; // Adjust to how many we *actually* requested
342
343     // Let the server run for 5 minutes
344     cyg_thread_delay(2*100); // let the stuff start up first
345     TNR_ON();
346
347     ticks = cyg_current_time() + TESTTIME * 100; // FIXME - assume cS clock.
348     while (1) {
349         if ( ticks < cyg_current_time() ) break;
350 #ifdef CYGHWR_NET_DRIVER_ETH0
351         if (eth0_up) {
352             ping_test(&eth0_bootp_data);
353         }
354 #endif
355 #ifdef CYGHWR_NET_DRIVER_ETH1
356         if ( ticks < cyg_current_time() ) break;
357         if (eth1_up) {
358             ping_test(&eth1_bootp_data);
359         }
360 #endif
361     };
362
363     // Additional delay 'cos host may be slower than us - and it has to
364     // complete a transfer anyway:
365     cyg_thread_delay(  30    *100); // FIXME - assume cS clock.
366     TNR_OFF();
367
368     autohost_end( numtests ); // check for N pass messages from hosts
369
370     TNR_PRINT_ACTIVITY();
371     CYG_TEST_EXIT("Done");
372 }
373
374 void
375 cyg_start(void)
376 {
377     // Create a main thread, so we can run the scheduler and have time 'pass'
378     cyg_thread_create(10,                // Priority - just a number
379                       net_test,          // entry
380                       0,                 // entry parameter
381                       "Network test",    // Name
382                       &stack[0],         // Stack
383                       STACK_SIZE,        // Size
384                       &thread_handle,    // Handle
385                       &thread_data       // Thread data structure
386             );
387     cyg_thread_resume(thread_handle);  // Start it
388     cyg_scheduler_start();
389 }
390
391 // EOF slowpingmux.c