1 /* This is a small demo of TFTP on the high-performance NetX TCP/IP stack.  This demo
2    relies on ThreadX and NetX , to show a simple file transfer from the client
3    and then back to the server.  */
4 
5 /* Indicate if using a NetX TFTP services. To port a NetX TFTP application to NetX TFTP
6    undefine this term.  */
7 
8 
9 #include    "tx_api.h"
10 #include    "nx_api.h"
11 #include    "nxd_tftp_client.h"
12 #include    "nxd_tftp_server.h"
13 #ifndef     NX_TFTP_NO_FILEX
14 #include    "fx_api.h"
15 #endif
16 
17 
18 #define USE_DUO
19 
20 /* If the host application is using NetX Duo, determine which IP version to use.
21    Make sure IPv6 in NetX Duo is enabled if planning to use TFTP over IPv6 */
22 #ifdef USE_DUO
23 #define     IP_TYPE     6
24 #endif /* USE_DUO        */
25 
26 #define     DEMO_STACK_SIZE         4096
27 #define     DEMO_DATA               "ABCDEFGHIJKLMNOPQRSTUVWXYZ "
28 
29 /* To use another file storage utility define this symbol:
30 #define NX_TFTP_NO_FILEX
31 */
32 
33 /* Define the ThreadX, NetX, and FileX object control blocks...  */
34 
35 TX_THREAD               server_thread;
36 TX_THREAD               client_thread;
37 NX_PACKET_POOL          server_pool;
38 NX_IP                   server_ip;
39 NX_PACKET_POOL          client_pool;
40 NX_IP                   client_ip;
41 FX_MEDIA                ram_disk;
42 
43 /* Define the NetX TFTP object control blocks.  */
44 
45 NX_TFTP_CLIENT          client;
46 NX_TFTP_SERVER          server;
47 
48 /* Define the application global variables */
49 
50 #define                 CLIENT_ADDRESS  IP_ADDRESS(1, 2, 3, 5)
51 #define                 SERVER_ADDRESS  IP_ADDRESS(1, 2, 3, 4)
52 
53 NXD_ADDRESS             server_ip_address;
54 NXD_ADDRESS             client_ip_address;
55 
56 UINT                    error_counter = 0;
57 
58 /* Define buffer used in the demo application.  */
59 UCHAR                   buffer[255];
60 ULONG                   data_length;
61 
62 
63 /* Define the memory area for the FileX RAM disk.  */
64 #ifndef NX_TFTP_NO_FILEX
65 UCHAR                   ram_disk_memory[32000];
66 UCHAR                   ram_disk_sector_cache[512];
67 #endif
68 
69 
70 /* Define function prototypes.  */
71 
72 VOID    _fx_ram_driver(FX_MEDIA *media_ptr);
73 VOID    _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr);
74 void    client_thread_entry(ULONG thread_input);
75 void    server_thread_entry(ULONG thread_input);
76 
77 
78 /* Define main entry point.  */
79 
main()80 int main()
81 {
82 
83     /* Enter the ThreadX kernel.  */
84     tx_kernel_enter();
85 }
86 
87 
88 /* Define what the initial system looks like.  */
89 
tx_application_define(void * first_unused_memory)90 void    tx_application_define(void *first_unused_memory)
91 {
92 
93 UINT    status;
94 UCHAR   *pointer;
95 
96 
97     /* Setup the working pointer.  */
98     pointer =  (UCHAR *) first_unused_memory;
99 
100 
101     /* Create the main TFTP server thread.  */
102     status = tx_thread_create(&server_thread, "TFTP Server Thread", server_thread_entry, 0,
103                               pointer, DEMO_STACK_SIZE,
104                               4,4, TX_NO_TIME_SLICE, TX_AUTO_START);
105 
106     pointer += DEMO_STACK_SIZE ;
107 
108     /* Check for errors.  */
109     if (status)
110         error_counter++;
111 
112 
113     /* Create the main TFTP client thread at a slightly lower priority.  */
114     status = tx_thread_create(&client_thread, "TFTP Client Thread", client_thread_entry, 0,
115                               pointer, DEMO_STACK_SIZE,
116                               5, 5, TX_NO_TIME_SLICE, TX_DONT_START);
117 
118     pointer += DEMO_STACK_SIZE ;
119 
120     /* Check for errors.  */
121     if (status)
122         error_counter++;
123 
124     /* Initialize the NetX system.  */
125     nx_system_initialize();
126 
127     /* Note: The data portion of a packet is exactly 512 bytes, but the packet payload size must
128        be at least 580 bytes. The remaining bytes are used for the UDP, IP, and Ethernet
129        headers and byte alignment requirements. */
130 
131     status =  nx_packet_pool_create(&server_pool, "TFTP Server Packet Pool", NX_TFTP_PACKET_SIZE, pointer, 8192);
132     pointer = pointer + 8192;
133 
134     /* Check for errors.  */
135     if (status)
136         error_counter++;
137 
138     /* Create the IP instance for the TFTP Server.  */
139     status = nx_ip_create(&server_ip, "NetX Server IP Instance", SERVER_ADDRESS, 0xFFFFFF00UL,
140                                         &server_pool, _nx_ram_network_driver, pointer, 2048, 1);
141     pointer = pointer + 2048;
142 
143     /* Check for errors.  */
144     if (status)
145         error_counter++;
146 
147 #ifndef NX_DISABLE_IPV4
148     /* Enable ARP and supply ARP cache memory for IP Instance 0.  */
149     status =  nx_arp_enable(&server_ip, (void *) pointer, 1024);
150     pointer = pointer + 1024;
151 
152     /* Check for errors.  */
153     if (status)
154         error_counter++;
155 #endif /* NX_DISABLE_IPV4  */
156 
157     /* Enable UDP.  */
158     status =  nx_udp_enable(&server_ip);
159 
160     /* Check for errors.  */
161     if (status)
162         error_counter++;
163 
164 
165     /* Create the TFTP server.  */
166 #ifdef USE_DUO
167 #if (IP_TYPE == 6)
168 #ifdef FEATURE_NX_IPV6
169     /* Specify the tftp server global address. */
170     server_ip_address.nxd_ip_version = NX_IP_VERSION_V6;
171     server_ip_address.nxd_ip_address.v6[0] = 0x20010db1;
172     server_ip_address.nxd_ip_address.v6[1] = 0xf101;
173     server_ip_address.nxd_ip_address.v6[2] = 0;
174     server_ip_address.nxd_ip_address.v6[3] = 0x102;
175 #endif
176 #else
177     server_ip_address.nxd_ip_version = NX_IP_VERSION_V4;
178     server_ip_address.nxd_ip_address.v4 = SERVER_ADDRESS;
179 
180 #endif
181 
182     status =  nxd_tftp_server_create(&server, "TFTP Server Instance", &server_ip, &ram_disk,
183                                       pointer, DEMO_STACK_SIZE, &server_pool);
184 #else
185     status =  nx_tftp_server_create(&server, "TFTP Server Instance", &server_ip, &ram_disk,
186                                       pointer, DEMO_STACK_SIZE, &server_pool);
187 #endif
188 
189     pointer =  pointer + DEMO_STACK_SIZE;
190 
191     /* Check for errors for the server.  */
192     if (status)
193         error_counter++;
194 
195     /* Create a packet pool for the TFTP client.  */
196 
197     /* Note: The data portion of a packet is exactly 512 bytes, but the packet payload size must
198        be at least 580 bytes. The remaining bytes are used for the UDP, IP, and Ethernet
199        headers and byte alignment requirements. */
200 
201     status =  nx_packet_pool_create(&client_pool, "TFTP Client Packet Pool", NX_TFTP_PACKET_SIZE, pointer, 8192);
202     pointer =  pointer + 8192;
203 
204     /* Create an IP instance for the TFTP client.  */
205     status = nx_ip_create(&client_ip, "TFTP Client IP Instance", CLIENT_ADDRESS, 0xFFFFFF00UL,
206                                                 &client_pool, _nx_ram_network_driver, pointer, 2048, 1);
207     pointer = pointer + 2048;
208 
209 #ifndef NX_DISABLE_IPV4
210     /* Enable ARP and supply ARP cache memory for IP Instance 1.  */
211     status =  nx_arp_enable(&client_ip, (void *) pointer, 1024);
212     pointer = pointer + 1024;
213 #endif /* NX_DISABLE_IPV4  */
214 
215     /* Enable UDP for client IP instance.  */
216     status =  nx_udp_enable(&client_ip);
217 
218     /* Check for errors.  */
219     if (status)
220         error_counter++;
221 
222     tx_thread_resume(&client_thread);
223 }
224 
server_thread_entry(ULONG thread_input)225 void server_thread_entry(ULONG thread_input)
226 {
227 
228 UINT        status, running;
229 #if (IP_TYPE == 6)
230 #ifdef FEATURE_NX_IPV6
231 UINT        address_index;
232 UINT        iface_index;
233 #endif
234 #endif
235 
236     NX_PARAMETER_NOT_USED(thread_input);
237 
238     /* Allow time for the network driver and NetX to get initialized. */
239     tx_thread_sleep(NX_IP_PERIODIC_RATE);
240 
241 #ifndef  NX_TFTP_NO_FILEX
242 
243     /* Format the RAM disk - the memory for the RAM disk was defined above.  */
244     status = fx_media_format(&ram_disk,
245                             _fx_ram_driver,                  /* Driver entry             */
246                             ram_disk_memory,                 /* RAM disk memory pointer  */
247                             ram_disk_sector_cache,           /* Media buffer pointer     */
248                             sizeof(ram_disk_sector_cache),   /* Media buffer size        */
249                             "MY_RAM_DISK",                   /* Volume Name              */
250                             1,                               /* Number of FATs           */
251                             32,                              /* Directory Entries        */
252                             0,                               /* Hidden sectors           */
253                             256,                             /* Total sectors            */
254                             128,                             /* Sector size              */
255                             1,                               /* Sectors per cluster      */
256                             1,                               /* Heads                    */
257                             1);                              /* Sectors per track        */
258 
259     /* Check for errors.  */
260     if (status != FX_SUCCESS)
261     {
262         return;
263     }
264 
265     /* Open the RAM disk.  */
266     status = fx_media_open(&ram_disk, "RAM DISK", _fx_ram_driver, ram_disk_memory, ram_disk_sector_cache, sizeof(ram_disk_sector_cache));
267 
268     /* Check for errors.  */
269     if (status != FX_SUCCESS)
270     {
271         return;
272     }
273 
274 #endif /*  NX_TFTP_NO_FILEX */
275 
276 #if (IP_TYPE == 6)
277 #ifdef FEATURE_NX_IPV6
278 
279     /* Enable ICMPv6 services. */
280     status |= nxd_icmp_enable(&server_ip);
281     if (status != NX_SUCCESS)
282     {
283         return;
284     }
285 
286     /* Enable IPv6 services for the server. */
287     status = nxd_ipv6_enable(&server_ip);
288     if (status != NX_SUCCESS)
289     {
290         return;
291     }
292 
293     /* This assumes the primary interface. See the NetX Duo
294        User Guide for more information on address configuration. */
295     iface_index = 0;
296     status = nxd_ipv6_address_set(&server_ip, iface_index, NX_NULL, 10, &address_index);
297     status += nxd_ipv6_address_set(&server_ip, iface_index, &server_ip_address, 64, &address_index);
298 
299     if (status != NX_SUCCESS)
300     {
301         return;
302     }
303 
304     /* Wait for DAD to validate the address. */
305     tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
306 #endif
307 
308 #endif /* IP_TYPE == 6 */
309 
310     /* Start the NetX TFTP server.  */
311 #ifdef USE_DUO
312     status =  nxd_tftp_server_start(&server);
313 #else
314     status =  nx_tftp_server_start(&server);
315 #endif
316 
317     /* Check for errors.  */
318     if (status)
319     {
320         error_counter++;
321         return;
322     }
323 
324     /* Run for a while */
325     running = NX_TRUE;
326     while(running)
327         tx_thread_sleep(NX_IP_PERIODIC_RATE);
328 
329 #ifdef USE_DUO
330     nxd_tftp_server_delete(&server);
331 #else
332     nx_tftp_server_delete(&server);
333 #endif
334 
335     /* Flush the media of changed file data, close all open files and ensure
336        directory information is also written out to the media.*/
337     status = fx_media_close(&ram_disk);
338     if (status)
339         error_counter++;
340 
341     return;
342 }
343 
344 /* Define the TFTP client thread.  */
345 
client_thread_entry(ULONG thread_input)346 void    client_thread_entry(ULONG thread_input)
347 {
348 
349 NX_PACKET   *my_packet;
350 UINT        status;
351 UINT        all_done = NX_FALSE;
352 #if (IP_TYPE == 6)
353 #ifdef FEATURE_NX_IPV6
354 UINT        address_index;
355 UINT        iface_index;
356 #endif
357 #endif
358 
359     NX_PARAMETER_NOT_USED(thread_input);
360 
361     /* Allow time for the network driver and NetX to get initialized. */
362     tx_thread_sleep(NX_IP_PERIODIC_RATE);
363 
364 #if (IP_TYPE == 6)
365 #ifdef FEATURE_NX_IPV6
366 
367     /* Enable ECMPv6 services for the client. */
368     status = nxd_icmp_enable(&client_ip);
369     if (status != NX_SUCCESS)
370     {
371         return;
372     }
373 
374     /* Enable IPv6 services for the client. */
375     status = nxd_ipv6_enable(&client_ip);
376     if (status != NX_SUCCESS)
377     {
378         return;
379     }
380 
381     /* Set the Client IPv6 address */
382     client_ip_address.nxd_ip_version = NX_IP_VERSION_V6;
383     client_ip_address.nxd_ip_address.v6[0] = 0x20010db1;
384     client_ip_address.nxd_ip_address.v6[1] = 0xf101;
385     client_ip_address.nxd_ip_address.v6[2] = 0;
386     client_ip_address.nxd_ip_address.v6[3] = 0x101;
387 
388     /* This assumes the primary interface. See the NetX Duo
389        User Guide for more information on address configuration. */
390     iface_index = 0;
391     status = nxd_ipv6_address_set(&client_ip, iface_index, NX_NULL, 10, &address_index);
392     status += nxd_ipv6_address_set(&client_ip, iface_index, &client_ip_address, 64, &address_index);
393 
394     if (status != NX_SUCCESS)
395     {
396         return;
397     }
398 
399     /* Wait for the link local and global addresses to be validated. */
400     tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
401 #endif
402 #endif /*(IP_TYPE == 6) */
403 
404 
405     /* The TFTP services used below include the NetX equivalent service which will work with
406        NetX Duo TFTP.  However, it is recommended for developers to port their applications
407        to the newer services that take the NXD_ADDRESS type and support both IPv4 and IPv6
408        communication.
409     */
410 
411     /* Create a TFTP client.  */
412 #ifdef USE_DUO
413     status =  nxd_tftp_client_create(&client, "TFTP Client", &client_ip, &client_pool, IP_TYPE);
414 #else
415     status =  nx_tftp_client_create(&client, "TFTP Client", &client_ip, &client_pool);
416 #endif
417 
418     /* Check status.  */
419     if (status)
420         return;
421 
422     /* Open a TFTP file for writing.  */
423 #ifdef USE_DUO
424     status =  nxd_tftp_client_file_open(&client, "test.txt", &server_ip_address, NX_TFTP_OPEN_FOR_WRITE, NX_IP_PERIODIC_RATE, IP_TYPE);
425 #else
426     status =  nx_tftp_client_file_open(&client, "test.txt", SERVER_ADDRESS, NX_TFTP_OPEN_FOR_WRITE, NX_IP_PERIODIC_RATE);
427 #endif
428 
429     /* Check status.  */
430     if (status)
431         return;
432 
433     /* Allocate a TFTP packet.  */
434 #ifdef USE_DUO
435     status =  nxd_tftp_client_packet_allocate(&client_pool, &my_packet, NX_IP_PERIODIC_RATE, IP_TYPE);
436 #else
437     status =  nx_tftp_client_packet_allocate(&client_pool, &my_packet, NX_IP_PERIODIC_RATE);
438 #endif
439     /* Check status.  */
440     if (status)
441         error_counter++;
442 
443     /* Write ABCs into the packet payload!  */
444     memcpy(my_packet -> nx_packet_prepend_ptr, DEMO_DATA, sizeof(DEMO_DATA)); /* Use case of memcpy is verified. */
445 
446     /* Adjust the write pointer.  */
447     my_packet -> nx_packet_length =  sizeof(DEMO_DATA);
448     my_packet -> nx_packet_append_ptr =  my_packet -> nx_packet_prepend_ptr + sizeof(DEMO_DATA);
449 
450     /* Write this packet to the file via TFTP.  */
451 #ifdef USE_DUO
452     status =  nxd_tftp_client_file_write(&client, my_packet, NX_IP_PERIODIC_RATE, IP_TYPE);
453 #else
454     status =  nx_tftp_client_file_write(&client, my_packet, NX_IP_PERIODIC_RATE);
455 #endif
456 
457     /* Check status.  */
458     if (status)
459         error_counter++;
460 
461     /* Close this file.  */
462 #ifdef USE_DUO
463     status =  nxd_tftp_client_file_close(&client, IP_TYPE);
464 #else
465     status =  nx_tftp_client_file_close(&client);
466 #endif
467 
468     /* Check status.  */
469     if (status)
470         error_counter++;
471 
472     /* Open the same file for reading.  */
473 #ifdef USE_DUO
474     status =  nxd_tftp_client_file_open(&client, "test.txt", &server_ip_address, NX_TFTP_OPEN_FOR_READ, NX_IP_PERIODIC_RATE, IP_TYPE);
475 #else
476     status =  nx_tftp_client_file_open(&client, "test.txt", SERVER_ADDRESS, NX_TFTP_OPEN_FOR_READ, NX_IP_PERIODIC_RATE);
477 #endif
478 
479     /* Check status.  */
480     if (status)
481         error_counter++;
482     do
483     {
484 
485     /* Read the file back.  */
486 #ifdef USE_DUO
487         status =  nxd_tftp_client_file_read(&client, &my_packet, NX_IP_PERIODIC_RATE, IP_TYPE);
488 #else
489         status =  nx_tftp_client_file_read(&client, &my_packet, NX_IP_PERIODIC_RATE);
490 #endif
491         /* Check for retranmission/dropped packet error. Benign. Try again... */
492         if (status == NX_TFTP_INVALID_BLOCK_NUMBER)
493         {
494 
495             continue;
496         }
497         else if (status == NX_TFTP_END_OF_FILE)
498         {
499 
500             /* All done. */
501             all_done = NX_TRUE;
502         }
503         else if (status != NX_SUCCESS)
504         {
505 
506             /* Internal error, invalid packet or error on read. */
507             break;
508         }
509 
510 
511         /* Do something with the packet data and release when done. */
512         nx_packet_data_retrieve(my_packet, buffer, &data_length);
513         buffer[data_length] = 0;
514         printf("Receive data: %s\n", buffer);
515 
516         printf("release packet in demo.\n");
517 
518         nx_packet_release(my_packet);
519 
520     } while (all_done == NX_FALSE);
521 
522     /* Close the file again.  */
523 #ifdef USE_DUO
524     status =  nxd_tftp_client_file_close(&client, IP_TYPE);
525 #else
526     status =  nx_tftp_client_file_close(&client);
527 #endif
528 
529     /* Check status.  */
530     if (status)
531         error_counter++;
532 
533     /* Delete the client.  */
534 #ifdef USE_DUO
535     status =  nxd_tftp_client_delete(&client);
536 #else
537     status =  nx_tftp_client_delete(&client);
538 #endif
539 
540     /* Check status.  */
541     if (status)
542         error_counter++;
543 
544     return;
545 }
546