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