1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** NetX Duo Component */
17 /** Trivial File Transfer Protocol (TFTP) Server */
18 /** */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 #define NX_TFTP_SOURCE_CODE
24
25
26 /* Force error checking to be disabled in this module */
27
28 #ifndef NX_DISABLE_ERROR_CHECKING
29 #define NX_DISABLE_ERROR_CHECKING
30 #endif
31
32 /* Include necessary system files. */
33
34 #include "nx_api.h"
35 #include "nx_ip.h"
36 #include "nxd_tftp_server.h"
37 #ifdef FEATURE_NX_IPV6
38 #include "nx_ipv6.h"
39 #endif
40
41 /* Bring in externs for caller checking code. */
42
43 NX_CALLER_CHECKING_EXTERNS
44
45 /**************************************************************************/
46 /* */
47 /* FUNCTION RELEASE */
48 /* */
49 /* _nxde_tftp_server_create PORTABLE C */
50 /* 6.1 */
51 /* AUTHOR */
52 /* */
53 /* Yuxin Zhou, Microsoft Corporation */
54 /* */
55 /* DESCRIPTION */
56 /* */
57 /* This function checks for errors in the TFTP server create call. */
58 /* */
59 /* */
60 /* INPUT */
61 /* */
62 /* tftp_server_ptr Pointer to TFTP server */
63 /* tftp_server_name Name of TFTP server */
64 /* ip_ptr Pointer to IP instance */
65 /* media_ptr Pointer to media structure */
66 /* stack_ptr Server thread's stack pointer */
67 /* stack_size Server thread's stack size */
68 /* pool_ptr Pointer to packet pool */
69 /* */
70 /* OUTPUT */
71 /* */
72 /* status Completion status */
73 /* NX_PTR_ERROR Invalid pointer input */
74 /* NX_TFTP_POOL_ERROR Invalid packet size for TFTP */
75 /* server packet pool */
76 /* */
77 /* CALLS */
78 /* */
79 /* _nxd_tftp_server_create Actual server create call */
80 /* */
81 /* CALLED BY */
82 /* */
83 /* Application Code */
84 /* */
85 /* RELEASE HISTORY */
86 /* */
87 /* DATE NAME DESCRIPTION */
88 /* */
89 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
90 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
91 /* resulting in version 6.1 */
92 /* */
93 /**************************************************************************/
_nxde_tftp_server_create(NX_TFTP_SERVER * tftp_server_ptr,CHAR * tftp_server_name,NX_IP * ip_ptr,FX_MEDIA * media_ptr,VOID * stack_ptr,ULONG stack_size,NX_PACKET_POOL * pool_ptr)94 UINT _nxde_tftp_server_create(NX_TFTP_SERVER *tftp_server_ptr, CHAR *tftp_server_name, NX_IP *ip_ptr,
95 FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr)
96 {
97
98 UINT status;
99 NX_PACKET *packet_ptr;
100
101
102 /* Check for invalid input pointers. */
103 if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) ||
104 (tftp_server_ptr == NX_NULL) || (tftp_server_ptr -> nx_tftp_server_id == NXD_TFTP_SERVER_ID) ||
105 (stack_ptr == NX_NULL) || (pool_ptr == NX_NULL))
106 {
107
108 return(NX_PTR_ERROR);
109 }
110
111 /* Pickup a packet from the supplied packet pool. */
112 packet_ptr = pool_ptr -> nx_packet_pool_available_list;
113
114 /* Determine if the packet payload is large enough (must include 512 bytes plus packet headers). */
115 if ((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_data_start) < NX_TFTP_PACKET_SIZE)
116 {
117
118 return(NX_TFTP_POOL_ERROR);
119 }
120
121 /* Call actual server create function. */
122 status = _nxd_tftp_server_create(tftp_server_ptr, tftp_server_name, ip_ptr, media_ptr, stack_ptr, stack_size, pool_ptr);
123
124 /* Return completion status. */
125 return(status);
126 }
127
128
129 /**************************************************************************/
130 /* */
131 /* FUNCTION RELEASE */
132 /* */
133 /* _nxd_tftp_server_create PORTABLE C */
134 /* 6.1 */
135 /* AUTHOR */
136 /* */
137 /* Yuxin Zhou, Microsoft Corporation */
138 /* */
139 /* DESCRIPTION */
140 /* */
141 /* This function creates a TFTP server on the specified IP. In doing */
142 /* so this function creates an UDP socket for subsequent TFTP */
143 /* transfers and a thread for the TFTP server. */
144 /* */
145 /* If NX_TFTP_SERVER_RETRANSMIT_ENABLE is enabled, it also creates */
146 /* a timer for retransmitting TFTP server packets up to a maximum */
147 /* number of retries before terminating the connection. */
148 /* */
149 /* INPUT */
150 /* */
151 /* tftp_server_ptr Pointer to TFTP server */
152 /* tftpvserver_name Name of TFTP server */
153 /* ip_ptr Pointer to IP instance */
154 /* media_ptr Pointer to media structure */
155 /* stack_ptr Server thread's stack pointer */
156 /* stack_size Server thread's stack size */
157 /* pool_ptr Pointer to packet pool */
158 /* */
159 /* OUTPUT */
160 /* */
161 /* status Actual cmpletion status */
162 /* NX_SUCCESS Successful completion */
163 /* */
164 /* CALLS */
165 /* */
166 /* nx_udp_socket_bind Bind the TFTP server socket */
167 /* nx_udp_socket_create Create TFTP server socket */
168 /* nx_udp_socket_delete Delete TFTP server socket */
169 /* nx_udp_socket_unbind Unbind TFTP server socket */
170 /* tx_thread_create Create TFTP server thread */
171 /* tx_timer_create Create retransmit timer */
172 /* nx_udp_socket_receive_notify Set a receive callback */
173 /* */
174 /* CALLED BY */
175 /* */
176 /* Application Code */
177 /* */
178 /* RELEASE HISTORY */
179 /* */
180 /* DATE NAME DESCRIPTION */
181 /* */
182 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
183 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
184 /* resulting in version 6.1 */
185 /* */
186 /**************************************************************************/
_nxd_tftp_server_create(NX_TFTP_SERVER * tftp_server_ptr,CHAR * tftp_server_name,NX_IP * ip_ptr,FX_MEDIA * media_ptr,VOID * stack_ptr,ULONG stack_size,NX_PACKET_POOL * pool_ptr)187 UINT _nxd_tftp_server_create(NX_TFTP_SERVER *tftp_server_ptr, CHAR *tftp_server_name, NX_IP *ip_ptr,
188 FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr)
189 {
190
191 UINT status;
192
193
194 /* Clear the TFTP server structure. */
195 memset((void *) tftp_server_ptr, 0, sizeof(NX_TFTP_SERVER));
196
197 /* Create the server's UDP socket. */
198 status = nx_udp_socket_create(ip_ptr, &(tftp_server_ptr -> nx_tftp_server_socket), tftp_server_name,
199 NX_TFTP_TYPE_OF_SERVICE, NX_TFTP_FRAGMENT_OPTION, NX_TFTP_TIME_TO_LIVE, NX_TFTP_QUEUE_DEPTH);
200
201 /* Determine if an error occurred. */
202 if (status != NX_SUCCESS)
203 {
204
205 /* Yes, return error code. */
206 return(status);
207 }
208
209 /* Register the receive function. */
210 nx_udp_socket_receive_notify(&(tftp_server_ptr -> nx_tftp_server_socket), _nx_tftp_server_data_present);
211
212 /* Make sure the socket points to the TFTP server. */
213 tftp_server_ptr -> nx_tftp_server_socket.nx_udp_socket_reserved_ptr = tftp_server_ptr;
214
215 /* Now, bind the socket to a the well known TFTP UDP port number. */
216 status = nx_udp_socket_bind(&(tftp_server_ptr -> nx_tftp_server_socket), NX_TFTP_SERVER_PORT, NX_NO_WAIT);
217
218 /* Determine if an error occurred. */
219 if (status != NX_SUCCESS)
220 {
221
222 /* Delete the UDP socket. */
223 nx_udp_socket_delete(&(tftp_server_ptr -> nx_tftp_server_socket));
224
225 /* Yes, return error code. */
226 return(status);
227 }
228
229 /* Now create the TFTP Server thread. */
230 status = tx_thread_create(&(tftp_server_ptr -> nx_tftp_server_thread), "TFTP Server Thread", _nx_tftp_server_thread_entry,
231 (ULONG) tftp_server_ptr, stack_ptr, stack_size, NX_TFTP_SERVER_PRIORITY, NX_TFTP_SERVER_PRIORITY,
232 NX_TFTP_SERVER_TIME_SLICE, TX_DONT_START);
233
234 /* Determine if an error occurred creating the thread. */
235 if (status != NX_SUCCESS)
236 {
237
238 /* Unbind the UDP socket. */
239 nx_udp_socket_unbind(&(tftp_server_ptr -> nx_tftp_server_socket));
240
241 /* Delete the UDP socket. */
242 nx_udp_socket_delete(&(tftp_server_ptr -> nx_tftp_server_socket));
243
244 /* Yes, return error code. */
245 return(status);
246 }
247
248 /* Create the ThreadX event flags. These will be used to drive the TFTP server thread. */
249 status = tx_event_flags_create(&(tftp_server_ptr -> nx_tftp_server_event_flags), "TFTP Server Thread Events");
250
251 /* Determine if an error occurred creating the event flags. */
252 if (status != TX_SUCCESS)
253 {
254
255 /* Unbind the UDP socket. */
256 nx_udp_socket_unbind(&(tftp_server_ptr -> nx_tftp_server_socket));
257
258 /* Delete the UDP socket. */
259 nx_udp_socket_delete(&(tftp_server_ptr -> nx_tftp_server_socket));
260
261 /* Delete the server thread. */
262 tx_thread_delete(&(tftp_server_ptr -> nx_tftp_server_thread));
263
264 /* Error creating the server event flags. */
265 return(status);
266 }
267
268 #ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE
269
270 /* Create the ThreadX retransmit timeout timer. This will be used to retransmit TFTP server
271 packets if the Client has not responded or sends a duplicate (old) ACK or data packet. */
272 status = tx_timer_create(&(tftp_server_ptr -> nx_tftp_server_timer), "TFTP Server Timer",
273 _nx_tftp_server_timer_entry, (ULONG) tftp_server_ptr,
274 (NX_TFTP_SERVER_TIMEOUT_PERIOD),
275 (NX_TFTP_SERVER_TIMEOUT_PERIOD), TX_NO_ACTIVATE);
276
277 if (status != NX_SUCCESS)
278 {
279
280 /* Unbind the UDP socket. */
281 nx_udp_socket_unbind(&(tftp_server_ptr -> nx_tftp_server_socket));
282
283 /* Delete the UDP socket. */
284 nx_udp_socket_delete(&(tftp_server_ptr -> nx_tftp_server_socket));
285
286 /* Delete the event flags. */
287 tx_event_flags_delete(&(tftp_server_ptr -> nx_tftp_server_event_flags));
288
289 /* Delete the server thread. */
290 tx_thread_delete(&(tftp_server_ptr -> nx_tftp_server_thread));
291
292 /* Yes, return error code. */
293 return(status);
294 }
295 #endif /* NX_TFTP_SERVER_RETRANSMIT_ENABLE */
296
297 /* Save the Server name. */
298 tftp_server_ptr -> nx_tftp_server_name = tftp_server_name;
299
300 /* Save the IP pointer address. */
301 tftp_server_ptr -> nx_tftp_server_ip_ptr = ip_ptr;
302
303 /* Save the packet pool pointer. */
304 tftp_server_ptr -> nx_tftp_server_packet_pool_ptr = pool_ptr;
305
306 /* Save the media pointer address. */
307 tftp_server_ptr -> nx_tftp_server_media_ptr = media_ptr;
308
309 /* Clear the error code and error string. */
310 tftp_server_ptr -> nx_tftp_server_error_code = 0;
311 tftp_server_ptr -> nx_tftp_server_error_string[0] = NX_NULL;
312
313 /* Set the server ID to indicate the TFTP server thread is ready. */
314 tftp_server_ptr -> nx_tftp_server_id = NXD_TFTP_SERVER_ID;
315
316 /* Return successful completion. */
317 return(NX_SUCCESS);
318 }
319
320 /**************************************************************************/
321 /* */
322 /* FUNCTION RELEASE */
323 /* */
324 /* _nxde_tftp_server_delete PORTABLE C */
325 /* 6.1 */
326 /* AUTHOR */
327 /* */
328 /* Yuxin Zhou, Microsoft Corporation */
329 /* */
330 /* DESCRIPTION */
331 /* */
332 /* This function checks for errors in the TFTP server delete call. */
333 /* */
334 /* */
335 /* INPUT */
336 /* */
337 /* tftp_server_ptr Pointer to TFTP server */
338 /* */
339 /* OUTPUT */
340 /* */
341 /* status Completion status */
342 /* NX_PTR_ERROR Invalid pointer input */
343 /* */
344 /* CALLS */
345 /* */
346 /* _nxd_tftp_server_delete Actual server delete call */
347 /* */
348 /* CALLED BY */
349 /* */
350 /* Application Code */
351 /* */
352 /* RELEASE HISTORY */
353 /* */
354 /* DATE NAME DESCRIPTION */
355 /* */
356 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
357 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
358 /* resulting in version 6.1 */
359 /* */
360 /**************************************************************************/
_nxde_tftp_server_delete(NX_TFTP_SERVER * tftp_server_ptr)361 UINT _nxde_tftp_server_delete(NX_TFTP_SERVER *tftp_server_ptr)
362 {
363
364 UINT status;
365
366
367 /* Check for invalid input pointers. */
368 if ((tftp_server_ptr == NX_NULL) || (tftp_server_ptr -> nx_tftp_server_id != NXD_TFTP_SERVER_ID))
369 return(NX_PTR_ERROR);
370
371 /* Check for appropriate caller. */
372 NX_THREADS_ONLY_CALLER_CHECKING
373
374 /* Call actual server delete function. */
375 status = _nxd_tftp_server_delete(tftp_server_ptr);
376
377 /* Return completion status. */
378 return(status);
379 }
380
381
382 /**************************************************************************/
383 /* */
384 /* FUNCTION RELEASE */
385 /* */
386 /* _nxd_tftp_server_delete PORTABLE C */
387 /* 6.1 */
388 /* AUTHOR */
389 /* */
390 /* Yuxin Zhou, Microsoft Corporation */
391 /* */
392 /* DESCRIPTION */
393 /* */
394 /* This function deletes a previously created TFTP server on the */
395 /* specified IP. */
396 /* */
397 /* */
398 /* INPUT */
399 /* */
400 /* tftp_server_ptr Pointer to TFTP server */
401 /* */
402 /* OUTPUT */
403 /* */
404 /* NX_SUCCESS Successful completion */
405 /* status Actual completion status */
406 /* */
407 /* CALLS */
408 /* */
409 /* fx_file_close File close */
410 /* nx_udp_socket_delete Delete TFTP server socket */
411 /* nx_udp_socket_unbind Unbind TFTP server socket */
412 /* tx_thread_delete Delete TFTP server thread */
413 /* tx_thread_suspend Suspend TFTP server thread */
414 /* tx_thread_terminate Terminate TFTP server */
415 /* thread */
416 /* */
417 /* CALLED BY */
418 /* */
419 /* Application Code */
420 /* */
421 /* RELEASE HISTORY */
422 /* */
423 /* DATE NAME DESCRIPTION */
424 /* */
425 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
426 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
427 /* resulting in version 6.1 */
428 /* */
429 /**************************************************************************/
_nxd_tftp_server_delete(NX_TFTP_SERVER * tftp_server_ptr)430 UINT _nxd_tftp_server_delete(NX_TFTP_SERVER *tftp_server_ptr)
431 {
432
433 UINT i;
434 NX_TFTP_CLIENT_REQUEST *client_request_ptr;
435
436
437 /* Clear the server ID to indicate the TFTP server is no longer ready. */
438 tftp_server_ptr -> nx_tftp_server_id = 0;
439
440 /* Unbind the UDP socket. */
441 nx_udp_socket_unbind(&(tftp_server_ptr -> nx_tftp_server_socket));
442
443 /* Delete the UDP socket. */
444 nx_udp_socket_delete(&(tftp_server_ptr -> nx_tftp_server_socket));
445
446 /* Suspend the TFTP server thread. */
447 tx_thread_suspend(&(tftp_server_ptr -> nx_tftp_server_thread));
448
449 /* Terminate server thread. */
450 tx_thread_terminate(&(tftp_server_ptr -> nx_tftp_server_thread));
451
452 /* Delete the server flag group. */
453 tx_event_flags_delete(&(tftp_server_ptr -> nx_tftp_server_event_flags));
454
455 #ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE
456 tx_timer_delete(&(tftp_server_ptr -> nx_tftp_server_timer));
457 #endif
458
459
460 /* Delete server thread. */
461 tx_thread_delete(&(tftp_server_ptr -> nx_tftp_server_thread));
462
463 /* Walk through the server structure to close any remaining open files. */
464 i = 0;
465
466 client_request_ptr = &(tftp_server_ptr -> nx_tftp_server_client_list[0]);
467
468 while (i < NX_TFTP_MAX_CLIENTS)
469 {
470
471 /* Is this entry in use? */
472
473 /* First determine which IP address type. */
474 if (client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_version == NX_IP_VERSION_V4)
475 {
476
477 #ifndef NX_DISABLE_IPV4
478 /* This is an IPv4 client. Is this slot empty? */
479 if ((client_request_ptr -> nx_tftp_client_request_port != 0) &&
480 (client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_address.v4) != 0)
481 {
482
483 /* No, need to close the file on this client! */
484 fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
485 }
486 #endif /* NX_DISABLE_IPV4 */
487 }
488 else if (client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_version == NX_IP_VERSION_V6)
489 {
490
491 #ifdef FEATURE_NX_IPV6
492 /* This is an IPv6 Client. Is this slot empty? */
493 if ((client_request_ptr -> nx_tftp_client_request_port != 0) &&
494 (!CHECK_UNSPECIFIED_ADDRESS(&client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_address.v6[0])))
495 {
496
497 /* No, need to close the file on this client!*/
498 fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
499 }
500 #endif /* FEATURE_NX_IPV6 */
501 }
502
503 /* Increment the pointer into the client request list. */
504 client_request_ptr++;
505 i++;
506 }
507
508 /* Return successful completion. */
509 return(NX_SUCCESS);
510 }
511
512
513 /**************************************************************************/
514 /* */
515 /* FUNCTION RELEASE */
516 /* */
517 /* _nxde_tftp_server_start PORTABLE C */
518 /* 6.1 */
519 /* AUTHOR */
520 /* */
521 /* Yuxin Zhou, Microsoft Corporation */
522 /* */
523 /* DESCRIPTION */
524 /* */
525 /* This function checks for errors in the TFTP server start call. */
526 /* */
527 /* */
528 /* INPUT */
529 /* */
530 /* tftp_server_ptr Pointer to TFTP server */
531 /* */
532 /* OUTPUT */
533 /* */
534 /* status Completion status */
535 /* NX_PTR_ERROR Invalid pointer input */
536 /* */
537 /* CALLS */
538 /* */
539 /* _nxd_tftp_server_start Actual server start call */
540 /* */
541 /* CALLED BY */
542 /* */
543 /* Application Code */
544 /* */
545 /* RELEASE HISTORY */
546 /* */
547 /* DATE NAME DESCRIPTION */
548 /* */
549 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
550 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
551 /* resulting in version 6.1 */
552 /* */
553 /**************************************************************************/
_nxde_tftp_server_start(NX_TFTP_SERVER * tftp_server_ptr)554 UINT _nxde_tftp_server_start(NX_TFTP_SERVER *tftp_server_ptr)
555 {
556
557 UINT status;
558
559
560 /* Check for invalid input pointers. */
561 if ((tftp_server_ptr == NX_NULL) || (tftp_server_ptr -> nx_tftp_server_id != NXD_TFTP_SERVER_ID))
562 return(NX_PTR_ERROR);
563
564 /* Call actual server start function. */
565 status = _nxd_tftp_server_start(tftp_server_ptr);
566
567 /* Return completion status. */
568 return(status);
569 }
570
571
572 /**************************************************************************/
573 /* */
574 /* FUNCTION RELEASE */
575 /* */
576 /* _nxd_tftp_server_start PORTABLE C */
577 /* 6.1 */
578 /* AUTHOR */
579 /* */
580 /* Yuxin Zhou, Microsoft Corporation */
581 /* */
582 /* DESCRIPTION */
583 /* */
584 /* This function starts a previously created TFTP server on the */
585 /* specified IP. */
586 /* */
587 /* */
588 /* INPUT */
589 /* */
590 /* tftp_server_ptr Pointer to TFTP server */
591 /* */
592 /* OUTPUT */
593 /* */
594 /* NX_SUCCESS Successful completion */
595 /* */
596 /* CALLS */
597 /* */
598 /* tx_thread_resume Resume TFTP server thread */
599 /* */
600 /* CALLED BY */
601 /* */
602 /* Application Code */
603 /* */
604 /* RELEASE HISTORY */
605 /* */
606 /* DATE NAME DESCRIPTION */
607 /* */
608 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
609 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
610 /* resulting in version 6.1 */
611 /* */
612 /**************************************************************************/
_nxd_tftp_server_start(NX_TFTP_SERVER * tftp_server_ptr)613 UINT _nxd_tftp_server_start(NX_TFTP_SERVER *tftp_server_ptr)
614 {
615
616 #ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE
617 /* Activate TFTP server timer. */
618 tx_timer_activate(&(tftp_server_ptr -> nx_tftp_server_timer));
619 #endif
620
621 /* Start the TFTP server thread. */
622 tx_thread_resume(&(tftp_server_ptr -> nx_tftp_server_thread));
623
624 /* Return successful completion. */
625 return(NX_SUCCESS);
626 }
627
628
629 /**************************************************************************/
630 /* */
631 /* FUNCTION RELEASE */
632 /* */
633 /* _nxde_tftp_server_stop PORTABLE C */
634 /* 6.1 */
635 /* AUTHOR */
636 /* */
637 /* Yuxin Zhou, Microsoft Corporation */
638 /* */
639 /* DESCRIPTION */
640 /* */
641 /* This function checks for errors in the TFTP server stop call. */
642 /* */
643 /* */
644 /* INPUT */
645 /* */
646 /* tftp_server_ptr Pointer to TFTP server */
647 /* */
648 /* OUTPUT */
649 /* */
650 /* status Completion status */
651 /* NX_PTR_ERROR Invalid pointer input */
652 /* */
653 /* CALLS */
654 /* */
655 /* _nxd_tftp_server_stop Actual server start call */
656 /* */
657 /* CALLED BY */
658 /* */
659 /* Application Code */
660 /* */
661 /* RELEASE HISTORY */
662 /* */
663 /* DATE NAME DESCRIPTION */
664 /* */
665 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
666 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
667 /* resulting in version 6.1 */
668 /* */
669 /**************************************************************************/
_nxde_tftp_server_stop(NX_TFTP_SERVER * tftp_server_ptr)670 UINT _nxde_tftp_server_stop(NX_TFTP_SERVER *tftp_server_ptr)
671 {
672
673 UINT status;
674
675
676 /* Check for invalid input pointers. */
677 if ((tftp_server_ptr == NX_NULL) || (tftp_server_ptr -> nx_tftp_server_id != NXD_TFTP_SERVER_ID))
678 return(NX_PTR_ERROR);
679
680 /* Check for appropriate caller. */
681 NX_THREADS_ONLY_CALLER_CHECKING
682
683 /* Call actual server delete function. */
684 status = _nxd_tftp_server_stop(tftp_server_ptr);
685
686 /* Return completion status. */
687 return(status);
688 }
689
690
691 /**************************************************************************/
692 /* */
693 /* FUNCTION RELEASE */
694 /* */
695 /* _nxd_tftp_server_stop PORTABLE C */
696 /* 6.1 */
697 /* AUTHOR */
698 /* */
699 /* Yuxin Zhou, Microsoft Corporation */
700 /* */
701 /* DESCRIPTION */
702 /* */
703 /* This function stops a previously started TFTP server on the */
704 /* specified IP. */
705 /* */
706 /* */
707 /* INPUT */
708 /* */
709 /* tftp_server_ptr Pointer to TFTP server */
710 /* */
711 /* OUTPUT */
712 /* */
713 /* NX_SUCCESS Successful completion */
714 /* */
715 /* CALLS */
716 /* */
717 /* tx_thread_suspend Suspend TFTP server thread */
718 /* */
719 /* CALLED BY */
720 /* */
721 /* Application Code */
722 /* */
723 /* RELEASE HISTORY */
724 /* */
725 /* DATE NAME DESCRIPTION */
726 /* */
727 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
728 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
729 /* resulting in version 6.1 */
730 /* */
731 /**************************************************************************/
_nxd_tftp_server_stop(NX_TFTP_SERVER * tftp_server_ptr)732 UINT _nxd_tftp_server_stop(NX_TFTP_SERVER *tftp_server_ptr)
733 {
734
735 #ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE
736 /* Deactivate TFTP server timer. */
737 tx_timer_deactivate(&(tftp_server_ptr -> nx_tftp_server_timer));
738 #endif
739
740 /* Suspend the TFTP server thread. */
741 tx_thread_suspend(&(tftp_server_ptr -> nx_tftp_server_thread));
742
743 /* Return successful completion. */
744 return(NX_SUCCESS);
745 }
746
747
748 /**************************************************************************/
749 /* */
750 /* FUNCTION RELEASE */
751 /* */
752 /* _nx_tftp_server_data_present PORTABLE C */
753 /* 6.1 */
754 /* AUTHOR */
755 /* */
756 /* Yuxin Zhou, Microsoft Corporation */
757 /* */
758 /* DESCRIPTION */
759 /* */
760 /* This function is notified by NetX of receive events generated by */
761 /* TFTP Clients connecting or sending data. */
762 /* */
763 /* INPUT */
764 /* */
765 /* socket_ptr Socket receiving data */
766 /* */
767 /* OUTPUT */
768 /* */
769 /* None */
770 /* */
771 /* CALLS */
772 /* */
773 /* tx_event_flags_set Set events for server thread */
774 /* */
775 /* CALLED BY */
776 /* */
777 /* NetX NetX TCP socket callback */
778 /* */
779 /* RELEASE HISTORY */
780 /* */
781 /* DATE NAME DESCRIPTION */
782 /* */
783 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
784 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
785 /* resulting in version 6.1 */
786 /* */
787 /**************************************************************************/
_nx_tftp_server_data_present(NX_UDP_SOCKET * socket_ptr)788 VOID _nx_tftp_server_data_present(NX_UDP_SOCKET *socket_ptr)
789 {
790
791 NX_TFTP_SERVER *server_ptr;
792
793 /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */
794 server_ptr = (NX_TFTP_SERVER *)(socket_ptr -> nx_udp_socket_reserved_ptr);
795
796 /* Set the data event flag. */
797 tx_event_flags_set(&(server_ptr -> nx_tftp_server_event_flags), NX_TFTP_SERVER_RECEIVE_EVENT, TX_OR);
798 }
799
800
801 #ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE
802 /**************************************************************************/
803 /* */
804 /* FUNCTION RELEASE */
805 /* */
806 /* _nx_tftp_server_timer_entry PORTABLE C */
807 /* 6.1 */
808 /* AUTHOR */
809 /* */
810 /* Yuxin Zhou, Microsoft Corporation */
811 /* */
812 /* DESCRIPTION */
813 /* */
814 /* This function captures timer events used to determine if the Client */
815 /* retransmit timer has expired. */
816 /* */
817 /* */
818 /* INPUT */
819 /* */
820 /* ULONG Pointer to TFTP server */
821 /* */
822 /* OUTPUT */
823 /* */
824 /* None */
825 /* */
826 /* CALLS */
827 /* */
828 /* tx_event_flags_set Set events for server thread */
829 /* */
830 /* CALLED BY */
831 /* */
832 /* NetX NetX connect callback */
833 /* */
834 /* RELEASE HISTORY */
835 /* */
836 /* DATE NAME DESCRIPTION */
837 /* */
838 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
839 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
840 /* resulting in version 6.1 */
841 /* */
842 /**************************************************************************/
_nx_tftp_server_timer_entry(ULONG tftp_server_address)843 VOID _nx_tftp_server_timer_entry(ULONG tftp_server_address)
844 {
845
846 NX_TFTP_SERVER *server_ptr;
847
848 /* Pickup server pointer. */
849 server_ptr = (NX_TFTP_SERVER *) tftp_server_address;
850
851 /* Set the data event flag. */
852 tx_event_flags_set(&(server_ptr -> nx_tftp_server_event_flags), NX_TFTP_SERVER_TIMER_EVENT, TX_OR);
853
854 return;
855 }
856
857 /**************************************************************************/
858 /* */
859 /* FUNCTION RELEASE */
860 /* */
861 /* _nx_tftp_server_timer_process PORTABLE C */
862 /* 6.1 */
863 /* AUTHOR */
864 /* */
865 /* Yuxin Zhou, Microsoft Corporation */
866 /* */
867 /* DESCRIPTION */
868 /* */
869 /* This function checks all the active TFTP client connections */
870 /* for their retransmission timeout. If expired, the Server retransmits*/
871 /* the data or ACK up to a maximum number of retries */
872 /* (NX_TFTP_SERVER_MAX_RETRIES) and then terminates the connection and */
873 /* closes any open files. The client request is cleared and available */
874 /* for the next client request */
875 /* */
876 /* */
877 /* INPUT */
878 /* */
879 /* server_ptr Pointer to TFTP server */
880 /* */
881 /* OUTPUT */
882 /* */
883 /* None */
884 /* */
885 /* CALLS */
886 /* */
887 /* fx_file_close Close session file. */
888 /* fx_file_delete Delete the file */
889 /* */
890 /* CALLED BY */
891 /* */
892 /* _nx_tftp_server_thread_entry TFTP server task function */
893 /* */
894 /* RELEASE HISTORY */
895 /* */
896 /* DATE NAME DESCRIPTION */
897 /* */
898 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
899 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
900 /* resulting in version 6.1 */
901 /* */
902 /**************************************************************************/
_nx_tftp_server_timer_process(NX_TFTP_SERVER * server_ptr)903 VOID _nx_tftp_server_timer_process(NX_TFTP_SERVER *server_ptr)
904 {
905
906 UINT i;
907 NX_TFTP_CLIENT_REQUEST *client_request_ptr;
908
909
910 /* Now look through all the sockets. */
911 for (i = 0; i < NX_TFTP_MAX_CLIENTS; i++)
912 {
913
914 /* Set a pointer to client request structure. */
915 client_request_ptr = &(server_ptr -> nx_tftp_server_client_list[i]);
916
917 /* Check if this request has a retransmit timeout pending. */
918 if (client_request_ptr -> nx_tftp_client_retransmit_timeout )
919 {
920
921 /* Update reatransmit timeout. */
922 if (client_request_ptr -> nx_tftp_client_retransmit_timeout >= NX_TFTP_SERVER_TIMEOUT_PERIOD)
923 {
924
925 client_request_ptr -> nx_tftp_client_retransmit_timeout -= NX_TFTP_SERVER_TIMEOUT_PERIOD;
926 }
927 else
928 {
929
930 client_request_ptr -> nx_tftp_client_retransmit_timeout = 0;
931 }
932
933 /* Has the retransmit timeout expired? */
934 if (client_request_ptr -> nx_tftp_client_retransmit_timeout == 0)
935 {
936
937 /* Yes, retransmit unless we have hit the max retry limit. */
938 if (client_request_ptr -> nx_tftp_client_retransmit_retries < NX_TFTP_SERVER_MAX_RETRIES)
939 {
940
941
942 /* Update the Client request retransmit timeout and number of retries. */
943 client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT;
944 client_request_ptr -> nx_tftp_client_retransmit_retries++;
945
946 /* Determine which type of request this is. */
947 if (client_request_ptr -> nx_tftp_client_request_open_type == NX_TFTP_STATE_WRITE_OPEN)
948 {
949
950 /* Retransmit the ACK. */
951 _nx_tftp_server_send_ack(server_ptr, client_request_ptr, NX_TRUE);
952 }
953 else
954 {
955
956 /* Retransmit the file data. */
957 _nx_tftp_server_send_data(server_ptr, client_request_ptr, NX_TRUE);
958 }
959 }
960 else
961 {
962
963 /* The session has timed out. Send error and close. */
964 _nx_tftp_server_send_error(server_ptr, &client_request_ptr -> nx_tftp_client_request_ip_address,
965 client_request_ptr -> nx_tftp_client_request_port,
966 NX_TFTP_SESSION_TIMED_OUT, "NetX TFTP Server: Session timed out");
967
968 /* Error, close the file and delete the client request. */
969 fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
970
971 memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST));
972 }
973 }
974 }
975 }
976 }
977 #endif /* NX_TFTP_SERVER_RETRANSMIT_ENABLE */
978
979
980 /**************************************************************************/
981 /* */
982 /* FUNCTION RELEASE */
983 /* */
984 /* _nx_tftp_server_thread_entry PORTABLE C */
985 /* 6.1 */
986 /* AUTHOR */
987 /* */
988 /* Yuxin Zhou, Microsoft Corporation */
989 /* */
990 /* DESCRIPTION */
991 /* */
992 /* This function is the entry of the TFTP server. All basic */
993 /* processing is initiated by this function. */
994 /* */
995 /* */
996 /* INPUT */
997 /* */
998 /* tftp_server Pointer to TFTP server */
999 /* */
1000 /* OUTPUT */
1001 /* */
1002 /* None */
1003 /* */
1004 /* CALLS */
1005 /* */
1006 /* tx_event_flags_get Get the TFTP events */
1007 /* _nx_tftp_server_process_received_data Process received packet */
1008 /* _nx_tftp_server_timer_process Process TFTP timer */
1009 /* */
1010 /* CALLED BY */
1011 /* */
1012 /* ThreadX */
1013 /* */
1014 /* RELEASE HISTORY */
1015 /* */
1016 /* DATE NAME DESCRIPTION */
1017 /* */
1018 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1019 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1020 /* resulting in version 6.1 */
1021 /* */
1022 /**************************************************************************/
_nx_tftp_server_thread_entry(ULONG tftp_server)1023 VOID _nx_tftp_server_thread_entry(ULONG tftp_server)
1024 {
1025
1026 NX_TFTP_SERVER *server_ptr;
1027 UINT status;
1028 ULONG events;
1029
1030
1031 /* Setup the server pointer. */
1032 server_ptr = (NX_TFTP_SERVER *) tftp_server;
1033
1034 /* Loop to process TFTP Server requests. */
1035 while(1)
1036 {
1037
1038 /* Wait for TFTP events. */
1039 status = tx_event_flags_get(&(server_ptr -> nx_tftp_server_event_flags), NX_SERVER_TFTP_ANY_EVENT,
1040 TX_OR_CLEAR, &events, TX_WAIT_FOREVER);
1041
1042 /* Check the return status. */
1043 if (status)
1044 {
1045
1046 /* If an error occurs, simply continue the loop. */
1047 continue;
1048 }
1049
1050 /* Otherwise, an event is present. Process according to the event. */
1051
1052 /* Check for a client receive event. */
1053 if (events & NX_TFTP_SERVER_RECEIVE_EVENT)
1054 {
1055
1056 /* Call the data received handler. */
1057 _nx_tftp_server_process_received_data(server_ptr);
1058 }
1059
1060 #ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE
1061 /* Check for a timer event. */
1062 if (events & NX_TFTP_SERVER_TIMER_EVENT)
1063 {
1064 /* Call the timer timeout handler. */
1065 _nx_tftp_server_timer_process(server_ptr);
1066 }
1067 #endif /* NX_TFTP_SERVER_RETRANSMIT_ENABLE*/
1068 }
1069 }
1070
1071
1072 /**************************************************************************/
1073 /* */
1074 /* FUNCTION RELEASE */
1075 /* */
1076 /* _nx_tftp_server_process_received_data PORTABLE C */
1077 /* 6.1.10 */
1078 /* AUTHOR */
1079 /* */
1080 /* Yuxin Zhou, Microsoft Corporation */
1081 /* */
1082 /* DESCRIPTION */
1083 /* */
1084 /* This function is called when the TFTP server is notified of a */
1085 /* receive event. It parses the TFTP Client message and calls the */
1086 /* appropriate handler for read and write requests, client errors, or */
1087 /* ACKing data sent by the server. */
1088 /* */
1089 /* INPUT */
1090 /* */
1091 /* server_ptr Pointer to TFTP server */
1092 /* */
1093 /* OUTPUT */
1094 /* */
1095 /* status Completion status */
1096 /* */
1097 /* CALLS */
1098 /* */
1099 /* _nx_tftp_server_ack_process Process ACK from previous read*/
1100 /* _nx_tftp_server_data_process Write data packet to file */
1101 /* _nx_tftp_server_error_process Process error packet */
1102 /* _nx_tftp_server_open_for_read_process Open file for reading */
1103 /* _nx_tftp_server_open_for_write_process Open for writing */
1104 /* nx_packet_release Release packet */
1105 /* nx_udp_socket_receive Receive next TFTP packet */
1106 /* */
1107 /* CALLED BY */
1108 /* */
1109 /* nx_tftp_server_thread_entry TFTP thread task function */
1110 /* */
1111 /* RELEASE HISTORY */
1112 /* */
1113 /* DATE NAME DESCRIPTION */
1114 /* */
1115 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1116 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1117 /* resulting in version 6.1 */
1118 /* 01-31-2022 Yuxin Zhou Modified comment(s), improved */
1119 /* the logic of processing */
1120 /* chained packet, */
1121 /* resulting in version 6.1.10 */
1122 /* */
1123 /**************************************************************************/
_nx_tftp_server_process_received_data(NX_TFTP_SERVER * server_ptr)1124 VOID _nx_tftp_server_process_received_data(NX_TFTP_SERVER *server_ptr)
1125 {
1126
1127 UINT status;
1128 NX_PACKET *packet_ptr;
1129 UCHAR request_code[2];
1130 ULONG bytes_copyed;
1131
1132
1133 /* Wait for a request on the TFTP UDP well known port 69. */
1134 status = nx_udp_socket_receive(&(server_ptr -> nx_tftp_server_socket), &packet_ptr, NX_NO_WAIT);
1135
1136 /* Check the return status. */
1137 if (status)
1138 {
1139
1140 /* If an error occurs, simply return to caller. */
1141 return;
1142 }
1143
1144 /* Check for valid packet length (The minimum TFTP header size is ACK packet, four bytes). */
1145 if (packet_ptr -> nx_packet_length < 4)
1146 {
1147
1148 /* Release the packet. */
1149 nx_packet_release(packet_ptr);
1150
1151 /* Return. */
1152 return;
1153 }
1154
1155 /* Otherwise, we have received a packet successfully. */
1156
1157 /* Pickup up the request code. First one must be zero. */
1158 status = nx_packet_data_extract_offset(packet_ptr, 0, request_code, sizeof(request_code), &bytes_copyed);
1159
1160 /* Check the return status. */
1161 if (status || (request_code[0] != 0))
1162 {
1163
1164 nx_packet_release(packet_ptr);
1165 return;
1166 }
1167
1168 /* Process relative to the TFTP request code. */
1169 switch (request_code[1])
1170 {
1171
1172 case NX_TFTP_CODE_READ:
1173
1174 /* Process an open for read request. */
1175 _nx_tftp_server_open_for_read_process(server_ptr, packet_ptr);
1176
1177 /* Increment the number of open for read requests. */
1178 server_ptr -> nx_tftp_server_open_for_read_requests++;
1179 break;
1180
1181 case NX_TFTP_CODE_WRITE:
1182
1183 /* Process an open for write request. */
1184 _nx_tftp_server_open_for_write_process(server_ptr, packet_ptr);
1185
1186 /* Increment the number of open for write requests. */
1187 server_ptr -> nx_tftp_server_open_for_write_requests++;
1188 break;
1189
1190 case NX_TFTP_CODE_DATA:
1191
1192 /* Process a data request. */
1193 _nx_tftp_server_data_process(server_ptr, packet_ptr);
1194
1195 /* Increment the number of data block write requests. */
1196 server_ptr -> nx_tftp_server_data_blocks_received++;
1197 break;
1198
1199 case NX_TFTP_CODE_ACK:
1200
1201 /* Process an ack response. */
1202 _nx_tftp_server_ack_process(server_ptr, packet_ptr);
1203
1204 /* Increment the number of acks for previous data blocks sent. */
1205 server_ptr -> nx_tftp_server_acks_received++;
1206 break;
1207
1208 case NX_TFTP_CODE_ERROR:
1209
1210 /* Process an error request. */
1211 _nx_tftp_server_error_process(server_ptr, packet_ptr);
1212
1213 /* Increment the number of errors received. */
1214 server_ptr -> nx_tftp_server_errors_received++;
1215 break;
1216
1217 default:
1218
1219 /* Increment the number of unknown codes received. */
1220 server_ptr -> nx_tftp_server_unknown_commands++;
1221
1222 /* Just release the packet. */
1223 nx_packet_release(packet_ptr);
1224 }
1225 }
1226
1227
1228 /**************************************************************************/
1229 /* */
1230 /* FUNCTION RELEASE */
1231 /* */
1232 /* _nx_tftp_server_open_for_read_process PORTABLE C */
1233 /* 6.1.10 */
1234 /* AUTHOR */
1235 /* */
1236 /* Yuxin Zhou, Microsoft Corporation */
1237 /* */
1238 /* DESCRIPTION */
1239 /* */
1240 /* This function opens the specified file for reading, and returns */
1241 /* the first block of the file. */
1242 /* */
1243 /* */
1244 /* INPUT */
1245 /* */
1246 /* server_ptr Pointer to TFTP server */
1247 /* packet_ptr Pointer to TFTP request packet*/
1248 /* */
1249 /* OUTPUT */
1250 /* */
1251 /* None */
1252 /* */
1253 /* CALLS */
1254 /* */
1255 /* fx_directory_information_get Get information about file */
1256 /* fx_file_close Close file on EOF or error */
1257 /* fx_file_open Open file for reading */
1258 /* fx_file_read Read block from file */
1259 /* _nx_tftp_server_find_client_request Find client entry */
1260 /* _nx_tftp_server_send_error Send error message */
1261 /* nx_packet_allocate Allocate a new packet */
1262 /* nx_packet_release Release packet */
1263 /* nx_udp_socket_send Send TFTP data packet */
1264 /* nx_udp_source_extract Extract IP and port */
1265 /* */
1266 /* CALLED BY */
1267 /* */
1268 /* _nx_tftp_server_thread_entry TFTP Server thread */
1269 /* */
1270 /* RELEASE HISTORY */
1271 /* */
1272 /* DATE NAME DESCRIPTION */
1273 /* */
1274 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1275 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1276 /* resulting in version 6.1 */
1277 /* 01-31-2022 Yuxin Zhou Modified comment(s), */
1278 /* checked the format of the */
1279 /* received packet, improved */
1280 /* the logic of processing */
1281 /* chained packet, fixed the */
1282 /* issue of cleaning up the */
1283 /* client request entry, */
1284 /* resulting in version 6.1.10 */
1285 /* */
1286 /**************************************************************************/
_nx_tftp_server_open_for_read_process(NX_TFTP_SERVER * server_ptr,NX_PACKET * packet_ptr)1287 void _nx_tftp_server_open_for_read_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr)
1288 {
1289 NXD_ADDRESS ip_address;
1290 ULONG file_size;
1291 ULONG actual_size;
1292 UINT port;
1293 UCHAR *buffer_ptr;
1294 NX_TFTP_CLIENT_REQUEST *client_request_ptr;
1295 NX_PACKET *new_packet = NX_NULL;
1296 UINT status;
1297 UINT count = 0;
1298
1299
1300 /* Extract the source IP and port numbers. */
1301 nxd_udp_source_extract(packet_ptr, &ip_address, &port);
1302
1303 /* First, try to find a matching exiting entry in the client request structure. */
1304 client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, port, &ip_address);
1305
1306 /* See if we need to find a new entry. */
1307 if (client_request_ptr == NX_NULL)
1308 {
1309
1310 /* Yes, find a free entry in the client request structure. */
1311 client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, 0, NX_NULL);
1312 }
1313 else
1314 {
1315
1316 /* This is a dupe request. Ignore it. */
1317 nx_packet_release(packet_ptr);
1318 return;
1319 }
1320
1321 /* Determine if there was a free entry. */
1322 if (client_request_ptr == NX_NULL)
1323 {
1324
1325 /* Increment the maximum clients errors. */
1326 server_ptr -> nx_tftp_server_clients_exceeded_errors++;
1327
1328 /* Send an error to the client. */
1329 _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_NOT_DEFINED, "NetX TFTP Server: Too Many Clients");
1330
1331 /* No more clients can be serviced, release the packet. */
1332 nx_packet_release(packet_ptr);
1333 return;
1334 }
1335
1336 /* Packet chain isn't supported. */
1337 #ifndef NX_DISABLE_PACKET_CHAIN
1338 if (packet_ptr -> nx_packet_next)
1339 {
1340 nx_packet_release(packet_ptr);
1341 return;
1342 }
1343 #endif /* NX_DISABLE_PACKET_CHAIN */
1344
1345 /* Setup a pointer to the file name. */
1346 buffer_ptr = (UCHAR *) (packet_ptr -> nx_packet_prepend_ptr + 2);
1347
1348 /* The format of RRQ/WRQ packet should be:
1349 2 bytes string 1 byte string 1 byte
1350 ------------------------------------------------
1351 | Opcode | Filename | 0 | Mode | 0 |
1352 ------------------------------------------------
1353 */
1354 while (buffer_ptr < (packet_ptr -> nx_packet_append_ptr - 1))
1355 {
1356 if (*buffer_ptr == 0)
1357 {
1358 count++;
1359 if (count == 2)
1360 break;
1361 }
1362
1363 buffer_ptr++;
1364 }
1365
1366 /* Check if the format of the termination is correct. */
1367 if ((count != 1) || *(UCHAR *)(packet_ptr -> nx_packet_append_ptr - 1))
1368 {
1369 nx_packet_release(packet_ptr);
1370 return;
1371 }
1372
1373 /* Reset the pointer to the file name. */
1374 buffer_ptr = (UCHAR *) (packet_ptr -> nx_packet_prepend_ptr + 2);
1375
1376 /* Pickup the file size. */
1377 status = fx_directory_information_get(server_ptr -> nx_tftp_server_media_ptr, (CHAR *) buffer_ptr, NX_NULL, &file_size, NX_NULL, NX_NULL, NX_NULL, NX_NULL, NX_NULL, NX_NULL);
1378
1379 /* Check the return status. */
1380 if (status != FX_SUCCESS)
1381 {
1382
1383 /* Send an error to the client. */
1384 _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_FILE_NOT_FOUND, "NetX TFTP Server: File Not Found");
1385
1386 /* Unable to find the file size, release the packet. */
1387 nx_packet_release(packet_ptr);
1388 return;
1389 }
1390
1391 /* Attempt to open the file. */
1392 status = fx_file_open(server_ptr -> nx_tftp_server_media_ptr, &(client_request_ptr ->nx_tftp_client_request_file), (CHAR *) buffer_ptr, FX_OPEN_FOR_READ);
1393
1394 /* Check the return status. */
1395 if (status != FX_SUCCESS)
1396 {
1397
1398 /* Send an error to the client. */
1399 _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_FILE_NOT_FOUND, "NetX TFTP Server: File Open Failed");
1400
1401 /* Unable to open the file, release the packet. */
1402 nx_packet_release(packet_ptr);
1403 return;
1404 }
1405
1406 /* The file has been opened successfully, now try to read up to 512 bytes. */
1407
1408 /* Allocate packet for the read packet. Determine whether we are sending IP packets. */
1409 if (ip_address.nxd_ip_version == NX_IP_VERSION_V4)
1410 {
1411 status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv4_UDP_PACKET, NX_WAIT_FOREVER);
1412 }
1413 else if (ip_address.nxd_ip_version == NX_IP_VERSION_V6)
1414 {
1415 status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv6_UDP_PACKET, NX_WAIT_FOREVER);
1416 }
1417 else
1418 status = NX_TFTP_INVALID_ADDRESS_TYPE;
1419 /* Check for successful packet allocation. */
1420 if (status != NX_SUCCESS)
1421 {
1422
1423 /* Increment the number of server allocation errors. */
1424 server_ptr -> nx_tftp_server_allocation_errors++;
1425
1426 /* Unable to allocate net packet, release the original. */
1427 nx_packet_release(packet_ptr);
1428 return;
1429 }
1430
1431 if (4u + NX_TFTP_FILE_TRANSFER_MAX > ((ULONG)(new_packet -> nx_packet_data_end) - (ULONG)(new_packet -> nx_packet_append_ptr)))
1432 {
1433 /* Release the original packet. */
1434 nx_packet_release(packet_ptr);
1435
1436 nx_packet_release(new_packet);
1437 return;
1438 }
1439
1440 /* Initialize the client request structure. */
1441 #ifndef NX_DISABLE_IPV4
1442 if (ip_address.nxd_ip_version == NX_IP_VERSION_V4)
1443 {
1444
1445 client_request_ptr ->nx_tftp_client_request_ip_address.nxd_ip_version = NX_IP_VERSION_V4;
1446 client_request_ptr ->nx_tftp_client_request_ip_address.nxd_ip_address.v4 = ip_address.nxd_ip_address.v4;
1447 }
1448 else
1449 #endif /* NX_DISABLE_IPV4 */
1450 #ifdef FEATURE_NX_IPV6
1451 if (ip_address.nxd_ip_version == NX_IP_VERSION_V6)
1452 {
1453 COPY_NXD_ADDRESS(&ip_address, &(client_request_ptr ->nx_tftp_client_request_ip_address));
1454 }
1455 else
1456 #endif
1457 {
1458 /* Release the original packet. */
1459 nx_packet_release(packet_ptr);
1460
1461 return;
1462 }
1463
1464 client_request_ptr -> nx_tftp_client_request_port = port;
1465 client_request_ptr -> nx_tftp_client_request_block_number = 1;
1466 client_request_ptr -> nx_tftp_client_request_open_type = NX_TFTP_STATE_OPEN;
1467 client_request_ptr -> nx_tftp_client_request_exact_fit = NX_FALSE;
1468
1469 #ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE
1470
1471 /* Reset the retransmission timeout and retries for the client request. */
1472 client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT;
1473 client_request_ptr -> nx_tftp_client_retransmit_retries = 0;
1474 #else
1475
1476 /* Clear the count of ACK retransmits from the other side. */
1477 client_request_ptr -> nx_tftp_client_request_retransmits = 0;
1478
1479 #endif
1480
1481 client_request_ptr -> nx_tftp_client_file_size = file_size;
1482
1483 /* Read data when length of file is larger then 0. */
1484 if(file_size)
1485 {
1486
1487 /* Attempt to read the requested file. */
1488 status = fx_file_read(&(client_request_ptr ->nx_tftp_client_request_file), new_packet -> nx_packet_prepend_ptr+4, NX_TFTP_FILE_TRANSFER_MAX, &actual_size);
1489
1490 /* Check for successful file read. */
1491 if ((status != NX_SUCCESS) ||
1492 ((file_size > NX_TFTP_FILE_TRANSFER_MAX) && (actual_size != NX_TFTP_FILE_TRANSFER_MAX)) ||
1493 ((file_size < NX_TFTP_FILE_TRANSFER_MAX) && (actual_size != file_size)))
1494 {
1495
1496 /* Send an error to the client. */
1497 _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_NOT_DEFINED, "NetX TFTP Server: File Read Error");
1498
1499 /* Unable to read the file, close it and release the packet. */
1500 fx_file_close(&(client_request_ptr ->nx_tftp_client_request_file));
1501
1502 memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST));
1503
1504 nx_packet_release(packet_ptr);
1505 return;
1506 }
1507 }
1508 else
1509 {
1510
1511 actual_size = 0;
1512 }
1513
1514 /* Increment the number of total bytes sent. */
1515 server_ptr -> nx_tftp_server_total_bytes_sent += actual_size;
1516
1517 /* Setup the client request structure. */
1518 client_request_ptr -> nx_tftp_client_request_remaining_bytes = file_size - actual_size;
1519
1520 /* Determine if the file size is evenly divisible by our TFTP transfer size. */
1521 if (file_size % NX_TFTP_FILE_TRANSFER_MAX)
1522 {
1523
1524 /* Not an exact fit, ensure the exact fit flag is clear. */
1525 client_request_ptr -> nx_tftp_client_request_exact_fit = NX_FALSE;
1526 }
1527 else if (file_size > 0)
1528 {
1529
1530 /* Yes, the file size happens to be evenly divisible by the TFTP transfer size. In this
1531 case, we need to send a zero-length data packet at the end of file to let the other side
1532 know we are at the end. */
1533 client_request_ptr -> nx_tftp_client_request_exact_fit = NX_TRUE;
1534 }
1535
1536 /* Move the TFTP data code and block number into the payload before sending it to the client. */
1537 buffer_ptr = new_packet -> nx_packet_prepend_ptr;
1538 *buffer_ptr++ = 0;
1539 *buffer_ptr++ = NX_TFTP_CODE_DATA;
1540 *buffer_ptr++ = 0;
1541 *buffer_ptr++ = 1; /* First block number of file. */
1542
1543 /* Setup the packet pointers appropriately. */
1544 new_packet -> nx_packet_length = actual_size + 4;
1545 new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr + new_packet -> nx_packet_length;
1546
1547 /* Send the data packet out. */
1548 status = nxd_udp_socket_send(&(server_ptr -> nx_tftp_server_socket), new_packet, &ip_address, port);
1549
1550 /* Release packet if send fails. */
1551 if (status)
1552 {
1553 nx_packet_release(new_packet);
1554 }
1555
1556 /* Release the original packet. */
1557 nx_packet_release(packet_ptr);
1558 }
1559
1560
1561 /**************************************************************************/
1562 /* */
1563 /* FUNCTION RELEASE */
1564 /* */
1565 /* _nx_tftp_server_open_for_write_process PORTABLE C */
1566 /* 6.1.10 */
1567 /* AUTHOR */
1568 /* */
1569 /* Yuxin Zhou, Microsoft Corporation */
1570 /* */
1571 /* DESCRIPTION */
1572 /* */
1573 /* This function opens the specified file for writing, and returns */
1574 /* an ACK for block 0 to let the client know everything is good. */
1575 /* */
1576 /* */
1577 /* INPUT */
1578 /* */
1579 /* server_ptr Pointer to TFTP server */
1580 /* packet_ptr Pointer to TFTP request packet*/
1581 /* */
1582 /* OUTPUT */
1583 /* */
1584 /* None */
1585 /* */
1586 /* CALLS */
1587 /* */
1588 /* fx_file_create Create file, if necessary */
1589 /* fx_file_close Close file on EOF or error */
1590 /* fx_file_open Open file for reading */
1591 /* fx_file_write Write block to file */
1592 /* _nx_tftp_server_find_client_request Find client entry */
1593 /* _nx_tftp_server_send_error Send error message */
1594 /* nx_packet_allocate Allocate a new packet */
1595 /* nx_packet_release Release packet */
1596 /* nx_udp_socket_send Send TFTP data packet */
1597 /* nx_udp_source_extract Extract IP and port */
1598 /* */
1599 /* CALLED BY */
1600 /* */
1601 /* _nx_tftp_server_thread_entry TFTP Server thread task */
1602 /* */
1603 /* RELEASE HISTORY */
1604 /* */
1605 /* DATE NAME DESCRIPTION */
1606 /* */
1607 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1608 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1609 /* resulting in version 6.1 */
1610 /* 01-31-2022 Yuxin Zhou Modified comment(s), */
1611 /* checked the format of the */
1612 /* received packet, improved */
1613 /* the logic of processing */
1614 /* chained packet, */
1615 /* resulting in version 6.1.10 */
1616 /* */
1617 /**************************************************************************/
_nx_tftp_server_open_for_write_process(NX_TFTP_SERVER * server_ptr,NX_PACKET * packet_ptr)1618 VOID _nx_tftp_server_open_for_write_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr)
1619 {
1620 NXD_ADDRESS ip_address;
1621 UINT port;
1622 UCHAR *buffer_ptr;
1623 NX_TFTP_CLIENT_REQUEST *client_request_ptr;
1624 NX_PACKET *new_packet;
1625 UINT status;
1626 UINT count = 0;
1627
1628
1629 /* Extract the source IP and port numbers. */
1630 nxd_udp_source_extract(packet_ptr, &ip_address, &port);
1631
1632 /* First, try to find a matching exiting entry in the client request structure. */
1633 client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, port, &ip_address);
1634
1635 /* See if we need to find a new entry. */
1636 if (client_request_ptr == NX_NULL)
1637 {
1638
1639 /* Find a free entry in the client request structure. */
1640 client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, 0, NX_NULL);
1641 }
1642 else
1643 {
1644
1645 /* This is a dupe request. Ignore it. */
1646 nx_packet_release(packet_ptr);
1647 return;
1648 }
1649
1650 /* Determine if there was a free entry. */
1651 if (client_request_ptr == NX_NULL)
1652 {
1653
1654 /* Increment the maximum clients errors. */
1655 server_ptr -> nx_tftp_server_clients_exceeded_errors++;
1656
1657 /* Send an error to the client. */
1658 _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_NOT_DEFINED, "NetX TFTP Server: Too Many Clients");
1659
1660 /* No more clients can be serviced, release the packet. */
1661 nx_packet_release(packet_ptr);
1662 return;
1663 }
1664
1665 /* Packet chain isn't supported. */
1666 #ifndef NX_DISABLE_PACKET_CHAIN
1667 if (packet_ptr -> nx_packet_next)
1668 {
1669 nx_packet_release(packet_ptr);
1670 return;
1671 }
1672 #endif /* NX_DISABLE_PACKET_CHAIN */
1673
1674 /* Setup a pointer to the file name. */
1675 buffer_ptr = (UCHAR *) (packet_ptr -> nx_packet_prepend_ptr + 2);
1676
1677 /* The format of RRQ/WRQ packet should be:
1678 2 bytes string 1 byte string 1 byte
1679 ------------------------------------------------
1680 | Opcode | Filename | 0 | Mode | 0 |
1681 ------------------------------------------------
1682 */
1683 while (buffer_ptr < (packet_ptr -> nx_packet_append_ptr - 1))
1684 {
1685 if (*buffer_ptr == 0)
1686 {
1687 count++;
1688 if (count == 2)
1689 break;
1690 }
1691
1692 buffer_ptr++;
1693 }
1694
1695 /* Check if the format of the termination is correct. */
1696 if ((count != 1) || *(UCHAR *)(packet_ptr -> nx_packet_append_ptr - 1))
1697 {
1698 nx_packet_release(packet_ptr);
1699 return;
1700 }
1701
1702 /* Reset the pointer to the file name. */
1703 buffer_ptr = (UCHAR *) (packet_ptr -> nx_packet_prepend_ptr + 2);
1704
1705 /* Perform a file create. This will fail if the file is already present, which we don't care about at this point. */
1706 fx_file_delete(server_ptr -> nx_tftp_server_media_ptr, (CHAR *) buffer_ptr);
1707 fx_file_create(server_ptr -> nx_tftp_server_media_ptr, (CHAR *) buffer_ptr);
1708
1709 /* Attempt to open the file. */
1710 status = fx_file_open(server_ptr -> nx_tftp_server_media_ptr, &(client_request_ptr -> nx_tftp_client_request_file), (CHAR *) buffer_ptr, FX_OPEN_FOR_WRITE);
1711
1712 /* Check for file is open errors. */
1713 if (status != NX_SUCCESS)
1714 {
1715
1716 /* This is an actual file open error. Send an error to the client. */
1717 if (status == FX_ACCESS_ERROR)
1718 _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_ACCESS_VIOLATION, "NetX TFTP Server: File Access Error");
1719 else
1720 _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_FILE_NOT_FOUND, "NetX TFTP Server: File Open Failed");
1721
1722 /* Unable to open the file, release the packet. */
1723 nx_packet_release(packet_ptr);
1724 return;
1725 }
1726
1727 /* Now, attempt to build an ACK response to let the client know it can start writing. */
1728
1729 /* Allocate packet for the ACK packet. Determine whether we are sending IP packets. */
1730 if (ip_address.nxd_ip_version == NX_IP_VERSION_V4)
1731 {
1732 status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv4_UDP_PACKET, NX_WAIT_FOREVER);
1733 }
1734 else
1735 {
1736 status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv6_UDP_PACKET, NX_WAIT_FOREVER);
1737 }
1738
1739 /* Check for successful packet allocation. */
1740 if (status != NX_SUCCESS)
1741 {
1742
1743 /* Increment the number of server allocation errors. */
1744 server_ptr -> nx_tftp_server_allocation_errors++;
1745
1746 /* Close the file. */
1747 fx_file_close(&(client_request_ptr ->nx_tftp_client_request_file));
1748
1749 /* Unable to allocate net packet, release the original. */
1750 nx_packet_release(packet_ptr);
1751 return;
1752 }
1753
1754 if (4u > ((ULONG)(new_packet -> nx_packet_data_end) - (ULONG)(new_packet -> nx_packet_append_ptr)))
1755 {
1756 nx_packet_release(new_packet);
1757
1758 /* Release the original packet. */
1759 nx_packet_release(packet_ptr);
1760
1761 return;
1762 }
1763
1764 new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr;
1765
1766 /* Setup the client request structure. */
1767 #ifndef NX_DISABLE_IPV4
1768 if (ip_address.nxd_ip_version == NX_IP_VERSION_V4)
1769 {
1770
1771 client_request_ptr ->nx_tftp_client_request_ip_address.nxd_ip_version = NX_IP_VERSION_V4;
1772 client_request_ptr ->nx_tftp_client_request_ip_address.nxd_ip_address.v4 = ip_address.nxd_ip_address.v4;
1773 }
1774 else
1775 #endif /* NX_DISABLE_IPV4 */
1776 #ifdef FEATURE_NX_IPV6
1777 if (ip_address.nxd_ip_version == NX_IP_VERSION_V6)
1778 {
1779 COPY_NXD_ADDRESS(&ip_address, &(client_request_ptr ->nx_tftp_client_request_ip_address));
1780 }
1781 else
1782 #endif
1783 {
1784
1785 /* Close the file. */
1786 fx_file_close(&(client_request_ptr ->nx_tftp_client_request_file));
1787
1788 /* Release the original packet. */
1789 nx_packet_release(packet_ptr);
1790
1791 return;
1792 }
1793
1794
1795 client_request_ptr -> nx_tftp_client_request_port = port;
1796 client_request_ptr -> nx_tftp_client_request_block_number = 1;
1797 client_request_ptr -> nx_tftp_client_request_open_type = NX_TFTP_STATE_WRITE_OPEN;
1798 client_request_ptr -> nx_tftp_client_request_remaining_bytes = 0;
1799
1800 #ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE
1801 /* Reset retransmission timeouts and retries on current client request. */
1802 client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT;
1803 client_request_ptr -> nx_tftp_client_retransmit_retries = 0;
1804
1805 #else
1806
1807 /* Clear the count of data retransmits from the other side. */
1808 client_request_ptr -> nx_tftp_client_request_retransmits = 0;
1809 #endif
1810
1811 /* Create the ACK packet. */
1812 buffer_ptr = new_packet -> nx_packet_prepend_ptr;
1813 *buffer_ptr++ = 0;
1814 *buffer_ptr++ = NX_TFTP_CODE_ACK;
1815 *buffer_ptr++ = 0;
1816 *buffer_ptr++ = 0; /* 0, just to signal server is ready. */
1817
1818 /* Setup the packet pointers appropriately. */
1819 new_packet -> nx_packet_length = 4;
1820 new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr + 4;
1821
1822 /* Send the data packet out. */
1823 status = nxd_udp_socket_send(&(server_ptr -> nx_tftp_server_socket), new_packet, &ip_address, port);
1824
1825 /* Release packet if send fails. */
1826 if (status)
1827 {
1828 nx_packet_release(new_packet);
1829 }
1830
1831 /* Release the original packet. */
1832 nx_packet_release(packet_ptr);
1833 }
1834
1835
1836 /**************************************************************************/
1837 /* */
1838 /* FUNCTION RELEASE */
1839 /* */
1840 /* _nx_tftp_server_data_process PORTABLE C */
1841 /* 6.1.10 */
1842 /* AUTHOR */
1843 /* */
1844 /* Yuxin Zhou, Microsoft Corporation */
1845 /* */
1846 /* DESCRIPTION */
1847 /* */
1848 /* This function takes the supplied data packet and writes it to the */
1849 /* previously opened file. */
1850 /* */
1851 /* */
1852 /* INPUT */
1853 /* */
1854 /* server_ptr Pointer to TFTP server */
1855 /* packet_ptr Pointer to TFTP request packet*/
1856 /* */
1857 /* OUTPUT */
1858 /* */
1859 /* None */
1860 /* */
1861 /* CALLS */
1862 /* */
1863 /* fx_file_close Close file on EOF or error */
1864 /* fx_file_write Write block to file */
1865 /* _nx_tftp_server_find_client_request Find client entry */
1866 /* _nx_tftp_server_send_error Send error message */
1867 /* nx_packet_allocate Allocate a new packet */
1868 /* nx_packet_copy Copy packet */
1869 /* nx_packet_release Release packet */
1870 /* nx_udp_socket_send Send TFTP ACK packet */
1871 /* nx_udp_source_extract Extract IP and port */
1872 /* */
1873 /* CALLED BY */
1874 /* */
1875 /* _nx_tftp_server_thread_entry TFTP Server thread loop */
1876 /* */
1877 /* RELEASE HISTORY */
1878 /* */
1879 /* DATE NAME DESCRIPTION */
1880 /* */
1881 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1882 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1883 /* resulting in version 6.1 */
1884 /* 01-31-2022 Yuxin Zhou Modified comment(s), improved */
1885 /* the logic of processing */
1886 /* chained packet, */
1887 /* resulting in version 6.1.10 */
1888 /* */
1889 /**************************************************************************/
_nx_tftp_server_data_process(NX_TFTP_SERVER * server_ptr,NX_PACKET * packet_ptr)1890 VOID _nx_tftp_server_data_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr)
1891 {
1892
1893 NXD_ADDRESS ip_address;
1894 UINT port;
1895 USHORT block_number;
1896 ULONG bytes_copyed;
1897 NX_TFTP_CLIENT_REQUEST *client_request_ptr;
1898 UINT status;
1899
1900 /* Extract the source IP and port numbers. */
1901 nxd_udp_source_extract(packet_ptr, &ip_address, &port);
1902
1903 /* Find the matching entry in the client request structure. */
1904 client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, port, &ip_address);
1905
1906
1907 /* Determine if there was a matching entry. */
1908 if (client_request_ptr == NX_NULL)
1909 {
1910
1911 /* Increment the unknown clients errors. */
1912 server_ptr -> nx_tftp_server_unknown_clients_errors++;
1913
1914 /* Send an error to the client. */
1915 _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_NO_SUCH_USER, "NetX TFTP Server: Unknown connection");
1916
1917 /* No more clients can be serviced, release the packet. */
1918 nx_packet_release(packet_ptr);
1919
1920 return;
1921 }
1922
1923 /* Pickup the block number. */
1924 status = nx_packet_data_extract_offset(packet_ptr, 2, (UCHAR *)&block_number, sizeof(block_number), &bytes_copyed);
1925
1926 /* Check return status. */
1927 if (status || (bytes_copyed != 2))
1928 {
1929 nx_packet_release(packet_ptr);
1930 return;
1931 }
1932
1933 /* Adjust the endianness. */
1934 NX_CHANGE_USHORT_ENDIAN(block_number);
1935
1936 /* Determine if this block number matches the current client block number. */
1937 if (client_request_ptr -> nx_tftp_client_request_block_number != block_number)
1938 {
1939
1940 /* No, it does not. */
1941
1942 /* Check if it matches our previous ACK e.g. it could be a retransmit from the other side. */
1943 if (client_request_ptr -> nx_tftp_client_request_block_number == (USHORT)(block_number + 1))
1944 {
1945
1946 #ifndef NX_TFTP_SERVER_RETRANSMIT_ENABLE
1947
1948 /* It does. Update how many we have received. */
1949 client_request_ptr -> nx_tftp_client_request_retransmits++;
1950
1951 /* Decide if we should close the client request. */
1952 if (client_request_ptr -> nx_tftp_client_request_retransmits <= NX_TFTP_MAX_CLIENT_RETRANSMITS)
1953 {
1954
1955 /* Not yet. Just drop the packet for now. */
1956 nx_packet_release(packet_ptr);
1957
1958 return;
1959 }
1960 /* Else handle as an error. */
1961 #else
1962 nx_packet_release(packet_ptr);
1963
1964 /* (Let the retransmit timeout handler retransmit our ACK to the client.) */
1965 return;
1966 #endif
1967 }
1968
1969 /* Send an error to the client. */
1970 _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_ILLEGAL_OPERATION, "NetX TFTP Server: Bad block number");
1971
1972 /* Error, close the file, release the packet and delete the client request. */
1973 fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
1974
1975 /* Release the packet. */
1976 nx_packet_release(packet_ptr);
1977
1978 memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST));
1979
1980 return;
1981 }
1982
1983 /* At this point we have a valid packet. */
1984
1985 #ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE
1986
1987 /* Reset the retransmit retry counter and retransmit timeout. */
1988 client_request_ptr -> nx_tftp_client_retransmit_retries = 0;
1989 client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT;
1990 #else
1991
1992 /* Clear the count of retransmits from the other side. */
1993 client_request_ptr -> nx_tftp_client_request_retransmits = 0;
1994 #endif
1995
1996 /* Determine if there is anything to write. */
1997 if (packet_ptr -> nx_packet_length > 4)
1998 {
1999
2000 /* At this point, we need to write the next block of the file. */
2001
2002 #ifndef NX_DISABLE_PACKET_CHAIN
2003 /* Determine if the current packet is chained. */
2004 if (packet_ptr -> nx_packet_next)
2005 {
2006
2007 NX_PACKET *temp_ptr;
2008
2009
2010 /* Yes, the packet is chained. We have to copy the receive packet into a packet with the
2011 a payload of at least 560 bytes so the write request can be supplied with just the
2012 payload pointer. */
2013 status = nx_packet_copy(packet_ptr, &temp_ptr, server_ptr -> nx_tftp_server_packet_pool_ptr, NX_WAIT_FOREVER);
2014
2015 /* Check for successful packet copy. */
2016 if (status != NX_SUCCESS)
2017 {
2018
2019 /* Increment the number of server allocation errors. */
2020 server_ptr -> nx_tftp_server_allocation_errors++;
2021
2022 /* Unable to allocate net packet, release the original. */
2023 fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
2024
2025 nx_packet_release(packet_ptr);
2026
2027 memset(client_request_ptr,0, sizeof(NX_TFTP_CLIENT_REQUEST));
2028
2029 return;
2030 }
2031
2032 /* Successful packet copy. Release the original packet and reassign the packet pointer variable. */
2033 nx_packet_release(packet_ptr);
2034 packet_ptr = temp_ptr;
2035 }
2036 #endif /* NX_DISABLE_PACKET_CHAIN */
2037
2038 /* Attempt to write the block to the file. */
2039 status = fx_file_write(&(client_request_ptr -> nx_tftp_client_request_file), packet_ptr -> nx_packet_prepend_ptr+4,
2040 packet_ptr -> nx_packet_length - 4);
2041
2042 /* Check for successful file write. */
2043 if (status != NX_SUCCESS)
2044 {
2045
2046 /* Send an error to the client. */
2047 _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_NOT_DEFINED, "NetX TFTP Server: File Write Error");
2048
2049 /* Unable to write the file, close it and release the packet. */
2050 fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
2051
2052 nx_packet_release(packet_ptr);
2053
2054 return;
2055 }
2056 }
2057
2058 /* Check the last packet. */
2059 if (packet_ptr -> nx_packet_length - 4 < NX_TFTP_FILE_TRANSFER_MAX)
2060 {
2061 fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
2062 }
2063
2064 status = _nx_tftp_server_send_ack(server_ptr, client_request_ptr, NX_FALSE);
2065
2066 if (status == NX_SUCCESS)
2067 {
2068
2069 /* Increment the number of total bytes received. */
2070 server_ptr -> nx_tftp_server_total_bytes_received += (packet_ptr -> nx_packet_length - 4);
2071
2072 /* Determine if this was the last write. */
2073 if ((packet_ptr -> nx_packet_length - 4) < NX_TFTP_FILE_TRANSFER_MAX)
2074 {
2075
2076 /* No, nothing left to write. Close the file, release the packet and delete
2077 the client request. */
2078 fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
2079 memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST));
2080 }
2081 }
2082
2083 /* Release the original packet. */
2084 nx_packet_release(packet_ptr);
2085
2086 return;
2087 }
2088
2089
2090 /**************************************************************************/
2091 /* */
2092 /* FUNCTION RELEASE */
2093 /* */
2094 /* _nx_tftp_server_ack_process PORTABLE C */
2095 /* 6.1.10 */
2096 /* AUTHOR */
2097 /* */
2098 /* Yuxin Zhou, Microsoft Corporation */
2099 /* */
2100 /* DESCRIPTION */
2101 /* */
2102 /* This function processes an ACK to the previous file read */
2103 /* operation and prepares the next data packet to send if necessary. */
2104 /* */
2105 /* */
2106 /* INPUT */
2107 /* */
2108 /* server_ptr Pointer to TFTP server */
2109 /* packet_ptr Pointer to TFTP request packet*/
2110 /* */
2111 /* OUTPUT */
2112 /* */
2113 /* None */
2114 /* */
2115 /* CALLS */
2116 /* */
2117 /* fx_file_close Close file on EOF or error */
2118 /* fx_file_read Read block from file */
2119 /* _nx_tftp_server_find_client_request Find client entry */
2120 /* _nx_tftp_server_send_error Send error message */
2121 /* nx_packet_allocate Allocate a new packet */
2122 /* nx_packet_copy Copy packet */
2123 /* nx_packet_release Release packet */
2124 /* nx_udp_socket_send Send TFTP data packet */
2125 /* nx_udp_source_extract Extract IP and port */
2126 /* */
2127 /* CALLED BY */
2128 /* */
2129 /* _nx_tftp_server_thread_entry TFTP Server thread */
2130 /* */
2131 /* RELEASE HISTORY */
2132 /* */
2133 /* DATE NAME DESCRIPTION */
2134 /* */
2135 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2136 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2137 /* resulting in version 6.1 */
2138 /* 01-31-2022 Yuxin Zhou Modified comment(s), improved */
2139 /* the logic of processing */
2140 /* chained packet, */
2141 /* resulting in version 6.1.10 */
2142 /* */
2143 /**************************************************************************/
_nx_tftp_server_ack_process(NX_TFTP_SERVER * server_ptr,NX_PACKET * packet_ptr)2144 VOID _nx_tftp_server_ack_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr)
2145 {
2146
2147 NXD_ADDRESS ip_address;
2148 UINT port;
2149 USHORT block_number;
2150 ULONG bytes_copyed;
2151 NX_TFTP_CLIENT_REQUEST *client_request_ptr;
2152 UINT status;
2153
2154
2155 /* Extract the source IP and port numbers. */
2156 nxd_udp_source_extract(packet_ptr, &ip_address, &port);
2157
2158
2159 /* Find a matching entry in the client request structure. */
2160 client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, port, &ip_address);
2161
2162 /* Determine if there was a matching entry. */
2163 if (client_request_ptr == NX_NULL)
2164 {
2165
2166 /* Increment the unknown clients errors. */
2167 server_ptr -> nx_tftp_server_unknown_clients_errors++;
2168
2169 /* Send an error to the client. */
2170 _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_NO_SUCH_USER, "NetX TFTP Server: Unknown connection");
2171
2172 /* No more clients can be serviced, release the packet. */
2173 nx_packet_release(packet_ptr);
2174 return;
2175 }
2176
2177 /* Pickup the block number. */
2178 status = nx_packet_data_extract_offset(packet_ptr, 2, (UCHAR *)&block_number, sizeof(block_number), &bytes_copyed);
2179
2180 /* Check return status. */
2181 if (status || (bytes_copyed != 2))
2182 {
2183 nx_packet_release(packet_ptr);
2184 return;
2185 }
2186
2187 /* Adjust the endianness. */
2188 NX_CHANGE_USHORT_ENDIAN(block_number);
2189
2190 /* Determine if this block number matches the request. */
2191 if (client_request_ptr -> nx_tftp_client_request_block_number != block_number)
2192 {
2193
2194 /* Check if this is a retransmitted ACK e.g. our previous data packet was dropped our
2195 delayed. */
2196 if (client_request_ptr -> nx_tftp_client_request_block_number == (USHORT)(block_number + 1))
2197 {
2198
2199 #ifndef NX_TFTP_SERVER_RETRANSMIT_ENABLE
2200
2201 /* It does. Update how many we have received. */
2202 client_request_ptr -> nx_tftp_client_request_retransmits++;
2203
2204 /* Decide if we should close the client request. */
2205 if (client_request_ptr -> nx_tftp_client_request_retransmits <= NX_TFTP_MAX_CLIENT_RETRANSMITS)
2206 {
2207
2208 /* Not yet. Just drop the packet for now. */
2209 nx_packet_release(packet_ptr);
2210
2211 return;
2212 }
2213
2214 /* Else handle as an error. */
2215 #else
2216 nx_packet_release(packet_ptr);
2217
2218 /* (Let the retransmit timeout handler retransmit our data to the client.) */
2219 return;
2220 #endif
2221 }
2222
2223 /* Send an error to the client. */
2224 _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_ILLEGAL_OPERATION, "NetX TFTP Server: Bad block number");
2225
2226 /* Error, close the file, release the packet and delete the client request. */
2227 fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
2228
2229 nx_packet_release(packet_ptr);
2230
2231 memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST));
2232
2233 return;
2234 }
2235
2236 /* The block number matches, see if there is anything left to send. */
2237 if ((client_request_ptr -> nx_tftp_client_request_remaining_bytes == 0) &&
2238 (client_request_ptr -> nx_tftp_client_request_exact_fit == NX_FALSE))
2239 {
2240
2241 /* No, nothing left to send. Close the file, release the packet and delete
2242 the client request. */
2243 fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
2244
2245 nx_packet_release(packet_ptr);
2246
2247 memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST));
2248
2249 return;
2250 }
2251
2252 #ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE
2253 /* We have a valid ACK. Reset the retransmit retry counter and retransmit timeout. */
2254 client_request_ptr -> nx_tftp_client_retransmit_retries = 0;
2255 client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT;
2256 #endif
2257
2258 /* At this point, we need to send the next block of the file. */
2259 _nx_tftp_server_send_data(server_ptr, client_request_ptr, NX_FALSE);
2260
2261 /* Release the original packet. */
2262 nx_packet_release(packet_ptr);
2263
2264 return;
2265 }
2266
2267
2268 /**************************************************************************/
2269 /* */
2270 /* FUNCTION RELEASE */
2271 /* */
2272 /* _nx_tftp_server_send_data PORTABLE C */
2273 /* 6.1 */
2274 /* AUTHOR */
2275 /* */
2276 /* Yuxin Zhou, Microsoft Corporation */
2277 /* */
2278 /* DESCRIPTION */
2279 /* */
2280 /* This function creates a data packet based on the last ACK received */
2281 /* and sends it out. This will also retransmit a data packet if */
2282 /* specified. On error it will close the file and the client request. */
2283 /* It does not update the Client request e.g. block number. */
2284 /* */
2285 /* INPUT */
2286 /* */
2287 /* server_ptr Pointer to TFTP server */
2288 /* client_request_ptr Pointer to Client request */
2289 /* retransmit Indicate if retransmiting a */
2290 /* previously sent ACK */
2291 /* */
2292 /* OUTPUT */
2293 /* */
2294 /* status Completion status */
2295 /* */
2296 /* CALLS */
2297 /* */
2298 /* _nx_tftp_server_close_client_request Terminate a client request */
2299 /* _nx_tftp_server_send_error Send error status to Client */
2300 /* nx_packet_allocate Allocate a new packet */
2301 /* nx_udp_socket_send Send TFTP data packet */
2302 /* fx_file_seek Set location in file */
2303 /* fx_file_read Read from set location in file*/
2304 /* */
2305 /* CALLED BY */
2306 /* */
2307 /* _nx_tftp_server_timer_process TFTP timeout event */
2308 /* _nx_tftp_server_ack_process Process a received ACK */
2309 /* */
2310 /* RELEASE HISTORY */
2311 /* */
2312 /* DATE NAME DESCRIPTION */
2313 /* */
2314 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2315 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2316 /* resulting in version 6.1 */
2317 /* */
2318 /**************************************************************************/
_nx_tftp_server_send_data(NX_TFTP_SERVER * server_ptr,NX_TFTP_CLIENT_REQUEST * client_request_ptr,UINT retransmit)2319 UINT _nx_tftp_server_send_data(NX_TFTP_SERVER *server_ptr, NX_TFTP_CLIENT_REQUEST *client_request_ptr, UINT retransmit)
2320 {
2321
2322 UINT status;
2323 ULONG actual_size = 0;
2324 NX_PACKET *new_packet;
2325 UCHAR *buffer_ptr;
2326
2327
2328 /* Allocate packet for the read packet. Determine whether we are sending IP packets. */
2329 if (client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_version == NX_IP_VERSION_V4)
2330 {
2331 status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv4_UDP_PACKET, NX_WAIT_FOREVER);
2332 }
2333 else
2334 {
2335 status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv6_UDP_PACKET, NX_WAIT_FOREVER);
2336 }
2337
2338
2339 /* Check for successful packet allocation. */
2340 if (status != NX_SUCCESS)
2341 {
2342
2343 /* Increment the number of server allocation errors. */
2344 server_ptr -> nx_tftp_server_allocation_errors++;
2345
2346 /* Unable to allocate net packet, release the original. */
2347 fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
2348
2349 memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST));
2350
2351 return status;
2352 }
2353
2354 if (4u + NX_TFTP_FILE_TRANSFER_MAX > ((ULONG)(new_packet -> nx_packet_data_end) - (ULONG)(new_packet -> nx_packet_append_ptr)))
2355 {
2356 nx_packet_release(new_packet);
2357 return(NX_SIZE_ERROR);
2358 }
2359
2360 new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr;
2361
2362 /* Determine if there are more bytes to read. */
2363 if (client_request_ptr -> nx_tftp_client_request_remaining_bytes)
2364 {
2365
2366 status = NX_SUCCESS;
2367
2368 /* Are we retransmitting? */
2369 if (retransmit)
2370 {
2371
2372 /* Yes, figure out where to reset the file pointer to the previous
2373 file read so we can retrieve the previous data we sent. */
2374 UINT index = client_request_ptr -> nx_tftp_client_file_size -
2375 client_request_ptr -> nx_tftp_client_request_remaining_bytes -
2376 client_request_ptr -> nx_tftp_client_previous_write_size;
2377
2378 status = fx_file_seek(&(client_request_ptr -> nx_tftp_client_request_file), index);
2379 }
2380
2381 /* Are we still ok to do a file read? */
2382 if (status == NX_SUCCESS)
2383 {
2384
2385 /* Yes. Attempt to read the requested file. */
2386 UINT status_read = fx_file_read(&(client_request_ptr -> nx_tftp_client_request_file), new_packet -> nx_packet_prepend_ptr+4,
2387 NX_TFTP_FILE_TRANSFER_MAX, &actual_size);
2388
2389 /* Check for successful file read. */
2390 if ((status_read != NX_SUCCESS) ||
2391 ((client_request_ptr -> nx_tftp_client_request_remaining_bytes > NX_TFTP_FILE_TRANSFER_MAX) && (actual_size < NX_TFTP_FILE_TRANSFER_MAX)) ||
2392 ((client_request_ptr -> nx_tftp_client_request_remaining_bytes < NX_TFTP_FILE_TRANSFER_MAX) && (actual_size != client_request_ptr -> nx_tftp_client_request_remaining_bytes)))
2393 {
2394
2395 /* Update our 'status' variable with the result from file read. */
2396 status = status_read;
2397 }
2398 }
2399
2400 /* Are we ok to transmit more data? */
2401 if (status != NX_SUCCESS)
2402 {
2403
2404 /* No, send an error back to the client. */
2405 _nx_tftp_server_send_error(server_ptr, &client_request_ptr -> nx_tftp_client_request_ip_address,
2406 client_request_ptr -> nx_tftp_client_request_port,
2407 NX_TFTP_ERROR_NOT_DEFINED, "NetX TFTP Server: File Read Error");
2408
2409 memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST));
2410
2411 /* Unable to read the file, close it and release the packet. */
2412 fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
2413
2414 nx_packet_release(new_packet);
2415
2416 return status;
2417 }
2418 }
2419 else
2420 {
2421
2422 /* Clear the exact fit flag since the only way we can be here is if the TFTP transfer size
2423 evenly divided into the file size and we need to send a zero length data buffer to signal
2424 the end of the file. */
2425 client_request_ptr -> nx_tftp_client_request_exact_fit = NX_FALSE;
2426
2427 /* Set the actual size to zero for exact fit case. */
2428 actual_size = 0;
2429 }
2430
2431 /* Increment the number of total bytes sent. */
2432 server_ptr -> nx_tftp_server_total_bytes_sent += actual_size;
2433
2434 /* Is this new data being sent (not a retransmit)? */
2435 if (retransmit == NX_FALSE)
2436 {
2437
2438 /* Yes, so advance the block number and number of bytes of the file sent. */
2439 client_request_ptr -> nx_tftp_client_request_block_number++;
2440
2441 client_request_ptr -> nx_tftp_client_request_remaining_bytes -= actual_size;
2442 }
2443
2444 client_request_ptr -> nx_tftp_client_previous_write_size = actual_size;
2445
2446 /* Move the TFTP data code and block number into the payload before sending it to the client. */
2447 buffer_ptr = new_packet -> nx_packet_prepend_ptr;
2448 *buffer_ptr++ = 0;
2449 *buffer_ptr++ = NX_TFTP_CODE_DATA;
2450 *buffer_ptr++ = (UCHAR) (client_request_ptr -> nx_tftp_client_request_block_number >> 8);
2451 *buffer_ptr++ = (UCHAR) (client_request_ptr -> nx_tftp_client_request_block_number & 0xFF);
2452
2453 /* Setup the packet pointers appropriately. */
2454 new_packet -> nx_packet_length = actual_size + 4;
2455 new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr + new_packet -> nx_packet_length;
2456
2457 /* Send the data packet out. */
2458 status = nxd_udp_socket_send(&(server_ptr -> nx_tftp_server_socket), new_packet, &client_request_ptr -> nx_tftp_client_request_ip_address,
2459 client_request_ptr -> nx_tftp_client_request_port);
2460
2461 /* Release packet if send fails. */
2462 if (status)
2463 {
2464 nx_packet_release(new_packet);
2465 }
2466
2467 return NX_SUCCESS;
2468 }
2469
2470
2471 /**************************************************************************/
2472 /* */
2473 /* FUNCTION RELEASE */
2474 /* */
2475 /* _nx_tftp_server_send_ack PORTABLE C */
2476 /* 6.1 */
2477 /* AUTHOR */
2478 /* */
2479 /* Yuxin Zhou, Microsoft Corporation */
2480 /* */
2481 /* DESCRIPTION */
2482 /* */
2483 /* This function creates an ACK packet based on the last block of data */
2484 /* received, and sends it out. This will also retransmit an ACK if */
2485 /* specified. On error it will close the file and the client request. */
2486 /* It does not update the Client request e.g. block number. */
2487 /* */
2488 /* INPUT */
2489 /* */
2490 /* server_ptr Pointer to TFTP server */
2491 /* client_request_ptr Pointer to Client request */
2492 /* retransmit Indicate if retransmiting a */
2493 /* previously sent ACK */
2494 /* */
2495 /* OUTPUT */
2496 /* */
2497 /* status Completion status */
2498 /* */
2499 /* CALLS */
2500 /* */
2501 /* _nx_tftp_server_close_client_request Terminate a client request */
2502 /* nx_packet_allocate Allocate a new packet */
2503 /* nx_udp_socket_send Send TFTP data packet */
2504 /* */
2505 /* CALLED BY */
2506 /* */
2507 /* _nx_tftp_server_timer_process TFTP timeout event */
2508 /* _nx_tftp_server_data_process Process a received packet */
2509 /* */
2510 /* RELEASE HISTORY */
2511 /* */
2512 /* DATE NAME DESCRIPTION */
2513 /* */
2514 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2515 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2516 /* resulting in version 6.1 */
2517 /* */
2518 /**************************************************************************/
_nx_tftp_server_send_ack(NX_TFTP_SERVER * server_ptr,NX_TFTP_CLIENT_REQUEST * client_request_ptr,UINT retransmit)2519 UINT _nx_tftp_server_send_ack(NX_TFTP_SERVER *server_ptr, NX_TFTP_CLIENT_REQUEST *client_request_ptr, UINT retransmit)
2520 {
2521
2522 UINT status;
2523 UCHAR *buffer_ptr;
2524 NX_PACKET *new_packet;
2525
2526
2527 /* Allocate packet for the ACK. Determine whether we are sending IP packets. */
2528 if (client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_version == NX_IP_VERSION_V4)
2529 {
2530 status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv4_UDP_PACKET, NX_WAIT_FOREVER);
2531 }
2532 else
2533 {
2534 status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv6_UDP_PACKET, NX_WAIT_FOREVER);
2535 }
2536
2537 /* Check for successful packet allocation. */
2538 if (status != NX_SUCCESS)
2539 {
2540
2541 /* Increment the number of server allocation errors. */
2542 server_ptr -> nx_tftp_server_allocation_errors++;
2543
2544 /* Unable to allocate net packet, release the original. */
2545 fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
2546
2547 memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST));
2548
2549 return status;
2550 }
2551
2552 if (4u > ((ULONG)(new_packet -> nx_packet_data_end) - (ULONG)(new_packet -> nx_packet_append_ptr)))
2553 {
2554 nx_packet_release(new_packet);
2555 return(NX_SIZE_ERROR);
2556 }
2557
2558 new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr;
2559
2560 /* Now build the ACK message to the client. */
2561 buffer_ptr = new_packet -> nx_packet_prepend_ptr;
2562 *buffer_ptr++ = 0;
2563 *buffer_ptr++ = NX_TFTP_CODE_ACK;
2564
2565 /* If we are retransmitting, send the block number of the previous ACK. */
2566 if (retransmit)
2567 {
2568
2569 *buffer_ptr++ = (UCHAR) ((client_request_ptr -> nx_tftp_client_request_block_number - 1) >> 8);
2570 *buffer_ptr++ = (UCHAR) ((client_request_ptr -> nx_tftp_client_request_block_number - 1) & 0xFF);
2571 }
2572 else
2573 {
2574
2575 *buffer_ptr++ = (UCHAR) ((client_request_ptr -> nx_tftp_client_request_block_number) >> 8);
2576 *buffer_ptr++ = (UCHAR) (client_request_ptr -> nx_tftp_client_request_block_number & 0xFF);
2577 }
2578
2579 /* Setup the packet pointers appropriately. */
2580 new_packet -> nx_packet_length = 4;
2581 new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr + 4;
2582
2583 /* Send the ACK packet out. */
2584 status = nxd_udp_socket_send(&(server_ptr -> nx_tftp_server_socket), new_packet, &client_request_ptr -> nx_tftp_client_request_ip_address,
2585 client_request_ptr -> nx_tftp_client_request_port);
2586
2587 /* Release packet if send fails. */
2588 if (status)
2589 {
2590 nx_packet_release(new_packet);
2591 }
2592
2593 /* Is this ACK for new data received (e.g. not a retransmit)? */
2594 if (retransmit == NX_FALSE)
2595 {
2596
2597 /* Yes, so increase the block number. */
2598 client_request_ptr -> nx_tftp_client_request_block_number++;
2599 }
2600
2601 return NX_SUCCESS;
2602 }
2603
2604
2605 /**************************************************************************/
2606 /* */
2607 /* FUNCTION RELEASE */
2608 /* */
2609 /* _nx_tftp_server_error_process PORTABLE C */
2610 /* 6.1.10 */
2611 /* AUTHOR */
2612 /* */
2613 /* Yuxin Zhou, Microsoft Corporation */
2614 /* */
2615 /* DESCRIPTION */
2616 /* */
2617 /* This function processes an error sent by a client. */
2618 /* */
2619 /* */
2620 /* INPUT */
2621 /* */
2622 /* server_ptr Pointer to TFTP server */
2623 /* packet_ptr Pointer to TFTP request packet*/
2624 /* */
2625 /* OUTPUT */
2626 /* */
2627 /* None */
2628 /* */
2629 /* CALLS */
2630 /* */
2631 /* nx_packet_release Release packet */
2632 /* */
2633 /* CALLED BY */
2634 /* */
2635 /* _nx_tftp_server_thread_entry TFTP Server thread task */
2636 /* */
2637 /* RELEASE HISTORY */
2638 /* */
2639 /* DATE NAME DESCRIPTION */
2640 /* */
2641 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2642 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2643 /* resulting in version 6.1 */
2644 /* 01-31-2022 Yuxin Zhou Modified comment(s), improved */
2645 /* the logic of processing */
2646 /* chained packet, */
2647 /* resulting in version 6.1.10 */
2648 /* */
2649 /**************************************************************************/
_nx_tftp_server_error_process(NX_TFTP_SERVER * server_ptr,NX_PACKET * packet_ptr)2650 VOID _nx_tftp_server_error_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr)
2651 {
2652
2653 UINT i;
2654 UCHAR *buffer_ptr;
2655 UINT port;
2656 NXD_ADDRESS ip_address;
2657 NX_TFTP_CLIENT_REQUEST *client_request_ptr;
2658
2659 /* Packet chain isn't supported. */
2660 #ifndef NX_DISABLE_PACKET_CHAIN
2661 if (packet_ptr -> nx_packet_next)
2662 {
2663 nx_packet_release(packet_ptr);
2664 return;
2665 }
2666 #endif /* NX_DISABLE_PACKET_CHAIN */
2667
2668 /* Pickup a pointer to the error code in the buffer. */
2669 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr + 2;
2670
2671 /* Set the error code in the server control block. */
2672 server_ptr -> nx_tftp_server_error_code = (((UINT) (*buffer_ptr)) << 8);
2673 buffer_ptr++;
2674 server_ptr -> nx_tftp_server_error_code |= ((UINT) (*buffer_ptr) & 0xFF);
2675 buffer_ptr++;
2676
2677 /* Loop to save error message. */
2678 server_ptr -> nx_tftp_server_error_string[sizeof(server_ptr -> nx_tftp_server_error_string) - 1] = NX_NULL;
2679 for (i = 0; i < NX_TFTP_ERROR_STRING_MAX; i++)
2680 {
2681
2682 /* Store desired file name. */
2683 server_ptr -> nx_tftp_server_error_string[i] = (CHAR) *buffer_ptr++;
2684
2685 /* Check for NULL character. */
2686 if (server_ptr -> nx_tftp_server_error_string[i] == NX_NULL)
2687 break;
2688
2689 /* Check for packet buffer boundary. */
2690 if (buffer_ptr >= packet_ptr -> nx_packet_append_ptr)
2691 break;
2692 }
2693
2694 /* Extract the source IP and port numbers. */
2695
2696 nxd_udp_source_extract(packet_ptr, &ip_address, &port);
2697
2698 /* First, try to find a matching existing entry in the client request structure. */
2699 client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, port, &ip_address);
2700
2701 /* Reset the retransmit timeout on the client request. */
2702 if (client_request_ptr)
2703 {
2704 #ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE
2705
2706 client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT;
2707 client_request_ptr -> nx_tftp_client_retransmit_retries = 0;
2708 #else
2709
2710 client_request_ptr -> nx_tftp_client_request_retransmits = 0;
2711
2712 #endif /* NX_TFTP_SERVER_RETRANSMIT_ENABLE */
2713 }
2714
2715 /* Release the packet. */
2716 nx_packet_release(packet_ptr);
2717 }
2718
2719
2720 /**************************************************************************/
2721 /* */
2722 /* FUNCTION RELEASE */
2723 /* */
2724 /* _nx_tftp_server_find_client_request PORTABLE C */
2725 /* 6.1 */
2726 /* AUTHOR */
2727 /* */
2728 /* Yuxin Zhou, Microsoft Corporation */
2729 /* */
2730 /* DESCRIPTION */
2731 /* */
2732 /* This function attempts to find the specified IP and port number in */
2733 /* the client request array of this TFTP server instance. */
2734 /* */
2735 /* */
2736 /* INPUT */
2737 /* */
2738 /* server_ptr Pointer to TFTP server */
2739 /* port Client port number */
2740 /* ip_address Client IP address */
2741 /* */
2742 /* OUTPUT */
2743 /* */
2744 /* NX_TFTP_CLIENT_REQUEST * NULL if not found */
2745 /* Non null if match found */
2746 /* */
2747 /* CALLS */
2748 /* */
2749 /* nx_packet_release Release packet */
2750 /* */
2751 /* CALLED BY */
2752 /* */
2753 /* _nx_tftp_server_ack_process ACK processing */
2754 /* _nx_tftp_server_data_process Data packet processing */
2755 /* _nx_tftp_server_open_for_write_process Open for write processing */
2756 /* _nx_tftp_server_open_for_read_process Open for read processing */
2757 /* */
2758 /* RELEASE HISTORY */
2759 /* */
2760 /* DATE NAME DESCRIPTION */
2761 /* */
2762 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2763 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2764 /* resulting in version 6.1 */
2765 /* */
2766 /**************************************************************************/
_nx_tftp_server_find_client_request(NX_TFTP_SERVER * server_ptr,UINT port,NXD_ADDRESS * ip_address)2767 NX_TFTP_CLIENT_REQUEST * _nx_tftp_server_find_client_request(NX_TFTP_SERVER *server_ptr, UINT port, NXD_ADDRESS *ip_address)
2768 {
2769
2770 UINT i;
2771 NX_TFTP_CLIENT_REQUEST *client_request_ptr;
2772
2773 /* First, find a free entry in the client request structure. */
2774 i = 0;
2775 for (i = 0; i < NX_TFTP_MAX_CLIENTS; i++)
2776 {
2777 client_request_ptr = &(server_ptr -> nx_tftp_server_client_list[i]);
2778
2779 /* First check if we are adding an address. If the caller sends in a blank
2780 address and port, we are. */
2781 if (port == 0)
2782 {
2783
2784 /* We are adding an address. Now check if this slot is empty. */
2785
2786 if (client_request_ptr -> nx_tftp_client_request_port == 0)
2787 {
2788
2789 /* If there is no port number, this is an empty slot. But let's clear the slot anyway. */
2790 memset(&(server_ptr -> nx_tftp_server_client_list[i]), 0, sizeof(NX_TFTP_CLIENT_REQUEST));
2791
2792 break;
2793 }
2794 }
2795 /* This is a valid address. Does it match the current entry? */
2796 else
2797 {
2798 /* Check if it is an IPv4 or IPv6 packet. */
2799 if (ip_address -> nxd_ip_version == NX_IP_VERSION_V4)
2800 {
2801
2802 #ifndef NX_DISABLE_IPV4
2803 /* This is an IPv4 request packet. */
2804 if ((client_request_ptr -> nx_tftp_client_request_port == port) &&
2805 (client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_address.v4 == ip_address -> nxd_ip_address.v4))
2806 {
2807
2808 /* Yes, they match! */
2809 break;
2810 }
2811 #else
2812 return NX_NULL;
2813 #endif /* NX_DISABLE_IPV4 */
2814 }
2815 else if (ip_address -> nxd_ip_version == NX_IP_VERSION_V6)
2816 {
2817
2818 #ifndef FEATURE_NX_IPV6
2819 return NX_NULL;
2820 #else
2821 /* This is an IPv6 request packet. */
2822 if ((client_request_ptr -> nx_tftp_client_request_port == port) &&
2823 (CHECK_IPV6_ADDRESSES_SAME(&client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_address.v6[0], &ip_address -> nxd_ip_address.v6[0])))
2824 {
2825
2826 /* Yes, they match! */
2827 break;
2828 }
2829 #endif
2830 }
2831 }
2832 }
2833
2834 /* Determine if a match was found. */
2835 if (i < NX_TFTP_MAX_CLIENTS)
2836 {
2837 /* Return a pointer to the matching client request. */
2838 return(&(server_ptr -> nx_tftp_server_client_list[i]));
2839 }
2840 else
2841 {
2842 /* Return a NULL pointer indicating no match found. */
2843 return((NX_TFTP_CLIENT_REQUEST *)NX_NULL);
2844 }
2845 }
2846
2847
2848 /**************************************************************************/
2849 /* */
2850 /* FUNCTION RELEASE */
2851 /* */
2852 /* _nx_tftp_server_send_error PORTABLE C */
2853 /* 6.1 */
2854 /* AUTHOR */
2855 /* */
2856 /* Yuxin Zhou, Microsoft Corporation */
2857 /* */
2858 /* DESCRIPTION */
2859 /* */
2860 /* This function send a TFTP error message to the client specified */
2861 /* by the port and IP address. */
2862 /* */
2863 /* */
2864 /* INPUT */
2865 /* */
2866 /* server_ptr Pointer to TFTP server */
2867 /* ip_address Client IP address */
2868 /* port Client port number */
2869 /* error TFTP error code */
2870 /* error_message Error string */
2871 /* */
2872 /* OUTPUT */
2873 /* */
2874 /* None */
2875 /* */
2876 /* CALLS */
2877 /* */
2878 /* nx_packet_allocate Allocate error packet */
2879 /* nx_udp_socket_send Send TFPT error packet */
2880 /* */
2881 /* CALLED BY */
2882 /* */
2883 /* _nx_tftp_server_ack_process ACK processing */
2884 /* _nx_tftp_server_data_process Data packet processing */
2885 /* _nx_tftp_server_open_for_write_process Open for write processing */
2886 /* _nx_tftp_server_open_for_read_process Open for read processing */
2887 /* */
2888 /* RELEASE HISTORY */
2889 /* */
2890 /* DATE NAME DESCRIPTION */
2891 /* */
2892 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2893 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2894 /* resulting in version 6.1 */
2895 /* */
2896 /**************************************************************************/
_nx_tftp_server_send_error(NX_TFTP_SERVER * server_ptr,NXD_ADDRESS * ip_address,UINT port,UINT error,CHAR * error_message)2897 VOID _nx_tftp_server_send_error(NX_TFTP_SERVER *server_ptr, NXD_ADDRESS *ip_address, UINT port, UINT error, CHAR *error_message)
2898 {
2899
2900 UINT status;
2901 UCHAR *buffer_ptr;
2902 NX_PACKET *new_packet;
2903
2904
2905 /* Allocate packet for the read packet. Determine whether we are sending IP packets. */
2906 if (ip_address -> nxd_ip_version == NX_IP_VERSION_V4)
2907 {
2908 status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv4_UDP_PACKET, NX_WAIT_FOREVER);
2909 }
2910 else
2911 {
2912 status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv6_UDP_PACKET, NX_WAIT_FOREVER);
2913 }
2914
2915 /* Check for successful packet allocation. */
2916 if (status != NX_SUCCESS)
2917 {
2918
2919 /* Increment the number of server allocation errors. */
2920 server_ptr -> nx_tftp_server_allocation_errors++;
2921
2922 /* Unable to allocate packet for error message, just return! */
2923 return;
2924 }
2925
2926 if (6u > ((ULONG)(new_packet -> nx_packet_data_end) - (ULONG)(new_packet -> nx_packet_append_ptr)))
2927 {
2928 nx_packet_release(new_packet);
2929 return;
2930 }
2931
2932 new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr;
2933
2934 /* Move the TFTP error code and message into the payload before sending it to the client. */
2935 buffer_ptr = new_packet -> nx_packet_prepend_ptr;
2936 *buffer_ptr++ = 0;
2937 *buffer_ptr++ = NX_TFTP_CODE_ERROR;
2938 *buffer_ptr++ = 0;
2939 *buffer_ptr++ = (UCHAR) (error & 0xFF);
2940
2941 /* Loop to copy the error message into the buffer. */
2942 do
2943 {
2944
2945 /* Copy a byte of the error message into the buffer. */
2946 *buffer_ptr = (UCHAR) *error_message;
2947
2948 /* Determine if a NULL is present. */
2949 if (*buffer_ptr == NX_NULL)
2950 {
2951
2952 /* Yes, we are at the end of the string end the loop. */
2953 break;
2954 }
2955
2956 /* Move both pointers to the next character. */
2957 buffer_ptr++;
2958 error_message++;
2959 } while (buffer_ptr < (new_packet -> nx_packet_data_end - 1));
2960
2961 /* Ensure a NULL is in the last position! */
2962 *buffer_ptr++ = NX_NULL;
2963
2964 /* Setup the packet pointers appropriately. */
2965 new_packet -> nx_packet_length = (ULONG)(buffer_ptr - new_packet -> nx_packet_prepend_ptr);
2966 new_packet -> nx_packet_append_ptr = buffer_ptr;
2967
2968 /* Send the data packet out. */
2969 status = nxd_udp_socket_send(&(server_ptr -> nx_tftp_server_socket), new_packet, ip_address, port);
2970
2971 /* Release packet if send fails. */
2972 if (status)
2973 {
2974 nx_packet_release(new_packet);
2975 }
2976 }
2977