1 /* This is a small demo of the high-performance NetX Duo TCP/IP stack.
2 This program demonstrates ICMPv6 protocols Neighbor Discovery and
3 Stateless Address Configuration for IPv6, ARP for IPv4, and
4 TCP packet sending and receiving with a simulated Ethernet driver. */
5
6
7 #include "tx_api.h"
8 #include "nx_api.h"
9
10 #define DEMO_STACK_SIZE 2048
11 #define DEMO_DATA "ABCDEFGHIJKLMNOPQRSTUVWXYZ "
12 #define PACKET_SIZE 1536
13 #define POOL_SIZE ((sizeof(NX_PACKET) + PACKET_SIZE) * 16)
14
15
16 /* Define the ThreadX and NetX object control blocks... */
17
18 TX_THREAD thread_0;
19 TX_THREAD thread_1;
20
21 NX_PACKET_POOL pool_0;
22 NX_IP ip_0;
23 NX_IP ip_1;
24 NX_TCP_SOCKET client_socket;
25 NX_TCP_SOCKET server_socket;
26 UCHAR pool_buffer[POOL_SIZE];
27
28
29
30 /* Define the counters used in the demo application... */
31
32 ULONG thread_0_counter;
33 ULONG thread_1_counter;
34 ULONG error_counter;
35
36
37 /* Define thread prototypes. */
38
39 void thread_0_entry(ULONG thread_input);
40 void thread_1_entry(ULONG thread_input);
41 void thread_1_connect_received(NX_TCP_SOCKET *server_socket, UINT port);
42 void thread_1_disconnect_received(NX_TCP_SOCKET *server_socket);
43
44 void _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req);
45
46
47 /* Define main entry point. */
48
main()49 int main()
50 {
51
52 /* Enter the ThreadX kernel. */
53 tx_kernel_enter();
54 }
55
56
57 /* Define what the initial system looks like. */
58
tx_application_define(void * first_unused_memory)59 void tx_application_define(void *first_unused_memory)
60 {
61
62 CHAR *pointer;
63 UINT status;
64
65 #ifndef NX_DISABLE_IPV6
66 NXD_ADDRESS ip_address;
67 #endif
68 /* Setup the working pointer. */
69 pointer = (CHAR *)first_unused_memory;
70
71 /* Create the main thread. */
72 tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,
73 pointer, DEMO_STACK_SIZE,
74 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
75
76 pointer = pointer + DEMO_STACK_SIZE;
77
78 /* Create the main thread. */
79 tx_thread_create(&thread_1, "thread 1", thread_1_entry, 0,
80 pointer, DEMO_STACK_SIZE,
81 3, 3, TX_NO_TIME_SLICE, TX_AUTO_START);
82
83 pointer = pointer + DEMO_STACK_SIZE;
84
85
86 /* Initialize the NetX system. */
87 nx_system_initialize();
88
89 /* Create a packet pool. */
90 status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", PACKET_SIZE, pool_buffer, POOL_SIZE);
91
92 if (status)
93 {
94 error_counter++;
95 }
96
97 /* Create an IP instance. */
98 status = nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(1, 2, 3, 4), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver,
99 pointer, 2048, 1);
100 pointer = pointer + 2048;
101
102 /* Create another IP instance. */
103 status += nx_ip_create(&ip_1, "NetX IP Instance 1", IP_ADDRESS(1, 2, 3, 5), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver,
104 pointer, 2048, 1);
105 pointer = pointer + 2048;
106
107 if (status)
108 {
109 error_counter++;
110 }
111
112 #ifndef NX_DISABLE_IPV4
113 /* Enable ARP and supply ARP cache memory for IP Instance 0. */
114 status = nx_arp_enable(&ip_0, (void *)pointer, 1024);
115 pointer = pointer + 1024;
116
117 /* Enable ARP and supply ARP cache memory for IP Instance 1. */
118 status += nx_arp_enable(&ip_1, (void *)pointer, 1024);
119 pointer = pointer + 1024;
120
121 /* Check ARP enable status. */
122 if (status)
123 {
124 error_counter++;
125 }
126 #endif /* NX_DISABLE_IPV4 */
127 #ifndef NX_DISABLE_IPV6
128
129 /* Enable IPv6 */
130 status = nxd_ipv6_enable(&ip_0);
131 if (status)
132 {
133 error_counter++;
134 }
135
136 status = nxd_ipv6_enable(&ip_1);
137 if (status)
138 {
139 error_counter++;
140 }
141 #endif
142
143 /* Enable ICMP */
144 status = nxd_icmp_enable(&ip_0);
145 if (status)
146 {
147 error_counter++;
148 }
149
150 status = nxd_icmp_enable(&ip_1);
151 if (status)
152 {
153 error_counter++;
154 }
155
156
157 /* Enable TCP processing for both IP instances. */
158 status = nx_tcp_enable(&ip_0);
159 status += nx_tcp_enable(&ip_1);
160
161 #ifndef NX_DISABLE_IPV6
162 /* Set ip_0 interface address. */
163 ip_address.nxd_ip_version = NX_IP_VERSION_V6;
164 ip_address.nxd_ip_address.v6[0] = 0x20010000;
165 ip_address.nxd_ip_address.v6[1] = 0;
166 ip_address.nxd_ip_address.v6[2] = 0;
167 ip_address.nxd_ip_address.v6[3] = 1;
168
169 status = nxd_ipv6_global_address_set(&ip_0, &ip_address, 64);
170 if (status)
171 {
172 error_counter++;
173 }
174
175 /* Set ip_0 interface address. */
176 ip_address.nxd_ip_version = NX_IP_VERSION_V6;
177 ip_address.nxd_ip_address.v6[0] = 0x20010000;
178 ip_address.nxd_ip_address.v6[1] = 0;
179 ip_address.nxd_ip_address.v6[2] = 0;
180 ip_address.nxd_ip_address.v6[3] = 2;
181
182 status = nxd_ipv6_global_address_set(&ip_1, &ip_address, 64);
183
184 if (status)
185 {
186 error_counter++;
187 }
188
189 /* Note we are not setting the link local address. The ram driver
190 does not use physical addresses so it is unnecessary. Consult the
191 NetX Duo User Guide for setting the link local address. */
192 #endif
193 }
194
195
196
197 /* Define the test threads. */
198
thread_0_entry(ULONG thread_input)199 void thread_0_entry(ULONG thread_input)
200 {
201
202 UINT status;
203 NX_PACKET *my_packet;
204 ULONG length;
205
206 #ifndef NX_DISABLE_IPV4
207 NXD_ADDRESS server_ipv4_address;
208 #endif /* NX_DISABLE_IPV4 */
209 #ifndef NX_DISABLE_IPV6
210 NXD_ADDRESS server_ipv6_address;
211 #endif
212 NXD_ADDRESS peer_address;
213 ULONG peer_port;
214
215 NX_PARAMETER_NOT_USED(thread_input);
216
217 #ifndef NX_DISABLE_IPV6
218
219 /* Wait 5 seconds for the IP thread to finish its initilization and
220 for the IPv6 stack to finish DAD process. */
221 tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
222
223 #else
224 /* Wait 1 second for the IP thread to finish its initilization. */
225 tx_thread_sleep(NX_IP_PERIODIC_RATE);
226 #endif
227
228 #ifndef NX_DISABLE_IPV4
229 /* set the TCP server addresses. */
230 server_ipv4_address.nxd_ip_version = NX_IP_VERSION_V4;
231 server_ipv4_address.nxd_ip_address.v4 = IP_ADDRESS(1, 2, 3, 5);
232 #endif /* NX_DISABLE_IPV4 */
233
234 #ifndef NX_DISABLE_IPV6
235
236 server_ipv6_address.nxd_ip_version = NX_IP_VERSION_V6;
237 server_ipv6_address.nxd_ip_address.v6[0] = 0x20010000;
238 server_ipv6_address.nxd_ip_address.v6[1] = 0;
239 server_ipv6_address.nxd_ip_address.v6[2] = 0;
240 server_ipv6_address.nxd_ip_address.v6[3] = 2;
241 #endif
242 /* Loop to repeat things over and over again! */
243 while (1)
244 {
245
246 /* Create a socket. */
247 status = nx_tcp_socket_create(&ip_0, &client_socket, "Client Socket",
248 NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 200,
249 NX_NULL, NX_NULL);
250
251 /* Check for error. */
252 if (status)
253 {
254 error_counter++;
255 }
256
257 /* Bind the socket. */
258 status = nx_tcp_client_socket_bind(&client_socket, 12, NX_WAIT_FOREVER);
259
260 /* Check for error. */
261 if (status)
262 {
263 error_counter++;
264 }
265
266 /* Attempt to connect the socket. */
267 #ifndef NX_DISABLE_IPV6
268 #ifndef NX_DISABLE_IPV4
269 /* In this demo, we alternate between IPv4 connections and IPv6 connections. */
270 if (thread_0_counter & 1)
271 {
272 status = nxd_tcp_client_socket_connect(&client_socket, &server_ipv4_address, 12, NX_IP_PERIODIC_RATE);
273 }
274 else
275 #endif /* NX_DISABLE_IPV4 */
276 {
277 status = nxd_tcp_client_socket_connect(&client_socket, &server_ipv6_address, 12, NX_IP_PERIODIC_RATE);
278 }
279 #else
280 status = nxd_tcp_client_socket_connect(&client_socket, &server_ipv4_address, 12, NX_IP_PERIODIC_RATE);
281 #endif
282
283 /* Check for error. */
284 if (status)
285 {
286 printf("Error with socket connect: 0x%x\n", status);
287 return;
288 }
289
290 status = nxd_tcp_socket_peer_info_get(&client_socket, &peer_address, &peer_port);
291
292 /* Allocate a packet. */
293 status = nx_packet_allocate(&pool_0, &my_packet, NX_TCP_PACKET, NX_WAIT_FOREVER);
294
295 /* Check status. */
296 if (status != NX_SUCCESS)
297 {
298 break;
299 }
300
301 /* Write ABCs into the packet payload! */
302 nx_packet_data_append(my_packet, DEMO_DATA, sizeof(DEMO_DATA), &pool_0, TX_WAIT_FOREVER);
303
304 status = nx_packet_length_get(my_packet, &length);
305 if ((status) || (length != sizeof(DEMO_DATA)))
306 {
307 error_counter++;
308 }
309
310 /* Send the packet out! */
311 status = nx_tcp_socket_send(&client_socket, my_packet, NX_IP_PERIODIC_RATE);
312
313 /* Determine if the status is valid. */
314 if (status)
315 {
316 error_counter++;
317 nx_packet_release(my_packet);
318 }
319
320 /* Disconnect this socket. */
321 status = nx_tcp_socket_disconnect(&client_socket, NX_IP_PERIODIC_RATE);
322
323 /* Determine if the status is valid. */
324 if (status)
325 {
326 error_counter++;
327 }
328
329 /* Unbind the socket. */
330 status = nx_tcp_client_socket_unbind(&client_socket);
331
332 /* Check for error. */
333 if (status)
334 {
335 error_counter++;
336 }
337
338 /* Delete the socket. */
339 status = nx_tcp_socket_delete(&client_socket);
340
341 /* Check for error. */
342 if (status)
343 {
344 error_counter++;
345 }
346
347 /* Increment thread 0's counter. */
348 thread_0_counter++;
349 }
350 }
351
352
thread_1_entry(ULONG thread_input)353 void thread_1_entry(ULONG thread_input)
354 {
355
356 UINT status;
357 NX_PACKET *packet_ptr;
358 ULONG actual_status;
359
360 NX_PARAMETER_NOT_USED(thread_input);
361
362 #ifndef NX_DISABLE_IPV6
363
364 /* Wait 5 seconds for the IP thread to finish its initilization and
365 for the IPv6 stack to finish DAD process. */
366 tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
367
368 #else
369 /* Wait 1 second for the IP thread to finish its initilization. */
370 tx_thread_sleep(NX_IP_PERIODIC_RATE);
371 #endif
372
373
374 /* Ensure the IP instance has been initialized. */
375 status = nx_ip_status_check(&ip_1, NX_IP_INITIALIZE_DONE, &actual_status, NX_IP_PERIODIC_RATE);
376
377 /* Check status... */
378 if (status != NX_SUCCESS)
379 {
380
381 error_counter++;
382 return;
383 }
384
385 /* Create a socket. */
386 status = nx_tcp_socket_create(&ip_1, &server_socket, "Server Socket",
387 NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 100,
388 NX_NULL, thread_1_disconnect_received);
389
390 /* Check for error. */
391 if (status)
392 {
393 error_counter++;
394 }
395
396 /* Setup this thread to listen. */
397 status = nx_tcp_server_socket_listen(&ip_1, 12, &server_socket, 5, thread_1_connect_received);
398
399 /* Check for error. */
400 if (status)
401 {
402 error_counter++;
403 }
404
405 /* Loop to create and establish server connections. */
406 while (1)
407 {
408
409 /* Increment thread 1's counter. */
410 thread_1_counter++;
411
412 /* Accept a client socket connection. */
413 status = nx_tcp_server_socket_accept(&server_socket, NX_WAIT_FOREVER);
414
415 /* Check for error. */
416 if (status)
417 {
418 error_counter++;
419 }
420
421 /* Receive a TCP message from the socket. */
422 status = nx_tcp_socket_receive(&server_socket, &packet_ptr, NX_IP_PERIODIC_RATE);
423
424 /* Check for error. */
425 if (status)
426 {
427 error_counter++;
428 }
429 else
430 {
431 /* Release the packet. */
432 nx_packet_release(packet_ptr);
433 }
434
435 /* Disconnect the server socket. */
436 status = nx_tcp_socket_disconnect(&server_socket, NX_IP_PERIODIC_RATE);
437
438 /* Check for error. */
439 if (status)
440 {
441 error_counter++;
442 }
443
444 /* Unaccept the server socket. */
445 status = nx_tcp_server_socket_unaccept(&server_socket);
446
447 /* Check for error. */
448 if (status)
449 {
450 error_counter++;
451 }
452
453 /* Setup server socket for listening again. */
454 status = nx_tcp_server_socket_relisten(&ip_1, 12, &server_socket);
455
456 /* Check for error. */
457 if (status)
458 {
459 error_counter++;
460 }
461 }
462 }
463
464
thread_1_connect_received(NX_TCP_SOCKET * socket_ptr,UINT port)465 void thread_1_connect_received(NX_TCP_SOCKET *socket_ptr, UINT port)
466 {
467
468 /* Check for the proper socket and port. */
469 if ((socket_ptr != &server_socket) || (port != 12))
470 {
471 error_counter++;
472 }
473 }
474
475
thread_1_disconnect_received(NX_TCP_SOCKET * socket)476 void thread_1_disconnect_received(NX_TCP_SOCKET *socket)
477 {
478
479 /* Check for proper disconnected socket. */
480 if (socket != &server_socket)
481 {
482 error_counter++;
483 }
484 }
485
486