905ae472a9a0ff11d24954862f25766b30a2c43c
[karo-tx-redboot.git] / packages / net / common / v2_0 / tests / nc_test_master.c
1 //==========================================================================
2 //
3 //      tests/nc_test_master.c
4 //
5 //      Network characterizations test (master portion)
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 // Network characterization test code - master portion
33
34 #include "nc_test_framework.h"
35
36 #ifdef __ECOS
37 #ifndef CYGPKG_LIBC_STDIO
38 #define perror(s) diag_printf(#s ": %s\n", strerror(errno))
39 #endif
40 #define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
41 static char stack[STACK_SIZE];
42 static cyg_thread thread_data;
43 static cyg_handle_t thread_handle;
44 #endif
45
46 struct test_params {
47     int  argc;
48     char **argv;
49 };
50
51 #define MAX_BUF 32*1024
52 static unsigned char in_buf[MAX_BUF], out_buf[MAX_BUF];
53
54 static int test_seq = 1;
55 static long long idle_count;
56 static long      idle_ticks;
57 #define IDLE_TEST_TIME   10
58
59 struct pause {
60     int pause_ticks;
61     int pause_threshold;
62 };
63 #define LENGTH(x) (sizeof(x)/sizeof(x[0]))
64
65 #ifdef __ECOS
66 extern void
67 cyg_test_exit(void);
68 #else
69 void
70 cyg_test_exit(void)
71 {
72     test_printf("... Done\n");
73     exit(1);
74 }
75 #endif
76
77 #ifdef __ECOS
78 static void
79 test_delay(int ticks)
80 {
81     cyg_thread_delay(ticks);
82 }
83
84 #else
85
86 static void
87 test_delay(int ticks)
88 {
89     usleep(ticks * 10000);
90 }
91 #endif
92
93 void
94 pexit(char *s)
95 {
96     perror(s);
97     cyg_test_exit();
98 }
99
100 #ifdef __ECOS
101 #ifndef CYGPKG_SNMPLIB
102 int
103 gettimeofday(struct timeval *tv, struct timezone *tz)
104 {
105     cyg_tick_count_t cur_time;
106     cur_time = cyg_current_time();
107     tv->tv_sec = cur_time / 100;
108     tv->tv_usec = (cur_time % 100) * 10000;
109 }
110 #else
111 int
112 gettimeofday(struct timeval *tv, struct timezone *tz);
113 #endif
114 #endif
115 void
116 show_results(const char *msg, struct timeval *start, 
117              struct timeval *end, int nbufs, int buflen,
118              int lost, int seq_errors)
119 {
120     struct timeval tot_time;
121 #ifndef __ECOS
122     double real_time, thru;
123     long tot_bytes = nbufs * buflen;
124 #endif
125     timersub(end, start, &tot_time);
126     test_printf("%s - %d bufs of %d bytes in %d.%02d seconds",
127                 msg, nbufs, buflen, 
128                 tot_time.tv_sec, tot_time.tv_usec / 10000);
129 #ifndef __ECOS
130     real_time = tot_time.tv_sec + ((tot_time.tv_usec / 10000) * .01);
131     // Compute bytes / second (rounded up)
132     thru = tot_bytes / real_time;
133     // Convert to Mb / second
134     test_printf(" - %.2f KB/S", thru / 1024.0);
135     test_printf(" - %.4f Mbit/S (M = 10^6)", thru * 8.0 / 1000000.0);
136 #endif
137     if (lost) {
138         test_printf(", %d lost", lost);
139     }
140     if (seq_errors) {
141         test_printf(", %d out of sequence", seq_errors);
142     }
143     test_printf("\n");
144 }
145
146 void
147 new_test(void)
148 {
149     test_seq++;
150 }
151
152 int
153 nc_message(int s, struct nc_request *req, 
154            struct nc_reply *reply, struct sockaddr_in *slave)
155 {
156     int len;
157     fd_set fds;
158     struct timeval timeout;
159     len = sizeof(*slave);
160     req->seq = htonl(test_seq);
161     if (sendto(s, req, sizeof(*req), 0, (struct sockaddr *)slave, len) < 0) {
162         perror("sendto");
163         return false;
164     }
165     FD_ZERO(&fds);
166     FD_SET(s, &fds);
167     timeout.tv_sec = NC_REPLY_TIMEOUT;
168     timeout.tv_usec = 0;
169     if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
170         test_printf("No response to command\n");
171         return false;
172     }
173     if (recvfrom(s, reply, sizeof(*reply), 0, 0, 0) < 0) {
174         perror("recvfrom");
175         return false;
176     }
177     if (reply->seq != req->seq) {
178         test_printf("Response out of order - sent: %d, recvd: %d\n",
179                     ntohl(req->seq), ntohl(reply->seq));
180         return false;
181     }
182     return true;
183 }
184
185 void
186 show_test_results(struct nc_test_results *results)
187 {
188     if ((ntohl(results->key1) == NC_TEST_RESULT_KEY1) &&
189         (ntohl(results->key2) == NC_TEST_RESULT_KEY2) &&
190         (ntohl(results->seq) == test_seq)) {
191         test_printf("   slave sent %d, recvd %d\n", 
192                     ntohl(results->nsent), ntohl(results->nrecvd));
193     } else {
194         test_printf("   ... invalid results - keys: %x/%x, seq: %d/%d\n",
195                     ntohl(results->key1), ntohl(results->key2),
196                     ntohl(results->seq), test_seq);
197     }
198 }
199
200 void
201 do_udp_test(int s1, int type, struct sockaddr_in *slave,
202             int nbufs, int buflen, int pause_time, int pause_threshold)
203 {
204     int i, s, td_len, seq, seq_errors, total_packets;
205     struct sockaddr_in test_chan_master, test_chan_slave;
206     struct timeval start_time, end_time;
207     struct nc_request req;
208     struct nc_reply reply;
209     struct nc_test_results results;
210     struct nc_test_data *tdp;
211     fd_set fds;
212     struct timeval timeout;
213     int lost_packets = 0;
214     int need_send, need_recv;
215     const char *type_name;
216     int pkt_ctr = 0;
217
218     need_recv = true;  need_send = true;  type_name = "UDP echo";
219     switch (type) {
220     case NC_REQUEST_UDP_RECV:
221         need_recv = false;
222         need_send = true;
223         type_name = "UDP recv";
224         break;
225     case NC_REQUEST_UDP_SEND:
226         need_recv = true;
227         need_send = false;
228         type_name = "UDP send";
229         break;
230     case NC_REQUEST_UDP_ECHO:
231         break;
232     }
233
234     new_test();
235     req.type = htonl(type);
236     req.nbufs = htonl(nbufs);
237     req.buflen = htonl(buflen);
238     req.slave_port = htonl(NC_TESTING_SLAVE_PORT);
239     req.master_port = htonl(NC_TESTING_MASTER_PORT);
240     nc_message(s1, &req, &reply, slave);
241     if (reply.response != ntohl(NC_REPLY_ACK)) {
242         test_printf("Slave denied %s [%d,%d] test\n", type_name, nbufs, buflen);
243         return;
244     }
245
246     s = socket(AF_INET, SOCK_DGRAM, 0);
247     if (s < 0) {
248         pexit("datagram socket");
249     }
250
251     memset(&test_chan_master, 0, sizeof(test_chan_master));
252     test_chan_master.sin_family = AF_INET;
253 #ifdef __ECOS
254     test_chan_master.sin_len = sizeof(test_chan_master);
255 #endif
256     test_chan_master.sin_port = htons(ntohl(req.master_port));
257     test_chan_master.sin_addr.s_addr = INADDR_ANY;
258
259     if (bind(s, (struct sockaddr *) &test_chan_master, sizeof(test_chan_master)) < 0) {
260         perror("bind");
261         close(s);
262         return;
263     }
264     test_printf("Start %s [%d,%d]", type_name, nbufs, buflen);
265     if (pause_time) {
266         test_printf(" - %dms delay after %d packet%s\n", pause_time*10, 
267                     pause_threshold, pause_threshold > 1 ? "s" : "");
268     } else {
269         test_printf(" - no delays\n");
270     }
271
272     gettimeofday(&start_time, 0);
273     memcpy(&test_chan_slave, slave, sizeof(*slave));
274     test_chan_slave.sin_port = htons(ntohl(req.slave_port));
275     seq = 0;  seq_errors = 0;  total_packets = 0;
276     for (i = 0;  i < nbufs;  i++) {
277         td_len = buflen + sizeof(struct nc_test_data);
278         if (need_send) {
279             tdp = (struct nc_test_data *)out_buf;
280             tdp->key1 = htonl(NC_TEST_DATA_KEY1);
281             tdp->key2 = htonl(NC_TEST_DATA_KEY2);
282             tdp->seq = htonl(i);
283             tdp->len = htonl(td_len);
284             if (sendto(s, tdp, td_len, 0, 
285                        (struct sockaddr *)&test_chan_slave, sizeof(test_chan_slave)) < 0) {
286                 perror("sendto");
287                 close(s);
288                 return;
289             }
290             total_packets++;
291         }
292         if (need_recv) {
293             FD_ZERO(&fds);
294             FD_SET(s, &fds);
295             timeout.tv_sec = NC_TEST_TIMEOUT;
296             timeout.tv_usec = 0;
297             if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
298                 test_printf("Slave timed out after %d buffers\n", i);
299                 lost_packets++;
300             } else {
301                 tdp = (struct nc_test_data *)in_buf;
302                 if (recvfrom(s, tdp, td_len, 0, 0, 0) < 0) {
303                     perror("recvfrom");
304                     close(s);
305                     return;
306                 }
307                 if ((ntohl(tdp->key1) == NC_TEST_DATA_KEY1) &&
308                     (ntohl(tdp->key2) == NC_TEST_DATA_KEY2)) {
309                     if (ntohl(tdp->seq) != seq) {
310                         test_printf("Packets out of sequence - recvd: %d, expected: %d\n",
311                                     ntohl(tdp->seq), seq);
312                         seq_errors++;
313                         if (!need_send) {
314                             // Reset sequence to what the slave wants
315                             seq = ntohl(tdp->seq);
316                         }
317                     }
318                 } else {
319                     test_printf("Bad data packet - key: %x/%x, seq: %d\n",
320                                 ntohl(tdp->key1), ntohl(tdp->key2),
321                                 ntohl(tdp->seq));
322                 }
323                 total_packets++;
324             }
325             seq++;
326             if (seq == nbufs) {
327                 break;
328             }
329             if (pause_time && (++pkt_ctr == pause_threshold)) {
330                 pkt_ctr = 0;
331                 test_delay(pause_time);
332             }
333         }
334     }
335     gettimeofday(&end_time, 0);
336     show_results(type_name, &start_time, &end_time, total_packets, buflen, 
337                  lost_packets, seq_errors);
338     // Fetch results record
339     FD_ZERO(&fds);
340     FD_SET(s, &fds);
341     timeout.tv_sec = NC_RESULTS_TIMEOUT;
342     timeout.tv_usec = 0;
343     if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
344         test_printf("No results record sent\n");
345     } else {
346         if (recvfrom(s, &results, sizeof(results), 0, 0, 0) < 0) {
347             perror("recvfrom");
348         }
349         show_test_results(&results);
350     }
351     close(s);
352 }
353
354 //
355 // Read data from a stream, accounting for the fact that packet 'boundaries'
356 // are not preserved.  This can also timeout (which would probably wreck the
357 // data boundaries).
358 //
359
360 int
361 do_read(int fd, void *buf, int buflen)
362 {
363     char *p = (char *)buf;
364     int len = buflen;
365     int res;
366     while (len) {
367         res = read(fd, p, len);
368         if (res < 0) {
369             perror("read");
370         } else {
371             len -= res;
372             p += res;
373             if (res == 0) {
374                 break;
375             }
376         }
377     }
378     return (buflen - len);
379 }
380
381 void
382 do_tcp_test(int s1, int type, struct sockaddr_in *slave,
383             int nbufs, int buflen, int pause_time, int pause_threshold)
384 {
385     int i, s, td_len, len, seq, seq_errors, total_packets, res;
386     struct sockaddr_in test_chan_slave;
387     struct timeval start_time, end_time;
388     struct nc_request req;
389     struct nc_reply reply;
390     struct nc_test_results results;
391     struct nc_test_data *tdp;
392     int lost_packets = 0;
393     int conn_failures = 0;
394     int need_send, need_recv;
395     const char *type_name;
396     int pkt_ctr = 0;
397
398     need_recv = true;  need_send = true;  type_name = "TCP echo";
399     switch (type) {
400     case NC_REQUEST_TCP_RECV:
401         need_recv = false;
402         need_send = true;
403         type_name = "TCP recv";
404         break;
405     case NC_REQUEST_TCP_SEND:
406         need_recv = true;
407         need_send = false;
408         type_name = "TCP send";
409         break;
410     case NC_REQUEST_TCP_ECHO:
411         break;
412     }
413
414     new_test();
415     req.type = htonl(type);
416     req.nbufs = htonl(nbufs);
417     req.buflen = htonl(buflen);
418     req.slave_port = htonl(NC_TESTING_SLAVE_PORT);
419     req.master_port = htonl(NC_TESTING_MASTER_PORT);
420     nc_message(s1, &req, &reply, slave);
421     if (reply.response != ntohl(NC_REPLY_ACK)) {
422         test_printf("Slave denied %s [%d,%d] test\n", type_name, nbufs, buflen);
423         return;
424     }
425
426     s = socket(AF_INET, SOCK_STREAM, 0);
427     if (s < 0) {
428         pexit("datagram socket");
429     }
430
431     test_printf("Start %s [%d,%d]", type_name, nbufs, buflen);
432     if (pause_time) {
433         test_printf(" - %dms delay after %d packet%s\n", pause_time*10, 
434                     pause_threshold, pause_threshold > 1 ? "s" : "");
435     } else {
436         test_printf(" - no delays\n");
437     }
438
439     test_delay(3*100);  
440     memcpy(&test_chan_slave, slave, sizeof(*slave));
441     test_chan_slave.sin_port = htons(ntohl(req.slave_port));
442     while (connect(s, (struct sockaddr *)&test_chan_slave, sizeof(*slave)) < 0) { 
443         perror("Can't connect to slave");
444         if (++conn_failures > MAX_ERRORS) {
445             test_printf("Too many connection failures - giving up\n");
446             return;
447         }
448         if (errno == ECONNREFUSED) {
449             // Give the slave a little time
450             test_delay(100);  // 1 second
451         } else {
452             return;
453         }
454     }
455
456     gettimeofday(&start_time, 0);
457     seq = 0;  seq_errors = 0;  total_packets = 0;
458     for (i = 0;  i < nbufs;  i++) {
459         td_len = buflen + sizeof(struct nc_test_data);
460         if (need_send) {
461             tdp = (struct nc_test_data *)out_buf;
462             tdp->key1 = htonl(NC_TEST_DATA_KEY1);
463             tdp->key2 = htonl(NC_TEST_DATA_KEY2);
464             tdp->seq = htonl(i);
465             tdp->len = htonl(td_len);
466             if ((len = write(s, tdp, td_len)) != td_len) {
467                 if (len < 0) {
468                     perror("write");
469                 } else {
470                     test_printf("short write - only %d or %d bytes written\n", len, td_len);
471                 }
472                 close(s);
473                 return;
474             }
475             total_packets++;
476         }
477         if (need_recv) {
478             tdp = (struct nc_test_data *)in_buf;
479             res = do_read(s, tdp, td_len);
480             if (res != td_len) {
481                 test_printf("Slave timed out after %d buffers\n", i);
482                 lost_packets++;
483             } else {
484                 if ((ntohl(tdp->key1) == NC_TEST_DATA_KEY1) &&
485                     (ntohl(tdp->key2) == NC_TEST_DATA_KEY2)) {
486                     if (ntohl(tdp->seq) != seq) {
487                         test_printf("Packets out of sequence - recvd: %d, expected: %d\n",
488                                     ntohl(tdp->seq), seq);
489                         seq_errors++;
490                         if (!need_send) {
491                             // Reset sequence to what the slave wants
492                             seq = ntohl(tdp->seq);
493                         }
494                     }
495                 } else {
496                     test_printf("Bad data packet - key: %x/%x, seq: %d\n",
497                                 ntohl(tdp->key1), ntohl(tdp->key2),
498                                 ntohl(tdp->seq));
499                 }
500                 total_packets++;
501             }
502             seq++;
503             if (seq == nbufs) {
504                 break;
505             }
506             if (pause_time && (++pkt_ctr == pause_threshold)) {
507                 pkt_ctr = 0;
508                 test_delay(pause_time);
509             }
510         }
511     }
512     gettimeofday(&end_time, 0);
513     show_results(type_name, &start_time, &end_time, total_packets, buflen, 
514                  lost_packets, seq_errors);
515     // Fetch results record
516     if (do_read(s, &results, sizeof(results)) != sizeof(results)) {
517         test_printf("No results record sent\n");
518     } else {
519         show_test_results(&results);
520     }
521     close(s);
522 }
523
524 int
525 do_set_load(int s, struct sockaddr_in *slave, int load_level)
526 {
527     struct nc_request req;
528     struct nc_reply reply;
529     req.type = htonl(NC_REQUEST_SET_LOAD);
530     req.nbufs = htonl(load_level);
531     nc_message(s, &req, &reply, slave);
532     return (reply.response == ntohl(NC_REPLY_ACK));
533 }
534
535 int
536 do_start_idle(int s, struct sockaddr_in *slave)
537 {
538     struct nc_request req;
539     struct nc_reply reply;
540     req.type = htonl(NC_REQUEST_START_IDLE);
541     nc_message(s, &req, &reply, slave);
542     return (reply.response == ntohl(NC_REPLY_ACK));
543 }
544
545 void
546 do_stop_idle(int s, struct sockaddr_in *slave, int calibrate)
547 {
548     struct nc_request req;
549     struct nc_reply reply;
550     long long res_idle_count;
551     long long adj_count;
552     int idle, res_idle_ticks;
553     req.type = htonl(NC_REQUEST_STOP_IDLE);
554     nc_message(s, &req, &reply, slave);
555     if (reply.response == ntohl(NC_REPLY_ACK)) {
556         res_idle_ticks = ntohl(reply.misc.idle_results.elapsed_time);
557         res_idle_count = ((long long)ntohl(reply.misc.idle_results.count[0]) << 32) |
558             ntohl(reply.misc.idle_results.count[1]);
559         test_printf("IDLE - ticks: %d, count: %ld", 
560                     res_idle_ticks, res_idle_count);
561         if (calibrate) {
562             idle_count = res_idle_count;
563             idle_ticks = res_idle_ticks;
564         } else {
565             adj_count = res_idle_count / res_idle_ticks;
566             adj_count *= idle_ticks;
567             idle = (int) ((adj_count * 100) / idle_count);
568             test_printf(", %d%% idle", idle);
569         }
570         test_printf("\n");
571     } else {
572         test_printf("Slave failed on IDLE\n");
573     }
574 }
575
576 void
577 do_disconnect(int s, struct sockaddr_in *slave)
578 {
579     struct nc_request req;
580     struct nc_reply reply;
581     req.type = htonl(NC_REQUEST_DISCONNECT);
582     nc_message(s, &req, &reply, slave);
583 }
584
585 static void
586 nc_master(struct test_params *p)
587 {
588     int s, i;
589     struct sockaddr_in slave, my_addr;
590     struct hostent *host;
591     struct pause pause_times[] = {
592         {0,0}, {1,10}, {5,10}, {10,10}, {1,1} };
593
594     if (p->argc != 2) {
595         test_printf("Need exactly 'master <host>'\n");
596         return;
597     }
598
599     s = socket(AF_INET, SOCK_DGRAM, 0);
600     if (s < 0) {
601         pexit("datagram socket");
602     }
603
604     memset(&my_addr, 0, sizeof(my_addr));
605     my_addr.sin_family = AF_INET;
606 #ifdef __ECOS
607     my_addr.sin_len = sizeof(my_addr);
608 #endif
609     my_addr.sin_port = htons(NC_MASTER_PORT);
610     my_addr.sin_addr.s_addr = INADDR_ANY;
611
612     if (bind(s, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0) {
613         pexit("bind");
614     }
615
616     host = gethostbyname(p->argv[1]);
617     if (host == (struct hostent *)NULL) {
618         pexit("gethostbyname");
619     }
620
621     memset(&slave, 0, sizeof(slave));
622     slave.sin_family = AF_INET;
623 #ifdef __ECOS
624     slave.sin_len = sizeof(slave);
625 #endif
626     slave.sin_port = htons(NC_SLAVE_PORT);
627     memcpy(&slave.sin_addr.s_addr, host->h_addr, host->h_length);
628
629     test_printf("================== No load, master at 100%% ========================\n");
630 #if 0
631     do_udp_test(s, NC_REQUEST_UDP_ECHO, &slave, 640, 1024, 0, 0);
632     do_udp_test(s, NC_REQUEST_UDP_SEND, &slave, 640, 1024, 0, 0);
633     do_udp_test(s, NC_REQUEST_UDP_RECV, &slave, 640, 1024, 0, 0);
634     do_tcp_test(s, NC_REQUEST_TCP_ECHO, &slave, 640, 1024, 0, 0);
635     do_tcp_test(s, NC_REQUEST_TCP_SEND, &slave, 640, 1024, 0, 0);
636     do_tcp_test(s, NC_REQUEST_TCP_RECV, &slave, 640, 1024, 0, 0);
637 #endif
638     do_tcp_test(s, NC_REQUEST_TCP_ECHO, &slave, 64, 10240, 0, 0);
639
640     if (do_set_load(s, &slave, 0)) {
641         test_printf("\n====================== Various slave compute loads ===================\n");
642         for (i = 0;  i < 60;  i += 10) {
643             test_printf(">>>>>>>>>>>> slave processing load at %d%%\n", i);
644             do_set_load(s, &slave, i);
645             do_udp_test(s, NC_REQUEST_UDP_ECHO, &slave, 2048, 1024, 0, 0);
646             do_tcp_test(s, NC_REQUEST_TCP_ECHO, &slave, 2048, 1024, 0, 0);
647         }
648     }
649
650     if (do_start_idle(s, &slave)) {
651         test_printf("\n====================== Various master loads ===================\n");
652         test_printf("Testing IDLE for %d seconds\n", IDLE_TEST_TIME);
653         test_delay(IDLE_TEST_TIME*100);
654         do_stop_idle(s, &slave, true);
655         for (i = 0;  i < LENGTH(pause_times);  i++) {
656             do_start_idle(s, &slave);
657             do_udp_test(s, NC_REQUEST_UDP_ECHO, &slave, 2048, 1024, 
658                         pause_times[i].pause_ticks, pause_times[i].pause_threshold);
659             do_stop_idle(s, &slave, false);
660             do_start_idle(s, &slave);
661             do_tcp_test(s, NC_REQUEST_TCP_ECHO, &slave, 2048, 1024, 
662                         pause_times[i].pause_ticks, pause_times[i].pause_threshold);
663             do_stop_idle(s, &slave, false);
664         }
665     }
666
667     do_disconnect(s, &slave);
668     close(s);
669 }
670
671 void
672 net_test(test_param_t p)
673 {
674     test_printf("Start Network Characterization - MASTER\n");
675 #ifdef __ECOS
676     init_all_network_interfaces();
677 #endif
678     nc_master((struct test_params *)p);
679     cyg_test_exit();
680 }
681
682 #ifdef __ECOS
683 void
684 cyg_start(void)
685 {
686     static struct test_params p;
687     // Create a main thread, so we can run the scheduler and have time 'pass'
688     cyg_thread_create(10,                // Priority - just a number
689                       net_test,          // entry
690                       (cyg_addrword_t)&p,// entry parameter
691                       "Network test",    // Name
692                       &stack[0],         // Stack
693                       STACK_SIZE,        // Size
694                       &thread_handle,    // Handle
695                       &thread_data       // Thread data structure
696             );
697     cyg_thread_resume(thread_handle);  // Start it
698     cyg_scheduler_start();
699 }
700
701 #else
702
703 int
704 main(int argc, char *argv[])
705 {
706     struct test_params p;
707     p.argc = argc;
708     p.argv = argv;
709     net_test(&p);
710 }
711 #endif