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