1 /* This is a small demo of the high-performance NetX Duo TCP/IP stack. This program demonstrates
2 ICMPv6 protocols Neighbor Discovery and Stateless Address Configuration for IPv6, ARP for IPv4, and
3 UDP packet sending and receiving with a simulated Ethernet driver. */
4
5 #include "tx_api.h"
6 #include "nx_api.h"
7
8 #define DEMO_STACK_SIZE 2048
9 #define DEMO_DATA "ABCDEFGHIJKLMNOPQRSTUVWXYZ "
10 #define PACKET_SIZE 1536
11 #define POOL_SIZE ((sizeof(NX_PACKET) + PACKET_SIZE) * 16)
12
13
14 /* Define the ThreadX and NetX object control blocks... */
15
16 TX_THREAD thread_0;
17 TX_THREAD thread_1;
18
19 NX_PACKET_POOL pool_0;
20 NX_IP ip_0;
21 NX_IP ip_1;
22
23
24 NX_UDP_SOCKET socket_0;
25 NX_UDP_SOCKET socket_1;
26 UCHAR pool_buffer[POOL_SIZE];
27
28
29 /* Define the counters used in the demo application... */
30
31 ULONG thread_0_counter;
32 ULONG thread_1_counter;
33 ULONG error_counter;
34
35 /* Define thread prototypes. */
36
37 void thread_0_entry(ULONG thread_input);
38 void thread_1_entry(ULONG thread_input);
39 void _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req);
40
41
42 /* Define main entry point. */
43
main()44 int main()
45 {
46
47 /* Enter the ThreadX kernel. */
48 tx_kernel_enter();
49 }
50
51
52 /* Define what the initial system looks like. */
53
tx_application_define(void * first_unused_memory)54 void tx_application_define(void *first_unused_memory)
55 {
56
57 CHAR *pointer;
58 UINT status;
59
60 #ifndef NX_DISABLE_IPV6
61 NXD_ADDRESS ip_address;
62 #endif
63 /* Setup the working pointer. */
64 pointer = (CHAR *)first_unused_memory;
65
66 /* Create the main thread. */
67 tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,
68 pointer, DEMO_STACK_SIZE,
69 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
70 pointer = pointer + DEMO_STACK_SIZE;
71
72 /* . */
73 tx_thread_create(&thread_1, "thread 1", thread_1_entry, 0,
74 pointer, DEMO_STACK_SIZE,
75 3, 3, TX_NO_TIME_SLICE, TX_AUTO_START);
76 pointer = pointer + DEMO_STACK_SIZE;
77
78 /* Initialize the NetX system. */
79 nx_system_initialize();
80
81 /* Create a packet pool. */
82 status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", PACKET_SIZE, pool_buffer, POOL_SIZE);
83
84 /* Check for pool creation error. */
85 if (status)
86 {
87 error_counter++;
88 }
89
90 /* Create an IP instance. */
91 status = nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(1, 2, 3, 4), 0xFFFFF000UL, &pool_0, _nx_ram_network_driver,
92 pointer, 2048, 1);
93 pointer = pointer + 2048;
94
95 /* Create another IP instance. */
96 status += nx_ip_create(&ip_1, "NetX IP Instance 1", IP_ADDRESS(1, 2, 3, 5), 0xFFFFF000UL, &pool_0, _nx_ram_network_driver,
97 pointer, 2048, 1);
98 pointer = pointer + 2048;
99
100 /* Check for IP create errors. */
101 if (status)
102 {
103 error_counter++;
104 }
105
106 #ifndef NX_DISABLE_IPV4
107 /* Enable ARP and supply ARP cache memory for IP Instance 0. */
108 status = nx_arp_enable(&ip_0, (void *)pointer, 1024);
109 pointer = pointer + 1024;
110
111 /* Enable ARP and supply ARP cache memory for IP Instance 1. */
112 status += nx_arp_enable(&ip_1, (void *)pointer, 1024);
113 pointer = pointer + 1024;
114
115 /* Check for ARP enable errors. */
116 if (status)
117 {
118 error_counter++;
119 }
120 #endif /* NX_DISABLE_IPV4 */
121
122 #ifndef NX_DISABLE_IPV6
123
124 /* Enable IPv6 */
125 status = nxd_ipv6_enable(&ip_0);
126 if (status)
127 {
128 error_counter++;
129 }
130
131 status = nxd_ipv6_enable(&ip_1);
132 if (status)
133 {
134 error_counter++;
135 }
136 #endif
137
138 /* Enable ICMP */
139 status = nxd_icmp_enable(&ip_0);
140 if (status)
141 {
142 error_counter++;
143 }
144
145 status = nxd_icmp_enable(&ip_1);
146 if (status)
147 {
148 error_counter++;
149 }
150
151 /* Enable UDP traffic. */
152 status = nx_udp_enable(&ip_0);
153 status += nx_udp_enable(&ip_1);
154
155 /* Check for UDP enable errors. */
156 if (status)
157 {
158 error_counter++;
159 }
160 #ifndef NX_DISABLE_IPV6
161
162 /* Set ip_0 global address 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 if (status)
169 {
170 error_counter++;
171 }
172
173 status = nxd_ipv6_global_address_set(&ip_0, &ip_address, 64);
174
175 /* Check for errors */
176 if (status)
177 {
178 error_counter++;
179 }
180
181 /* Set ip_1 global address address. */
182 ip_address.nxd_ip_version = NX_IP_VERSION_V6;
183 ip_address.nxd_ip_address.v6[0] = 0x20010000;
184 ip_address.nxd_ip_address.v6[1] = 0;
185 ip_address.nxd_ip_address.v6[2] = 0;
186 ip_address.nxd_ip_address.v6[3] = 2;
187
188 status = nxd_ipv6_global_address_set(&ip_1, &ip_address, 64);
189
190 /* Check for errors */
191 if (status)
192 {
193 error_counter++;
194 }
195
196 /* Note we are not setting the link local address. The ram driver
197 does not use physical addresses so it is unnecessary. Consult the
198 NetX Duo User Guide for setting the link local address. */
199 #endif
200 }
201
202
203
204 /* Define the test threads. */
205
thread_0_entry(ULONG thread_input)206 void thread_0_entry(ULONG thread_input)
207 {
208
209 UINT status;
210 NX_PACKET *my_packet;
211
212 #ifndef NX_DISABLE_IPV4
213 NXD_ADDRESS ipv4_address;
214 #endif /* NX_DISABLE_IPV4 */
215 #ifndef NX_DISABLE_IPV6
216 NXD_ADDRESS ipv6_address;
217 #endif
218
219 NX_PARAMETER_NOT_USED(thread_input);
220
221 /* Let the IP threads and thread 1 execute. */
222 tx_thread_sleep(NX_IP_PERIODIC_RATE);
223
224 #ifndef NX_DISABLE_IPV6
225
226 /* Wait for IPv6 stack to finish DAD process. */
227 tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
228 #endif
229
230 #ifndef NX_DISABLE_IPV4
231 ipv4_address.nxd_ip_version = NX_IP_VERSION_V4;
232 ipv4_address.nxd_ip_address.v4 = IP_ADDRESS(1, 2, 3, 5);
233 #endif /* NX_DISABLE_IPV4 */
234
235 #ifndef NX_DISABLE_IPV6
236
237 ipv6_address.nxd_ip_version = NX_IP_VERSION_V6;
238 ipv6_address.nxd_ip_address.v6[0] = 0x20010000;
239 ipv6_address.nxd_ip_address.v6[1] = 0;
240 ipv6_address.nxd_ip_address.v6[2] = 0;
241 ipv6_address.nxd_ip_address.v6[3] = 2;
242 #endif
243
244 /* Create a UDP socket. */
245 status = nx_udp_socket_create(&ip_0, &socket_0, "Socket 0", NX_IP_NORMAL, NX_FRAGMENT_OKAY, 0x80, 5);
246
247 /* Check status. */
248 if (status)
249 {
250 error_counter++;
251 return;
252 }
253
254 /* Bind the UDP socket to the IP port. */
255 status = nx_udp_socket_bind(&socket_0, 0x88, TX_WAIT_FOREVER);
256
257 /* Check status. */
258 if (status)
259 {
260 error_counter++;
261 return;
262 }
263
264 /* Disable checksum logic for this socket. */
265 nx_udp_socket_checksum_disable(&socket_0);
266
267 /* Setup the ARP entry for the UDP send. */
268 nx_arp_dynamic_entry_set(&ip_0, IP_ADDRESS(1, 2, 3, 5), 0, 0);
269
270 while (1)
271 {
272
273
274 /* Allocate a packet. */
275 status = nx_packet_allocate(&pool_0, &my_packet, NX_UDP_PACKET, TX_WAIT_FOREVER);
276
277 /* Check status. */
278 if (status != NX_SUCCESS)
279 {
280 break;
281 }
282
283 /* Write ABCs into the packet payload! */
284 nx_packet_data_append(my_packet, DEMO_DATA, sizeof(DEMO_DATA), &pool_0, TX_WAIT_FOREVER);
285
286 /* Send the UDP packet. */
287 #ifndef NX_DISABLE_IPV6
288
289 #ifndef NX_DISABLE_IPV4
290 /* In this demo, we alternate between IPv4 connections and IPv6 connections. */
291 if (thread_0_counter & 1)
292 {
293 status = nxd_udp_socket_send(&socket_0, my_packet, &ipv4_address, 0x89);
294 }
295 else
296 #endif /* NX_DISABLE_IPV4 */
297 {
298 status = nxd_udp_socket_send(&socket_0, my_packet, &ipv6_address, 0x89);
299 }
300 #else
301 status = nxd_udp_socket_send(&socket_0, my_packet, &ipv4_address, 0x89);
302 #endif
303
304 /* Check status. */
305 if (status != NX_SUCCESS)
306 {
307 error_counter++;
308 break;
309 }
310
311 /* Increment thread 0's counter. */
312 thread_0_counter++;
313 }
314 }
315
316
thread_1_entry(ULONG thread_input)317 void thread_1_entry(ULONG thread_input)
318 {
319
320 UINT status;
321 NX_PACKET *my_packet;
322
323 NX_PARAMETER_NOT_USED(thread_input);
324
325 tx_thread_sleep(NX_IP_PERIODIC_RATE);
326 #ifndef NX_DISABLE_IPV6
327 /* Wait 5 seconds for IPv6 stack to finish DAD process. */
328 tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
329 #endif
330 /* Create a UDP socket. */
331 status = nx_udp_socket_create(&ip_1, &socket_1, "Socket 1", NX_IP_NORMAL, NX_FRAGMENT_OKAY, 0x80, 5);
332
333 /* Check status. */
334 if (status)
335 {
336 error_counter++;
337 return;
338 }
339
340 /* Bind the UDP socket to the IP port. */
341 status = nx_udp_socket_bind(&socket_1, 0x89, TX_WAIT_FOREVER);
342
343 /* Check status. */
344 if (status)
345 {
346 error_counter++;
347 return;
348 }
349
350 while (1)
351 {
352
353
354 /* Receive a UDP packet. */
355 status = nx_udp_socket_receive(&socket_1, &my_packet, TX_WAIT_FOREVER);
356
357 /* Check status. */
358 if (status != NX_SUCCESS)
359 {
360 break;
361 }
362
363 /* Release the packet. */
364 status = nx_packet_release(my_packet);
365
366 /* Check status. */
367 if (status != NX_SUCCESS)
368 {
369 break;
370 }
371
372 /* Increment thread 1's counter. */
373 thread_1_counter++;
374 }
375 }
376
377