1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
|
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="Mozilla/4.7 [en] (X11; I; Linux 2.2.14 ppc) [Netscape]">
</head>
<body>
<center>
<h1>
Sample Networking Program</h1></center>
<p><br>This example is derived from the test program <tt>".../net/tcpip/v1_3_1/tests/ping_test.c"</tt>.
<br>
<blockquote><tt><font size=-1>//==========================================================================</font></tt>
<br><tt><font size=-1>//</font></tt>
<br><tt><font size=-1>// tests/ping_test.c</font></tt>
<br><tt><font size=-1>//</font></tt>
<br><tt><font size=-1>// Simple test of PING
(ICMP) and networking support</font></tt>
<br><tt><font size=-1>//</font></tt>
<br><tt><font size=-1>//==========================================================================</font></tt>
<br><tt><font size=-1>//==========================================================================</font></tt>
<br><tt><font size=-1>//#####DESCRIPTIONBEGIN####</font></tt>
<br><tt><font size=-1>//</font></tt>
<br><tt><font size=-1>// Author(s): gthomas</font></tt>
<br><tt><font size=-1>// Contributors: gthomas</font></tt>
<br><tt><font size=-1>// Date:
2000-01-10</font></tt>
<br><tt><font size=-1>// Purpose:</font></tt>
<br><tt><font size=-1>// Description:</font></tt>
<br><tt><font size=-1>//</font></tt>
<br><tt><font size=-1>//</font></tt>
<br><tt><font size=-1>//####DESCRIPTIONEND####</font></tt>
<br><tt><font size=-1>//</font></tt>
<br><tt><font size=-1>//==========================================================================</font></tt><tt><font size=-1></font></tt>
<p><tt><font size=-1>// PING test code</font></tt><b><tt><font size=-1></font></tt></b>
<p><b><tt><font size=-1>#include <network.h></font></tt></b></blockquote>
This single include directive is all that is required to pick up the networking
support, including complete configuration information.
<blockquote><tt><font size=-1>#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL</font></tt>
<br><tt><font size=-1>static char stack[STACK_SIZE];</font></tt>
<br><tt><font size=-1>static cyg_thread thread_data;</font></tt>
<br><tt><font size=-1>static cyg_handle_t thread_handle;</font></tt><tt><font size=-1></font></tt>
<p><tt><font size=-1>#define NUM_PINGS 16</font></tt>
<br><tt><font size=-1>#define MAX_PACKET 4096</font></tt>
<br><tt><font size=-1>static unsigned char pkt1[MAX_PACKET], pkt2[MAX_PACKET];</font></tt><tt><font size=-1></font></tt>
<p><tt><font size=-1>#define UNIQUEID 0x1234</font></tt><tt><font size=-1></font></tt>
<p><tt><font size=-1>void</font></tt>
<br><tt><font size=-1>cyg_test_exit(void)</font></tt>
<br><tt><font size=-1>{</font></tt>
<br><tt><font size=-1> diag_printf("... Done\n");</font></tt>
<br><tt><font size=-1> while (1) ;</font></tt>
<br><tt><font size=-1>}</font></tt><tt><font size=-1></font></tt>
<p><tt><font size=-1>void</font></tt>
<br><tt><font size=-1>pexit(char *s)</font></tt>
<br><tt><font size=-1>{</font></tt>
<br><tt><font size=-1> perror(s);</font></tt>
<br><tt><font size=-1> cyg_test_exit();</font></tt>
<br><tt><font size=-1>}</font></tt><tt><font size=-1></font></tt>
<p><tt><font size=-1>// Compute INET checksum</font></tt>
<br><tt><font size=-1>int</font></tt>
<br><tt><font size=-1>inet_cksum(u_short *addr, int len)</font></tt>
<br><tt><font size=-1>{</font></tt>
<br><tt><font size=-1> register int nleft = len;</font></tt>
<br><tt><font size=-1> register u_short *w = addr;</font></tt>
<br><tt><font size=-1> register u_short answer;</font></tt>
<br><tt><font size=-1> register u_int sum = 0;</font></tt>
<br><tt><font size=-1> u_short odd_byte = 0;</font></tt><tt><font size=-1></font></tt>
<p><tt><font size=-1> /*</font></tt>
<br><tt><font size=-1> * Our algorithm is
simple, using a 32 bit accumulator (sum),</font></tt>
<br><tt><font size=-1> * we add sequential
16 bit words to it, and at the end, fold</font></tt>
<br><tt><font size=-1> * back all the carry
bits from the top 16 bits into the lower</font></tt>
<br><tt><font size=-1> * 16 bits.</font></tt>
<br><tt><font size=-1> */</font></tt>
<br><tt><font size=-1> while( nleft > 1 ) {</font></tt>
<br><tt><font size=-1> sum +=
*w++;</font></tt>
<br><tt><font size=-1> nleft
-= 2;</font></tt>
<br><tt><font size=-1> }</font></tt><tt><font size=-1></font></tt>
<p><tt><font size=-1> /* mop up an odd byte, if necessary
*/</font></tt>
<br><tt><font size=-1> if( nleft == 1 ) {</font></tt>
<br><tt><font size=-1> *(u_char
*)(&odd_byte) = *(u_char *)w;</font></tt>
<br><tt><font size=-1> sum +=
odd_byte;</font></tt>
<br><tt><font size=-1> }</font></tt><tt><font size=-1></font></tt>
<p><tt><font size=-1> /*</font></tt>
<br><tt><font size=-1> * add back carry outs from
top 16 bits to low 16 bits</font></tt>
<br><tt><font size=-1> */</font></tt>
<br><tt><font size=-1> sum = (sum >> 16) + (sum &
0x0000ffff); /* add hi 16 to low 16 */</font></tt>
<br><tt><font size=-1> sum += (sum >> 16);
/* add carry */</font></tt>
<br><tt><font size=-1> answer = ~sum;
/* truncate to 16 bits */</font></tt>
<br><tt><font size=-1> return (answer);</font></tt>
<br><tt><font size=-1>}</font></tt><tt><font size=-1></font></tt>
<p><tt><font size=-1>static int</font></tt>
<br><tt><font size=-1>show_icmp(unsigned char *pkt, int len,</font></tt>
<br><tt><font size=-1>
struct sockaddr_in *from, struct sockaddr_in *to)</font></tt>
<br><tt><font size=-1>{</font></tt>
<br><tt><font size=-1> cyg_tick_count_t *tp, tv;</font></tt>
<br><tt><font size=-1> struct ip *ip;</font></tt>
<br><tt><font size=-1> struct icmp *icmp;</font></tt>
<br><tt><font size=-1> tv = cyg_current_time();</font></tt>
<br><tt><font size=-1> ip = (struct ip *)pkt;</font></tt>
<br><tt><font size=-1> if ((len < sizeof(*ip)) ||
ip->ip_v != IPVERSION) {</font></tt>
<br><tt><font size=-1> diag_printf("%s:
Short packet or not IP! - Len: %d, Version: %d\n",</font></tt>
<br><tt><font size=-1>
inet_ntoa(from->sin_addr), len, ip->ip_v);</font></tt>
<br><tt><font size=-1> return
0;</font></tt>
<br><tt><font size=-1> }</font></tt>
<br><tt><font size=-1> icmp = (struct icmp *)(pkt + sizeof(*ip));</font></tt>
<br><tt><font size=-1> len -= (sizeof(*ip) + 8);</font></tt>
<br><tt><font size=-1> tp = (cyg_tick_count_t *)&icmp->icmp_data;</font></tt>
<br><tt><font size=-1> if (icmp->icmp_type != ICMP_ECHOREPLY)
{</font></tt>
<br><tt><font size=-1> diag_printf("%s:
Invalid ICMP - type: %d\n",</font></tt>
<br><tt><font size=-1>
inet_ntoa(from->sin_addr), icmp->icmp_type);</font></tt>
<br><tt><font size=-1> return
0;</font></tt>
<br><tt><font size=-1> }</font></tt>
<br><tt><font size=-1> if (icmp->icmp_id != UNIQUEID)
{</font></tt>
<br><tt><font size=-1> diag_printf("%s:
ICMP received for wrong id - sent: %x, recvd: %x\n",</font></tt>
<br><tt><font size=-1>
inet_ntoa(from->sin_addr), UNIQUEID, icmp->icmp_id);</font></tt>
<br><tt><font size=-1> }</font></tt>
<br><tt><font size=-1> diag_printf("%d bytes from %s:
", len, inet_ntoa(from->sin_addr));</font></tt>
<br><tt><font size=-1> diag_printf("icmp_seq=%d", icmp->icmp_seq);</font></tt>
<br><tt><font size=-1> diag_printf(", time=%dms\n", (int)(tv
- *tp)*10);</font></tt>
<br><tt><font size=-1> return (from->sin_addr.s_addr
== to->sin_addr.s_addr);</font></tt>
<br><tt><font size=-1>}</font></tt><tt><font size=-1></font></tt>
<p><tt><font size=-1>static void</font></tt>
<br><tt><font size=-1>ping_host(int s, struct sockaddr_in *host)</font></tt>
<br><tt><font size=-1>{</font></tt>
<br><tt><font size=-1> struct icmp *icmp = (struct icmp
*)pkt1;</font></tt>
<br><tt><font size=-1> int icmp_len = 64;</font></tt>
<br><tt><font size=-1> int seq, ok_recv, bogus_recv;</font></tt>
<br><tt><font size=-1> cyg_tick_count_t *tp;</font></tt>
<br><tt><font size=-1> long *dp;</font></tt>
<br><tt><font size=-1> struct sockaddr_in from;</font></tt>
<br><tt><font size=-1> int i, len, fromlen;</font></tt><tt><font size=-1></font></tt>
<p><tt><font size=-1> ok_recv = 0;</font></tt>
<br><tt><font size=-1> bogus_recv = 0;</font></tt>
<br><tt><font size=-1> diag_printf("PING server %s\n",
<b>inet_ntoa(host->sin_addr)</b>);</font></tt></blockquote>
This function takes an IP address and returns a string representation.
Useful for printing the address.
<blockquote><tt><font size=-1> for (seq = 0; seq
< NUM_PINGS; seq++) {</font></tt>
<br><tt><font size=-1> // Build
ICMP packet</font></tt>
<br><tt><font size=-1> icmp->icmp_type
= ICMP_ECHO;</font></tt>
<br><tt><font size=-1> icmp->icmp_code
= 0;</font></tt>
<br><tt><font size=-1> icmp->icmp_cksum
= 0;</font></tt>
<br><tt><font size=-1> icmp->icmp_seq
= seq;</font></tt>
<br><tt><font size=-1> icmp->icmp_id
= 0x1234;</font></tt>
<br><tt><font size=-1> // Set
up ping data</font></tt>
<br><tt><font size=-1> tp = (cyg_tick_count_t
*)&icmp->icmp_data;</font></tt>
<br><tt><font size=-1> *tp++
= cyg_current_time();</font></tt>
<br><tt><font size=-1> dp = (long
*)tp;</font></tt>
<br><tt><font size=-1> for (i
= sizeof(*tp); i < icmp_len; i += sizeof(*dp)) {</font></tt>
<br><tt><font size=-1>
*dp++ = i;</font></tt>
<br><tt><font size=-1> }</font></tt>
<br><tt><font size=-1> // Add
checksum</font></tt>
<br><tt><font size=-1> icmp->icmp_cksum
= inet_cksum( (u_short *)icmp, icmp_len+8);</font></tt>
<br><tt><font size=-1> // Send
it off</font></tt>
<br><tt><font size=-1> <b>if
(sendto(s, icmp, icmp_len+8, 0, (struct sockaddr *)host, sizeof(*host))
< 0) {</b></font></tt></blockquote>
This function sends a single packet, in this case via the ICMP protocol.
The destination address is specified by the <tt>host</tt> argument.
<blockquote><tt><font size=-1>
perror("sendto");</font></tt>
<br><tt><font size=-1>
continue;</font></tt>
<br><tt><font size=-1> }</font></tt>
<br><tt><font size=-1> // Wait
for a response</font></tt>
<br><tt><font size=-1> fromlen
= sizeof(from);</font></tt>
<br><tt><font size=-1> <b>len
= recvfrom(s, pkt2, sizeof(pkt2), 0, (struct sockaddr *)&from, &fromlen);</b></font></tt></blockquote>
This function waits for a packet to be sent to this interface. Note:
this operation can fail if no packet is received with a given amount of
time (this timeout value is setup in the <tt>ping_test()</tt> routine below).
<blockquote><tt><font size=-1>
if (len < 0) {</font></tt>
<br><tt><font size=-1>
perror("recvfrom");</font></tt>
<br><tt><font size=-1> } else
{</font></tt>
<br><tt><font size=-1>
if (show_icmp(pkt2, len, &from, host)) {</font></tt>
<br><tt><font size=-1>
ok_recv++;</font></tt>
<br><tt><font size=-1>
} else {</font></tt>
<br><tt><font size=-1>
bogus_recv++;</font></tt>
<br><tt><font size=-1>
}</font></tt>
<br><tt><font size=-1> }</font></tt>
<br><tt><font size=-1> }</font></tt>
<br><tt><font size=-1> diag_printf("Sent %d packets,
received %d OK, %d bad\n", NUM_PINGS, ok_recv, bogus_recv);</font></tt>
<br><tt><font size=-1>}</font></tt><tt><font size=-1></font></tt>
<p><tt><font size=-1>static void</font></tt>
<br><tt><font size=-1>ping_test(struct bootp *bp)</font></tt>
<br><tt><font size=-1>{</font></tt>
<br><tt><font size=-1> struct protoent *p;</font></tt>
<br><tt><font size=-1> struct timeval tv;</font></tt>
<br><tt><font size=-1> struct sockaddr_in host;</font></tt>
<br><tt><font size=-1> int s;</font></tt><tt><font size=-1></font></tt>
<p><tt><font size=-1> <b>if ((p = getprotobyname("icmp"))
== (struct protoent *)0) {</b></font></tt></blockquote>
This function gets information about the ICMP protocol. This will
be used below to set up the "socket" (the handle to a network connection).
<blockquote><tt><font size=-1>
perror("getprotobyname");</font></tt>
<br><tt><font size=-1> return;</font></tt>
<br><tt><font size=-1> }</font></tt>
<br><tt><font size=-1> <b>s = socket(AF_INET, SOCK_RAW,
p->p_proto);</b></font></tt></blockquote>
Create the socket "s". A socket is an abstract object (sometimes
called a handle or endpoint). Sockets come in many flavors, RAW sockets
are used for communicating with non-structured protocols. DATAGRAM
sockets are used for packet oriented protocols, such as UDP. STREAM
sockets are used for reliable, sequenced byte streams, such as those provided
by TCP.
<blockquote><tt><font size=-1> if (s < 0) {</font></tt>
<br><tt><font size=-1> perror("socket");</font></tt>
<br><tt><font size=-1> return;</font></tt>
<br><tt><font size=-1> }</font></tt>
<br><tt><font size=-1> tv.tv_sec = 1;</font></tt>
<br><tt><font size=-1> tv.tv_usec = 0;</font></tt>
<br><tt><font size=-1> <b>setsockopt(s, SOL_SOCKET, SO_RCVTIMEO,
&tv, sizeof(tv));</b></font></tt></blockquote>
This function instructs the system that receive operations (see <tt>ping_host()</tt>
above) must complete within 1 second or issue a timed out error condition.
<blockquote><tt><font size=-1> // Set up host address</font></tt>
<br><tt><font size=-1> host.sin_family = AF_INET;</font></tt>
<br><tt><font size=-1> host.sin_addr = bp->bp_siaddr;</font></tt>
<br><tt><font size=-1> host.sin_port = 0;</font></tt>
<br><tt><font size=-1> ping_host(s, &host);</font></tt>
<br><tt><font size=-1> // Now try a bogus host</font></tt>
<br><tt><font size=-1> host.sin_addr.s_addr = htonl(ntohl(host.sin_addr.s_addr)
+ 32);</font></tt>
<br><tt><font size=-1> ping_host(s, &host);</font></tt>
<br><tt><font size=-1>}</font></tt>
<br><tt><font size=-1></font></tt> </blockquote>
This function drives the test.
<blockquote><tt><font size=-1>void</font></tt>
<br><tt><font size=-1>net_test(cyg_addrword_t p)</font></tt>
<br><tt><font size=-1>{</font></tt>
<br><tt><font size=-1> diag_printf("Start PING test\n");</font></tt>
<br><tt><font size=-1> <b>init_all_network_interfaces();</b></font></tt></blockquote>
This is a call to the network initialization code. Note that it must
be executed from a thread context, thus we can't put it in the <tt>cyg_start()
</tt>function which follows. The <tt>init_all_network_interfaces()</tt>
routine will cause the networking system to be initialized and any hardware
interfaces will be set up. Using the system configuration information,
an interface can be started using either <b>BOOTP</b>, or a predefined
configuration with static IP information. It is also possible to
indicate that an interface will be configured by the user code, outside
of "<tt>init_all_network_interfaces()</tt>".
<br><tt><font size=-1> </font></tt>
<br><tt><font size=-1> #ifdef CYGHWR_NET_DRIVER_ETH0</font></tt>
<br><tt><font size=-1> if (eth0_up)
{</font></tt>
<blockquote><tt><font size=-1>
ping_test(&eth0_bootp_data);</font></tt>
<br><tt><font size=-1> }</font></tt>
<br><tt><font size=-1>#endif</font></tt></blockquote>
Notice that there is a BOOTP information structure kept about all hardware
interfaces. This is created and initialized by the call to <tt>init_all_network_interfaces()</tt>,
unless manual configuration is selected. This information can be
used by the application to learn things such as the local IP address, server
name, etc.
<blockquote><tt><font size=-1>#ifdef CYGHWR_NET_DRIVER_ETH1</font></tt>
<br><tt><font size=-1> if (eth1_up) {</font></tt>
<br><tt><font size=-1> ping_test(&eth1_bootp_data);</font></tt>
<br><tt><font size=-1> }</font></tt>
<br><tt><font size=-1>#endif</font></tt></blockquote>
Multiple hardware interfaces can be supported, depending on the hardware
platform. If the platform provides a single ethernet device then
<b><tt>CYGHWR_NET_DRIVER_ETH0 </tt></b>will be defined. If there
is a second interface, then will <b><tt>CYGHWR_NET_DRIVER_ETH1 </tt></b>be
defined.
<blockquote><tt><font size=-1> cyg_test_exit();</font></tt>
<br><tt><font size=-1>}</font></tt>
<br><tt><font size=-1></font></tt> </blockquote>
The following function creates an initial thread which runs the program.
This could just as easily be done by naming the <tt>net_test()</tt> function
<tt>main()</tt>.
<blockquote><tt><font size=-1>void</font></tt>
<br><tt><font size=-1>cyg_start(void)</font></tt>
<br><tt><font size=-1>{</font></tt>
<br><tt><font size=-1> // Create a main thread, so we
can run the scheduler and have time 'pass'</font></tt>
<br><tt><font size=-1> cyg_thread_create(10,
// Priority - just a number</font></tt>
<br><tt><font size=-1>
net_test, // entry</font></tt>
<br><tt><font size=-1>
0,
// entry parameter</font></tt>
<br><tt><font size=-1>
"Network test", // Name</font></tt>
<br><tt><font size=-1>
&stack[0], // Stack</font></tt>
<br><tt><font size=-1>
STACK_SIZE, // Size</font></tt>
<br><tt><font size=-1>
&thread_handle, // Handle</font></tt>
<br><tt><font size=-1>
&thread_data // Thread data structure</font></tt>
<br><tt><font size=-1>
);</font></tt>
<br><tt><font size=-1> cyg_thread_resume(thread_handle);
// Start it</font></tt>
<br><tt><font size=-1> cyg_scheduler_start();</font></tt>
<br><tt><font size=-1>}</font></tt></blockquote>
</body>
</html>
|