unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / net / common / v2_0 / tests / dhcp_test.c
1 //==========================================================================
2 //
3 //      tests/dhcp_test.c
4 //
5 //      Simple test of DHCP (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
23 // Date:         2000-01-10
24 // Purpose:      
25 // Description:  
26 //              
27 //
28 //####DESCRIPTIONEND####
29 //
30 //==========================================================================
31
32 // DHCP test code
33
34 #include <network.h>
35
36 #include <pkgconf/system.h>
37 #include <pkgconf/net.h>
38
39 #include <dhcp.h>
40
41 #include <cyg/infra/testcase.h>
42
43 #ifdef CYGBLD_DEVS_ETH_DEVICE_H    // Get the device config if it exists
44 #include CYGBLD_DEVS_ETH_DEVICE_H  // May provide CYGTST_DEVS_ETH_TEST_NET_REALTIME
45 #endif
46
47 #ifdef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS // do we use the rt test?
48 # ifdef CYGTST_DEVS_ETH_TEST_NET_REALTIME // Get the test ancilla if it exists
49 #  include CYGTST_DEVS_ETH_TEST_NET_REALTIME
50 # endif
51 #endif
52
53 // Fill in the blanks if necessary
54 #ifndef TNR_OFF
55 # define TNR_OFF()
56 #endif
57 #ifndef TNR_ON
58 # define TNR_ON()
59 #endif
60 #ifndef TNR_INIT
61 # define TNR_INIT()
62 #endif
63 #ifndef TNR_PRINT_ACTIVITY
64 # define TNR_PRINT_ACTIVITY()
65 #endif
66
67
68
69 #define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
70 static char stack[STACK_SIZE];
71 static cyg_thread thread_data;
72 static cyg_handle_t thread_handle;
73
74 #define NUM_PINGS 16
75 #define MAX_PACKET 4096
76 #define MIN_PACKET   64
77 #define MAX_SEND   4000
78
79 #define PACKET_ADD  ((MAX_SEND - MIN_PACKET)/NUM_PINGS)
80 #define nPACKET_ADD  1 
81
82 static unsigned char pkt1[MAX_PACKET], pkt2[MAX_PACKET];
83
84 #define UNIQUEID 0x1234
85
86 void
87 pexit(char *s)
88 {
89     CYG_TEST_FAIL_FINISH(s);
90 }
91
92 // Compute INET checksum
93 int
94 inet_cksum(u_short *addr, int len)
95 {
96     register int nleft = len;
97     register u_short *w = addr;
98     register u_short answer;
99     register u_int sum = 0;
100     u_short odd_byte = 0;
101
102     /*
103      *  Our algorithm is simple, using a 32 bit accumulator (sum),
104      *  we add sequential 16 bit words to it, and at the end, fold
105      *  back all the carry bits from the top 16 bits into the lower
106      *  16 bits.
107      */
108     while( nleft > 1 )  {
109         sum += *w++;
110         nleft -= 2;
111     }
112
113     /* mop up an odd byte, if necessary */
114     if( nleft == 1 ) {
115         *(u_char *)(&odd_byte) = *(u_char *)w;
116         sum += odd_byte;
117     }
118
119     /*
120      * add back carry outs from top 16 bits to low 16 bits
121      */
122     sum = (sum >> 16) + (sum & 0x0000ffff); /* add hi 16 to low 16 */
123     sum += (sum >> 16);                     /* add carry */
124     answer = ~sum;                          /* truncate to 16 bits */
125     return (answer);
126 }
127
128 static int
129 show_icmp(unsigned char *pkt, int len, 
130           struct sockaddr_in *from, struct sockaddr_in *to)
131 {
132     cyg_tick_count_t *tp, tv;
133     struct ip *ip;
134     struct icmp *icmp;
135     tv = cyg_current_time();
136     ip = (struct ip *)pkt;
137     if ((len < sizeof(*ip)) || ip->ip_v != IPVERSION) {
138         diag_printf("%s: Short packet or not IP! - Len: %d, Version: %d\n", 
139                     inet_ntoa(from->sin_addr), len, ip->ip_v);
140         return 0;
141     }
142     icmp = (struct icmp *)(pkt + sizeof(*ip));
143     len -= (sizeof(*ip) + 8);
144     tp = (cyg_tick_count_t *)&icmp->icmp_data;
145     if (icmp->icmp_type != ICMP_ECHOREPLY) {
146         diag_printf("%s: Invalid ICMP - type: %d\n", 
147                     inet_ntoa(from->sin_addr), icmp->icmp_type);
148         return 0;
149     }
150     if (icmp->icmp_id != UNIQUEID) {
151         diag_printf("%s: ICMP received for wrong id - sent: %x, recvd: %x\n", 
152                     inet_ntoa(from->sin_addr), UNIQUEID, icmp->icmp_id);
153     }
154     diag_printf("%d bytes from %s: ", len, inet_ntoa(from->sin_addr));
155     diag_printf("icmp_seq=%d", icmp->icmp_seq);
156     diag_printf(", time=%dms\n", (int)(tv - *tp)*10);
157     return (from->sin_addr.s_addr == to->sin_addr.s_addr);
158 }
159
160 static void
161 ping_host(int s, struct sockaddr_in *host)
162 {
163     struct icmp *icmp = (struct icmp *)pkt1;
164     int icmp_len = MIN_PACKET;
165     int seq, ok_recv, bogus_recv;
166     cyg_tick_count_t *tp;
167     long *dp;
168     struct sockaddr_in from;
169     int i, len;
170     socklen_t fromlen;
171
172     ok_recv = 0;
173     bogus_recv = 0;
174     diag_printf("PING server %s\n", inet_ntoa(host->sin_addr));
175     for (seq = 0;  seq < NUM_PINGS;  seq++, icmp_len += PACKET_ADD ) {
176         TNR_ON();
177         // Build ICMP packet
178         icmp->icmp_type = ICMP_ECHO;
179         icmp->icmp_code = 0;
180         icmp->icmp_cksum = 0;
181         icmp->icmp_seq = seq;
182         icmp->icmp_id = 0x1234;
183         // Set up ping data
184         tp = (cyg_tick_count_t *)&icmp->icmp_data;
185         *tp++ = cyg_current_time();
186         dp = (long *)tp;
187         for (i = sizeof(*tp);  i < icmp_len;  i += sizeof(*dp)) {
188             *dp++ = i;
189         }
190         // Add checksum
191         icmp->icmp_cksum = inet_cksum( (u_short *)icmp, icmp_len+8);
192         // Send it off
193         if (sendto(s, icmp, icmp_len+8, 0, (struct sockaddr *)host, sizeof(*host)) < 0) {
194             TNR_OFF();
195             perror("sendto");
196             continue;
197         }
198         // Wait for a response
199         fromlen = sizeof(from);
200         len = recvfrom(s, pkt2, sizeof(pkt2), 0, (struct sockaddr *)&from, &fromlen);
201         TNR_OFF();
202         if (len < 0) {
203             perror("recvfrom");
204             icmp_len = MIN_PACKET - PACKET_ADD; // go back to small packet size
205             seq+=4;
206         } else {
207             if (show_icmp(pkt2, len, &from, host)) {
208                 ok_recv++;
209             } else {
210                 bogus_recv++;
211             }
212         }
213     }
214     TNR_OFF();
215 }
216
217 static void
218 ping_test(struct bootp *bp)
219 {
220     struct protoent *p;
221     struct timeval tv;
222     struct sockaddr_in host;
223     int s;
224
225     if ((p = getprotobyname("icmp")) == (struct protoent *)0) {
226         pexit("getprotobyname");
227         return;
228     }
229     s = socket(AF_INET, SOCK_RAW, p->p_proto);
230     if (s < 0) {
231         pexit("socket");
232         return;
233     }
234     tv.tv_sec = 1;
235     tv.tv_usec = 0;
236     setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
237     // Set up host address
238     host.sin_family = AF_INET;
239     host.sin_len = sizeof(host);
240     host.sin_addr = bp->bp_siaddr;
241     host.sin_port = 0;
242     ping_host(s, &host);
243     // Now try a bogus host
244     host.sin_addr.s_addr = htonl(ntohl(host.sin_addr.s_addr) + 32);
245     ping_host(s, &host);
246     close(s);
247 }
248
249 void
250 net_test(cyg_addrword_t p)
251 {
252 #ifndef CYGPKG_NET_DHCP
253     CYG_TEST_NA( "DHCP is not enabled" );
254     CYG_TEST_EXIT( "DHCP is not enabled" );
255 #else
256     int i;
257     diag_printf("Start DHCP test\n");
258     TNR_INIT();
259     init_all_network_interfaces();
260
261     for ( i = 10; i > 0; i-- ) {
262 #ifdef CYGHWR_NET_DRIVER_ETH0
263         if (eth0_up) {
264             ping_test(&eth0_bootp_data);
265         }
266 #endif
267         // Now do the DHCP renewal ritual...
268         if ( cyg_semaphore_trywait( &dhcp_needs_attention )) {
269             if ( ! dhcp_bind() ) {
270                 // All done
271                 dhcp_halt();
272                 CYG_TEST_FAIL_FINISH( "Rebind after lease failed");
273                 break;
274             }
275         }
276 #ifdef CYGHWR_NET_DRIVER_ETH1
277         if (eth1_up) {
278             ping_test(&eth1_bootp_data);
279         }
280 #endif
281
282 #ifndef CYGOPT_NET_DHCP_DHCP_THREAD
283         // Now do the DHCP renewal ritual...
284         if ( cyg_semaphore_trywait( &dhcp_needs_attention )) {
285             if ( ! dhcp_bind() ) {
286                 // All done
287                 dhcp_halt();
288                 CYG_TEST_FAIL_FINISH( "Rebind after lease failed");
289                 break;
290             }
291         }
292 #endif // not CYGOPT_NET_DHCP_DHCP_THREAD 
293
294         if ( 1 == (i & 3) ) {
295             dhcp_release();             // relinquish leases
296             dhcp_halt();
297             init_all_network_interfaces();
298         }
299     }
300     dhcp_release();
301
302     TNR_PRINT_ACTIVITY();
303     CYG_TEST_PASS_FINISH("Dhcp test OK");
304 #endif
305 }
306
307 void
308 cyg_start(void)
309 {
310     // Create a main thread, so we can run the scheduler and have time 'pass'
311     cyg_thread_create(10,                // Priority - just a number
312                       net_test,          // entry
313                       0,                 // entry parameter
314                       "Network test",    // Name
315                       &stack[0],         // Stack
316                       STACK_SIZE,        // Size
317                       &thread_handle,    // Handle
318                       &thread_data       // Thread data structure
319             );
320     cyg_thread_resume(thread_handle);  // Start it
321     cyg_scheduler_start();
322 }