mirror of
https://github.com/azure-rtos/netx.git
synced 2023-08-10 07:57:54 +08:00
2763 lines
136 KiB
C
2763 lines
136 KiB
C
/**************************************************************************/
|
|
/* */
|
|
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
|
/* */
|
|
/* This software is licensed under the Microsoft Software License */
|
|
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
|
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
|
/* and in the root directory of this software. */
|
|
/* */
|
|
/**************************************************************************/
|
|
|
|
|
|
/**************************************************************************/
|
|
/**************************************************************************/
|
|
/** */
|
|
/** NetX Component */
|
|
/** Trivial File Transfer Protocol (TFTP) Server */
|
|
/** */
|
|
/** */
|
|
/**************************************************************************/
|
|
/**************************************************************************/
|
|
|
|
#define NX_TFTP_SOURCE_CODE
|
|
|
|
|
|
/* Force error checking to be disabled in this module */
|
|
|
|
#ifndef NX_DISABLE_ERROR_CHECKING
|
|
#define NX_DISABLE_ERROR_CHECKING
|
|
#endif
|
|
|
|
/* Include necessary system files. */
|
|
|
|
#include "nx_api.h"
|
|
#include "nx_ip.h"
|
|
#include "nx_tftp_server.h"
|
|
|
|
/* Bring in externs for caller checking code. */
|
|
|
|
NX_CALLER_CHECKING_EXTERNS
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _nxe_tftp_server_create PORTABLE C */
|
|
/* 6.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Yuxin Zhou, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function checks for errors in the TFTP server create call. */
|
|
/* */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* tftp_server_ptr Pointer to TFTP server */
|
|
/* tftp_server_name Name of TFTP server */
|
|
/* ip_ptr Pointer to IP instance */
|
|
/* media_ptr Pointer to media structure */
|
|
/* stack_ptr Server thread's stack pointer */
|
|
/* stack_size Server thread's stack size */
|
|
/* pool_ptr Pointer to packet pool */
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* status Completion status */
|
|
/* NX_PTR_ERROR Invalid pointer input */
|
|
/* NX_TFTP_POOL_ERROR Invalid packet size for TFTP */
|
|
/* server packet pool */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* _nx_tftp_server_create Actual server create call */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* Application Code */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
|
|
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
|
|
/* resulting in version 6.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
UINT _nxe_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)
|
|
{
|
|
|
|
UINT status;
|
|
NX_PACKET *packet_ptr;
|
|
|
|
|
|
/* Check for invalid input pointers. */
|
|
if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) ||
|
|
(tftp_server_ptr == NX_NULL) || (tftp_server_ptr -> nx_tftp_server_id == NX_TFTP_SERVER_ID) ||
|
|
(stack_ptr == NX_NULL) || (pool_ptr == NX_NULL))
|
|
{
|
|
|
|
return(NX_PTR_ERROR);
|
|
}
|
|
|
|
/* Pickup a packet from the supplied packet pool. */
|
|
packet_ptr = pool_ptr -> nx_packet_pool_available_list;
|
|
|
|
/* Determine if the packet payload is large enough (must include 512 bytes plus packet headers). */
|
|
if ((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_data_start) < NX_TFTP_PACKET_SIZE)
|
|
{
|
|
|
|
return(NX_TFTP_POOL_ERROR);
|
|
}
|
|
|
|
/* Call actual server create function. */
|
|
status = _nx_tftp_server_create(tftp_server_ptr, tftp_server_name, ip_ptr, media_ptr, stack_ptr, stack_size, pool_ptr);
|
|
|
|
/* Return completion status. */
|
|
return(status);
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _nx_tftp_server_create PORTABLE C */
|
|
/* 6.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Yuxin Zhou, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function creates a TFTP server on the specified IP. In doing */
|
|
/* so this function creates an UDP socket for subsequent TFTP */
|
|
/* transfers and a thread for the TFTP server. */
|
|
/* */
|
|
/* If NX_TFTP_SERVER_RETRANSMIT_ENABLE is enabled, it also creates */
|
|
/* a timer for retransmitting TFTP server packets up to a maximum */
|
|
/* number of retries before terminating the connection. */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* tftp_server_ptr Pointer to TFTP server */
|
|
/* tftpvserver_name Name of TFTP server */
|
|
/* ip_ptr Pointer to IP instance */
|
|
/* media_ptr Pointer to media structure */
|
|
/* stack_ptr Server thread's stack pointer */
|
|
/* stack_size Server thread's stack size */
|
|
/* pool_ptr Pointer to packet pool */
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* status Actual cmpletion status */
|
|
/* NX_SUCCESS Successful completion */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* nx_udp_socket_bind Bind the TFTP server socket */
|
|
/* nx_udp_socket_create Create TFTP server socket */
|
|
/* nx_udp_socket_delete Delete TFTP server socket */
|
|
/* nx_udp_socket_unbind Unbind TFTP server socket */
|
|
/* tx_thread_create Create TFTP server thread */
|
|
/* tx_timer_create Create retransmit timer */
|
|
/* nx_udp_socket_receive_notify Set a receive callback */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* Application Code */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
|
|
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
|
|
/* resulting in version 6.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
UINT _nx_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)
|
|
{
|
|
|
|
UINT status;
|
|
|
|
|
|
/* Clear the TFTP server structure. */
|
|
memset((void *) tftp_server_ptr, 0, sizeof(NX_TFTP_SERVER));
|
|
|
|
/* Create the server's UDP socket. */
|
|
status = nx_udp_socket_create(ip_ptr, &(tftp_server_ptr -> nx_tftp_server_socket), tftp_server_name,
|
|
NX_TFTP_TYPE_OF_SERVICE, NX_TFTP_FRAGMENT_OPTION, NX_TFTP_TIME_TO_LIVE, NX_TFTP_QUEUE_DEPTH);
|
|
|
|
/* Determine if an error occurred. */
|
|
if (status != NX_SUCCESS)
|
|
{
|
|
|
|
/* Yes, return error code. */
|
|
return(status);
|
|
}
|
|
|
|
/* Register the receive function. */
|
|
nx_udp_socket_receive_notify(&(tftp_server_ptr -> nx_tftp_server_socket), _nx_tftp_server_data_present);
|
|
|
|
/* Make sure the socket points to the TFTP server. */
|
|
tftp_server_ptr -> nx_tftp_server_socket.nx_udp_socket_reserved_ptr = tftp_server_ptr;
|
|
|
|
/* Now, bind the socket to a the well known TFTP UDP port number. */
|
|
status = nx_udp_socket_bind(&(tftp_server_ptr -> nx_tftp_server_socket), NX_TFTP_SERVER_PORT, NX_NO_WAIT);
|
|
|
|
/* Determine if an error occurred. */
|
|
if (status != NX_SUCCESS)
|
|
{
|
|
|
|
/* Delete the UDP socket. */
|
|
nx_udp_socket_delete(&(tftp_server_ptr -> nx_tftp_server_socket));
|
|
|
|
/* Yes, return error code. */
|
|
return(status);
|
|
}
|
|
|
|
/* Now create the TFTP Server thread. */
|
|
status = tx_thread_create(&(tftp_server_ptr -> nx_tftp_server_thread), "TFTP Server Thread", _nx_tftp_server_thread_entry,
|
|
(ULONG) tftp_server_ptr, stack_ptr, stack_size, NX_TFTP_SERVER_PRIORITY, NX_TFTP_SERVER_PRIORITY,
|
|
NX_TFTP_SERVER_TIME_SLICE, TX_DONT_START);
|
|
|
|
/* Determine if an error occurred creating the thread. */
|
|
if (status != NX_SUCCESS)
|
|
{
|
|
|
|
/* Unbind the UDP socket. */
|
|
nx_udp_socket_unbind(&(tftp_server_ptr -> nx_tftp_server_socket));
|
|
|
|
/* Delete the UDP socket. */
|
|
nx_udp_socket_delete(&(tftp_server_ptr -> nx_tftp_server_socket));
|
|
|
|
/* Yes, return error code. */
|
|
return(status);
|
|
}
|
|
|
|
/* Create the ThreadX event flags. These will be used to drive the TFTP server thread. */
|
|
status = tx_event_flags_create(&(tftp_server_ptr -> nx_tftp_server_event_flags), "TFTP Server Thread Events");
|
|
|
|
/* Determine if an error occurred creating the event flags. */
|
|
if (status != TX_SUCCESS)
|
|
{
|
|
|
|
/* Unbind the UDP socket. */
|
|
nx_udp_socket_unbind(&(tftp_server_ptr -> nx_tftp_server_socket));
|
|
|
|
/* Delete the UDP socket. */
|
|
nx_udp_socket_delete(&(tftp_server_ptr -> nx_tftp_server_socket));
|
|
|
|
/* Delete the server thread. */
|
|
tx_thread_delete(&(tftp_server_ptr -> nx_tftp_server_thread));
|
|
|
|
/* Error creating the server event flags. */
|
|
return(status);
|
|
}
|
|
|
|
#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE
|
|
|
|
/* Create the ThreadX retransmit timeout timer. This will be used to retransmit TFTP server
|
|
packets if the Client has not responded or sends a duplicate (old) ACK or data packet. */
|
|
status = tx_timer_create(&(tftp_server_ptr -> nx_tftp_server_timer), "TFTP Server Timer",
|
|
_nx_tftp_server_timer_entry, (ULONG) tftp_server_ptr,
|
|
(NX_TFTP_SERVER_TIMEOUT_PERIOD),
|
|
(NX_TFTP_SERVER_TIMEOUT_PERIOD), TX_NO_ACTIVATE);
|
|
|
|
if (status != NX_SUCCESS)
|
|
{
|
|
|
|
/* Unbind the UDP socket. */
|
|
nx_udp_socket_unbind(&(tftp_server_ptr -> nx_tftp_server_socket));
|
|
|
|
/* Delete the UDP socket. */
|
|
nx_udp_socket_delete(&(tftp_server_ptr -> nx_tftp_server_socket));
|
|
|
|
/* Delete the event flags. */
|
|
tx_event_flags_delete(&(tftp_server_ptr -> nx_tftp_server_event_flags));
|
|
|
|
/* Delete the server thread. */
|
|
tx_thread_delete(&(tftp_server_ptr -> nx_tftp_server_thread));
|
|
|
|
/* Yes, return error code. */
|
|
return(status);
|
|
}
|
|
#endif /* NX_TFTP_SERVER_RETRANSMIT_ENABLE */
|
|
|
|
/* Save the Server name. */
|
|
tftp_server_ptr -> nx_tftp_server_name = tftp_server_name;
|
|
|
|
/* Save the IP pointer address. */
|
|
tftp_server_ptr -> nx_tftp_server_ip_ptr = ip_ptr;
|
|
|
|
/* Save the packet pool pointer. */
|
|
tftp_server_ptr -> nx_tftp_server_packet_pool_ptr = pool_ptr;
|
|
|
|
/* Save the media pointer address. */
|
|
tftp_server_ptr -> nx_tftp_server_media_ptr = media_ptr;
|
|
|
|
/* Clear the error code and error string. */
|
|
tftp_server_ptr -> nx_tftp_server_error_code = 0;
|
|
tftp_server_ptr -> nx_tftp_server_error_string[0] = NX_NULL;
|
|
|
|
/* Set the server ID to indicate the TFTP server thread is ready. */
|
|
tftp_server_ptr -> nx_tftp_server_id = NX_TFTP_SERVER_ID;
|
|
|
|
/* Return successful completion. */
|
|
return(NX_SUCCESS);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _nxe_tftp_server_delete PORTABLE C */
|
|
/* 6.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Yuxin Zhou, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function checks for errors in the TFTP server delete call. */
|
|
/* */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* tftp_server_ptr Pointer to TFTP server */
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* status Completion status */
|
|
/* NX_PTR_ERROR Invalid pointer input */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* _nx_tftp_server_delete Actual server delete call */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* Application Code */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
|
|
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
|
|
/* resulting in version 6.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
UINT _nxe_tftp_server_delete(NX_TFTP_SERVER *tftp_server_ptr)
|
|
{
|
|
|
|
UINT status;
|
|
|
|
|
|
/* Check for invalid input pointers. */
|
|
if ((tftp_server_ptr == NX_NULL) || (tftp_server_ptr -> nx_tftp_server_id != NX_TFTP_SERVER_ID))
|
|
return(NX_PTR_ERROR);
|
|
|
|
/* Check for appropriate caller. */
|
|
NX_THREADS_ONLY_CALLER_CHECKING
|
|
|
|
/* Call actual server delete function. */
|
|
status = _nx_tftp_server_delete(tftp_server_ptr);
|
|
|
|
/* Return completion status. */
|
|
return(status);
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _nx_tftp_server_delete PORTABLE C */
|
|
/* 6.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Yuxin Zhou, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function deletes a previously created TFTP server on the */
|
|
/* specified IP. */
|
|
/* */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* tftp_server_ptr Pointer to TFTP server */
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* NX_SUCCESS Successful completion */
|
|
/* status Actual completion status */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* fx_file_close File close */
|
|
/* nx_udp_socket_delete Delete TFTP server socket */
|
|
/* nx_udp_socket_unbind Unbind TFTP server socket */
|
|
/* tx_thread_delete Delete TFTP server thread */
|
|
/* tx_thread_suspend Suspend TFTP server thread */
|
|
/* tx_thread_terminate Terminate TFTP server */
|
|
/* thread */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* Application Code */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
|
|
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
|
|
/* resulting in version 6.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
UINT _nx_tftp_server_delete(NX_TFTP_SERVER *tftp_server_ptr)
|
|
{
|
|
|
|
UINT i;
|
|
NX_TFTP_CLIENT_REQUEST *client_request_ptr;
|
|
|
|
|
|
/* Clear the server ID to indicate the TFTP server is no longer ready. */
|
|
tftp_server_ptr -> nx_tftp_server_id = 0;
|
|
|
|
/* Unbind the UDP socket. */
|
|
nx_udp_socket_unbind(&(tftp_server_ptr -> nx_tftp_server_socket));
|
|
|
|
/* Delete the UDP socket. */
|
|
nx_udp_socket_delete(&(tftp_server_ptr -> nx_tftp_server_socket));
|
|
|
|
/* Suspend the TFTP server thread. */
|
|
tx_thread_suspend(&(tftp_server_ptr -> nx_tftp_server_thread));
|
|
|
|
/* Terminate server thread. */
|
|
tx_thread_terminate(&(tftp_server_ptr -> nx_tftp_server_thread));
|
|
|
|
/* Delete the server flag group. */
|
|
tx_event_flags_delete(&(tftp_server_ptr -> nx_tftp_server_event_flags));
|
|
|
|
#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE
|
|
tx_timer_delete(&(tftp_server_ptr -> nx_tftp_server_timer));
|
|
#endif
|
|
|
|
|
|
/* Delete server thread. */
|
|
tx_thread_delete(&(tftp_server_ptr -> nx_tftp_server_thread));
|
|
|
|
/* Walk through the server structure to close any remaining open files. */
|
|
i = 0;
|
|
|
|
client_request_ptr = &(tftp_server_ptr -> nx_tftp_server_client_list[0]);
|
|
|
|
while (i < NX_TFTP_MAX_CLIENTS)
|
|
{
|
|
|
|
/* Is this entry in use? */
|
|
|
|
/* First determine which IP address type. */
|
|
if((client_request_ptr -> nx_tftp_client_request_port != 0) &&
|
|
(client_request_ptr -> nx_tftp_client_request_ip_address != 0))
|
|
{
|
|
/* No, need to close the file on this client! */
|
|
fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
|
|
}
|
|
|
|
/* Increment the pointer into the client request list. */
|
|
client_request_ptr++;
|
|
i++;
|
|
}
|
|
|
|
/* Return successful completion. */
|
|
return(NX_SUCCESS);
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _nxe_tftp_server_start PORTABLE C */
|
|
/* 6.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Yuxin Zhou, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function checks for errors in the TFTP server start call. */
|
|
/* */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* tftp_server_ptr Pointer to TFTP server */
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* status Completion status */
|
|
/* NX_PTR_ERROR Invalid pointer input */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* _nx_tftp_server_start Actual server start call */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* Application Code */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
|
|
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
|
|
/* resulting in version 6.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
UINT _nxe_tftp_server_start(NX_TFTP_SERVER *tftp_server_ptr)
|
|
{
|
|
|
|
UINT status;
|
|
|
|
|
|
/* Check for invalid input pointers. */
|
|
if ((tftp_server_ptr == NX_NULL) || (tftp_server_ptr -> nx_tftp_server_id != NX_TFTP_SERVER_ID))
|
|
return(NX_PTR_ERROR);
|
|
|
|
/* Call actual server start function. */
|
|
status = _nx_tftp_server_start(tftp_server_ptr);
|
|
|
|
/* Return completion status. */
|
|
return(status);
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _nx_tftp_server_start PORTABLE C */
|
|
/* 6.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Yuxin Zhou, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function starts a previously created TFTP server on the */
|
|
/* specified IP. */
|
|
/* */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* tftp_server_ptr Pointer to TFTP server */
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* NX_SUCCESS Successful completion */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* tx_thread_resume Resume TFTP server thread */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* Application Code */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
|
|
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
|
|
/* resulting in version 6.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
UINT _nx_tftp_server_start(NX_TFTP_SERVER *tftp_server_ptr)
|
|
{
|
|
|
|
#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE
|
|
/* Activate TFTP server timer. */
|
|
tx_timer_activate(&(tftp_server_ptr -> nx_tftp_server_timer));
|
|
#endif
|
|
|
|
/* Start the TFTP server thread. */
|
|
tx_thread_resume(&(tftp_server_ptr -> nx_tftp_server_thread));
|
|
|
|
/* Return successful completion. */
|
|
return(NX_SUCCESS);
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _nxe_tftp_server_stop PORTABLE C */
|
|
/* 6.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Yuxin Zhou, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function checks for errors in the TFTP server stop call. */
|
|
/* */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* tftp_server_ptr Pointer to TFTP server */
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* status Completion status */
|
|
/* NX_PTR_ERROR Invalid pointer input */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* _nx_tftp_server_stop Actual server start call */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* Application Code */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
|
|
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
|
|
/* resulting in version 6.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
UINT _nxe_tftp_server_stop(NX_TFTP_SERVER *tftp_server_ptr)
|
|
{
|
|
|
|
UINT status;
|
|
|
|
|
|
/* Check for invalid input pointers. */
|
|
if ((tftp_server_ptr == NX_NULL) || (tftp_server_ptr -> nx_tftp_server_id != NX_TFTP_SERVER_ID))
|
|
return(NX_PTR_ERROR);
|
|
|
|
/* Check for appropriate caller. */
|
|
NX_THREADS_ONLY_CALLER_CHECKING
|
|
|
|
/* Call actual server delete function. */
|
|
status = _nx_tftp_server_stop(tftp_server_ptr);
|
|
|
|
/* Return completion status. */
|
|
return(status);
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _nx_tftp_server_stop PORTABLE C */
|
|
/* 6.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Yuxin Zhou, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function stops a previously started TFTP server on the */
|
|
/* specified IP. */
|
|
/* */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* tftp_server_ptr Pointer to TFTP server */
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* NX_SUCCESS Successful completion */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* tx_thread_suspend Suspend TFTP server thread */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* Application Code */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
|
|
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
|
|
/* resulting in version 6.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
UINT _nx_tftp_server_stop(NX_TFTP_SERVER *tftp_server_ptr)
|
|
{
|
|
|
|
#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE
|
|
/* Deactivate TFTP server timer. */
|
|
tx_timer_deactivate(&(tftp_server_ptr -> nx_tftp_server_timer));
|
|
#endif
|
|
|
|
/* Suspend the TFTP server thread. */
|
|
tx_thread_suspend(&(tftp_server_ptr -> nx_tftp_server_thread));
|
|
|
|
/* Return successful completion. */
|
|
return(NX_SUCCESS);
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _nx_tftp_server_data_present PORTABLE C */
|
|
/* 6.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Yuxin Zhou, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function is notified by NetX of receive events generated by */
|
|
/* TFTP Clients connecting or sending data. */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* socket_ptr Socket receiving data */
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* None */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* tx_event_flags_set Set events for server thread */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* NetX NetX TCP socket callback */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
|
|
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
|
|
/* resulting in version 6.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
VOID _nx_tftp_server_data_present(NX_UDP_SOCKET *socket_ptr)
|
|
{
|
|
|
|
NX_TFTP_SERVER *server_ptr;
|
|
|
|
/* Pickup server pointer. This is setup in the reserved field of the TCP socket. */
|
|
server_ptr = (NX_TFTP_SERVER *)(socket_ptr -> nx_udp_socket_reserved_ptr);
|
|
|
|
/* Set the data event flag. */
|
|
tx_event_flags_set(&(server_ptr -> nx_tftp_server_event_flags), NX_TFTP_SERVER_RECEIVE_EVENT, TX_OR);
|
|
}
|
|
|
|
|
|
#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _nx_tftp_server_timer_entry PORTABLE C */
|
|
/* 6.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Yuxin Zhou, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function captures timer events used to determine if the Client */
|
|
/* retransmit timer has expired. */
|
|
/* */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* ULONG Pointer to TFTP server */
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* None */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* tx_event_flags_set Set events for server thread */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* NetX NetX connect callback */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
|
|
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
|
|
/* resulting in version 6.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
VOID _nx_tftp_server_timer_entry(ULONG tftp_server_address)
|
|
{
|
|
|
|
NX_TFTP_SERVER *server_ptr;
|
|
|
|
/* Pickup server pointer. */
|
|
server_ptr = (NX_TFTP_SERVER *) tftp_server_address;
|
|
|
|
/* Set the data event flag. */
|
|
tx_event_flags_set(&(server_ptr -> nx_tftp_server_event_flags), NX_TFTP_SERVER_TIMER_EVENT, TX_OR);
|
|
|
|
return;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _nx_tftp_server_timer_process PORTABLE C */
|
|
/* 6.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Yuxin Zhou, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function checks all the active TFTP client connections */
|
|
/* for their retransmission timeout. If expired, the Server retransmits*/
|
|
/* the data or ACK up to a maximum number of retries */
|
|
/* (NX_TFTP_SERVER_MAX_RETRIES) and then terminates the connection and */
|
|
/* closes any open files. The client request is cleared and available */
|
|
/* for the next client request */
|
|
/* */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* server_ptr Pointer to TFTP server */
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* None */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* fx_file_close Close session file. */
|
|
/* fx_file_delete Delete the file */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* _nx_tftp_server_thread_entry TFTP server task function */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
|
|
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
|
|
/* resulting in version 6.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
VOID _nx_tftp_server_timer_process(NX_TFTP_SERVER *server_ptr)
|
|
{
|
|
|
|
UINT i;
|
|
NX_TFTP_CLIENT_REQUEST *client_request_ptr;
|
|
|
|
|
|
/* Now look through all the sockets. */
|
|
for (i = 0; i < NX_TFTP_MAX_CLIENTS; i++)
|
|
{
|
|
|
|
/* Set a pointer to client request structure. */
|
|
client_request_ptr = &(server_ptr -> nx_tftp_server_client_list[i]);
|
|
|
|
/* Check if this request has a retransmit timeout pending. */
|
|
if (client_request_ptr -> nx_tftp_client_retransmit_timeout )
|
|
{
|
|
|
|
/* Update reatransmit timeout. */
|
|
if (client_request_ptr -> nx_tftp_client_retransmit_timeout >= NX_TFTP_SERVER_TIMEOUT_PERIOD)
|
|
{
|
|
|
|
client_request_ptr -> nx_tftp_client_retransmit_timeout -= NX_TFTP_SERVER_TIMEOUT_PERIOD;
|
|
}
|
|
else
|
|
{
|
|
|
|
client_request_ptr -> nx_tftp_client_retransmit_timeout = 0;
|
|
}
|
|
|
|
/* Has the retransmit timeout expired? */
|
|
if (client_request_ptr -> nx_tftp_client_retransmit_timeout == 0)
|
|
{
|
|
|
|
/* Yes, retransmit unless we have hit the max retry limit. */
|
|
if (client_request_ptr -> nx_tftp_client_retransmit_retries < NX_TFTP_SERVER_MAX_RETRIES)
|
|
{
|
|
|
|
|
|
/* Update the Client request retransmit timeout and number of retries. */
|
|
client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT;
|
|
client_request_ptr -> nx_tftp_client_retransmit_retries++;
|
|
|
|
/* Determine which type of request this is. */
|
|
if (client_request_ptr -> nx_tftp_client_request_open_type == NX_TFTP_STATE_WRITE_OPEN)
|
|
{
|
|
|
|
/* Retransmit the ACK. */
|
|
_nx_tftp_server_send_ack(server_ptr, client_request_ptr, NX_TRUE);
|
|
}
|
|
else
|
|
{
|
|
|
|
/* Retransmit the file data. */
|
|
_nx_tftp_server_send_data(server_ptr, client_request_ptr, NX_TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
/* The session has timed out. Send error and close. */
|
|
_nx_tftp_server_send_error(server_ptr, &client_request_ptr -> nx_tftp_client_request_ip_address,
|
|
client_request_ptr -> nx_tftp_client_request_port,
|
|
NX_TFTP_SESSION_TIMED_OUT, "NetX TFTP Server: Session timed out");
|
|
|
|
/* Error, close the file and delete the client request. */
|
|
fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
|
|
|
|
memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif /* NX_TFTP_SERVER_RETRANSMIT_ENABLE */
|
|
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _nx_tftp_server_thread_entry PORTABLE C */
|
|
/* 6.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Yuxin Zhou, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function is the entry of the TFTP server. All basic */
|
|
/* processing is initiated by this function. */
|
|
/* */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* tftp_server Pointer to TFTP server */
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* None */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* tx_event_flags_get Get the TFTP events */
|
|
/* _nx_tftp_server_process_received_data Process received packet */
|
|
/* _nx_tftp_server_timer_process Process TFTP timer */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* ThreadX */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
|
|
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
|
|
/* resulting in version 6.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
VOID _nx_tftp_server_thread_entry(ULONG tftp_server)
|
|
{
|
|
|
|
NX_TFTP_SERVER *server_ptr;
|
|
UINT status;
|
|
ULONG events;
|
|
|
|
|
|
/* Setup the server pointer. */
|
|
server_ptr = (NX_TFTP_SERVER *) tftp_server;
|
|
|
|
/* Loop to process TFTP Server requests. */
|
|
while(1)
|
|
{
|
|
|
|
/* Wait for TFTP events. */
|
|
status = tx_event_flags_get(&(server_ptr -> nx_tftp_server_event_flags), NX_SERVER_TFTP_ANY_EVENT,
|
|
TX_OR_CLEAR, &events, TX_WAIT_FOREVER);
|
|
|
|
/* Check the return status. */
|
|
if (status)
|
|
{
|
|
|
|
/* If an error occurs, simply continue the loop. */
|
|
continue;
|
|
}
|
|
|
|
/* Otherwise, an event is present. Process according to the event. */
|
|
|
|
/* Check for a client receive event. */
|
|
if (events & NX_TFTP_SERVER_RECEIVE_EVENT)
|
|
{
|
|
|
|
/* Call the data received handler. */
|
|
_nx_tftp_server_process_received_data(server_ptr);
|
|
}
|
|
|
|
#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE
|
|
/* Check for a timer event. */
|
|
if (events & NX_TFTP_SERVER_TIMER_EVENT)
|
|
{
|
|
/* Call the timer timeout handler. */
|
|
_nx_tftp_server_timer_process(server_ptr);
|
|
}
|
|
#endif /* NX_TFTP_SERVER_RETRANSMIT_ENABLE*/
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _nx_tftp_server_process_received_data PORTABLE C */
|
|
/* 6.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Yuxin Zhou, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function is called when the TFTP server is notified of a */
|
|
/* receive event. It parses the TFTP Client message and calls the */
|
|
/* appropriate handler for read and write requests, client errors, or */
|
|
/* ACKing data sent by the server. */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* server_ptr Pointer to TFTP server */
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* status Completion status */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* _nx_tftp_server_ack_process Process ACK from previous read*/
|
|
/* _nx_tftp_server_data_process Write data packet to file */
|
|
/* _nx_tftp_server_error_process Process error packet */
|
|
/* _nx_tftp_server_open_for_read_process Open file for reading */
|
|
/* _nx_tftp_server_open_for_write_process Open for writing */
|
|
/* nx_packet_release Release packet */
|
|
/* nx_udp_socket_receive Receive next TFTP packet */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* nx_tftp_server_thread_entry TFTP thread task function */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
|
|
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
|
|
/* resulting in version 6.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
VOID _nx_tftp_server_process_received_data(NX_TFTP_SERVER *server_ptr)
|
|
{
|
|
|
|
UINT status;
|
|
NX_PACKET *packet_ptr;
|
|
UCHAR *buffer_ptr;
|
|
UCHAR request_code;
|
|
|
|
|
|
/* Wait for a request on the TFTP UDP well known port 69. */
|
|
status = nx_udp_socket_receive(&(server_ptr -> nx_tftp_server_socket), &packet_ptr, NX_NO_WAIT);
|
|
|
|
/* Check the return status. */
|
|
if (status)
|
|
{
|
|
|
|
/* If an error occurs, simply return to caller. */
|
|
return;
|
|
}
|
|
|
|
/* Check for valid packet length (The minimum TFTP header size is ACK packet, four bytes). */
|
|
if (packet_ptr -> nx_packet_length < 4)
|
|
{
|
|
|
|
/* Release the packet. */
|
|
nx_packet_release(packet_ptr);
|
|
|
|
/* Return. */
|
|
return;
|
|
}
|
|
|
|
/* Otherwise, we have received a packet successfully. */
|
|
|
|
/* Setup a pointer to packet buffer area. */
|
|
buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
|
|
|
|
/* Pickup up the request code. First one must be zero. */
|
|
request_code = *buffer_ptr++;
|
|
|
|
/* If not zero, abort. */
|
|
if (request_code)
|
|
{
|
|
|
|
nx_packet_release(packet_ptr);
|
|
|
|
return;
|
|
}
|
|
|
|
/* Now get the actual request code. */
|
|
request_code = *buffer_ptr++;
|
|
|
|
/* Process relative to the TFTP request code. */
|
|
switch (request_code)
|
|
{
|
|
|
|
case NX_TFTP_CODE_READ:
|
|
|
|
/* Process an open for read request. */
|
|
_nx_tftp_server_open_for_read_process(server_ptr, packet_ptr);
|
|
|
|
/* Increment the number of open for read requests. */
|
|
server_ptr -> nx_tftp_server_open_for_read_requests++;
|
|
break;
|
|
|
|
case NX_TFTP_CODE_WRITE:
|
|
|
|
/* Process an open for write request. */
|
|
_nx_tftp_server_open_for_write_process(server_ptr, packet_ptr);
|
|
|
|
/* Increment the number of open for write requests. */
|
|
server_ptr -> nx_tftp_server_open_for_write_requests++;
|
|
break;
|
|
|
|
case NX_TFTP_CODE_DATA:
|
|
|
|
/* Process a data request. */
|
|
_nx_tftp_server_data_process(server_ptr, packet_ptr);
|
|
|
|
/* Increment the number of data block write requests. */
|
|
server_ptr -> nx_tftp_server_data_blocks_received++;
|
|
break;
|
|
|
|
case NX_TFTP_CODE_ACK:
|
|
|
|
/* Process an ack response. */
|
|
_nx_tftp_server_ack_process(server_ptr, packet_ptr);
|
|
|
|
/* Increment the number of acks for previous data blocks sent. */
|
|
server_ptr -> nx_tftp_server_acks_received++;
|
|
break;
|
|
|
|
case NX_TFTP_CODE_ERROR:
|
|
|
|
/* Process an error request. */
|
|
_nx_tftp_server_error_process(server_ptr, packet_ptr);
|
|
|
|
/* Increment the number of errors received. */
|
|
server_ptr -> nx_tftp_server_errors_received++;
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Increment the number of unknown codes received. */
|
|
server_ptr -> nx_tftp_server_unknown_commands++;
|
|
|
|
/* Just release the packet. */
|
|
nx_packet_release(packet_ptr);
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _nx_tftp_server_open_for_read_process PORTABLE C */
|
|
/* 6.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Yuxin Zhou, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function opens the specified file for reading, and returns */
|
|
/* the first block of the file. */
|
|
/* */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* server_ptr Pointer to TFTP server */
|
|
/* packet_ptr Pointer to TFTP request packet*/
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* None */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* fx_directory_information_get Get information about file */
|
|
/* fx_file_close Close file on EOF or error */
|
|
/* fx_file_open Open file for reading */
|
|
/* fx_file_read Read block from file */
|
|
/* _nx_tftp_server_find_client_request Find client entry */
|
|
/* _nx_tftp_server_send_error Send error message */
|
|
/* nx_packet_allocate Allocate a new packet */
|
|
/* nx_packet_release Release packet */
|
|
/* nx_udp_socket_send Send TFTP data packet */
|
|
/* nx_udp_source_extract Extract IP and port */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* _nx_tftp_server_thread_entry TFTP Server thread */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
|
|
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
|
|
/* resulting in version 6.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
void _nx_tftp_server_open_for_read_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr)
|
|
{
|
|
ULONG ip_address;
|
|
ULONG file_size;
|
|
ULONG actual_size;
|
|
UINT port;
|
|
UCHAR *buffer_ptr;
|
|
NX_TFTP_CLIENT_REQUEST *client_request_ptr;
|
|
NX_PACKET *new_packet = NX_NULL;
|
|
UINT status;
|
|
|
|
|
|
/* Extract the source IP and port numbers. */
|
|
nx_udp_source_extract(packet_ptr, &ip_address, &port);
|
|
|
|
/* First, try to find a matching exiting entry in the client request structure. */
|
|
client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, port, ip_address);
|
|
|
|
/* See if we need to find a new entry. */
|
|
if (client_request_ptr == NX_NULL)
|
|
{
|
|
|
|
/* Yes, find a free entry in the client request structure. */
|
|
client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, 0, NX_NULL);
|
|
}
|
|
else
|
|
{
|
|
|
|
/* This is a dupe request. Ignore it. */
|
|
nx_packet_release(packet_ptr);
|
|
return;
|
|
}
|
|
|
|
/* Determine if there was a free entry. */
|
|
if (client_request_ptr == NX_NULL)
|
|
{
|
|
|
|
/* Increment the maximum clients errors. */
|
|
server_ptr -> nx_tftp_server_clients_exceeded_errors++;
|
|
|
|
/* Send an error to the client. */
|
|
_nx_tftp_server_send_error(server_ptr, ip_address, port, NX_TFTP_ERROR_NOT_DEFINED, "NetX TFTP Server: Too Many Clients");
|
|
|
|
/* No more clients can be serviced, release the packet. */
|
|
nx_packet_release(packet_ptr);
|
|
return;
|
|
}
|
|
|
|
/* Initialize the client request structure. */
|
|
client_request_ptr -> nx_tftp_client_request_ip_address = ip_address;
|
|
|
|
|
|
client_request_ptr -> nx_tftp_client_request_port = port;
|
|
client_request_ptr -> nx_tftp_client_request_block_number = 1;
|
|
client_request_ptr -> nx_tftp_client_request_open_type = NX_TFTP_STATE_OPEN;
|
|
client_request_ptr -> nx_tftp_client_request_exact_fit = NX_FALSE;
|
|
|
|
#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE
|
|
|
|
/* Reset the retransmission timeout and retries for the client request. */
|
|
client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT;
|
|
client_request_ptr -> nx_tftp_client_retransmit_retries = 0;
|
|
#else
|
|
|
|
/* Clear the count of ACK retransmits from the other side. */
|
|
client_request_ptr -> nx_tftp_client_request_retransmits = 0;
|
|
|
|
#endif
|
|
|
|
/* Setup a pointer to the file name. */
|
|
buffer_ptr = (UCHAR *) (packet_ptr -> nx_packet_prepend_ptr + 2);
|
|
|
|
if (packet_ptr -> nx_packet_length < 4)
|
|
{
|
|
nx_packet_release(packet_ptr);
|
|
return;
|
|
}
|
|
|
|
/* Check if the packet buffer ends with NULL. */
|
|
if (*(UCHAR *)(packet_ptr -> nx_packet_append_ptr - 1))
|
|
{
|
|
nx_packet_release(packet_ptr);
|
|
return;
|
|
}
|
|
|
|
/* Pickup the file size. */
|
|
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);
|
|
|
|
/* Check the return status. */
|
|
if (status != FX_SUCCESS)
|
|
{
|
|
|
|
/* Send an error to the client. */
|
|
_nx_tftp_server_send_error(server_ptr, ip_address, port, NX_TFTP_ERROR_FILE_NOT_FOUND, "NetX TFTP Server: File Not Found");
|
|
|
|
/* Unable to find the file size, release the packet. */
|
|
nx_packet_release(packet_ptr);
|
|
return;
|
|
}
|
|
|
|
/* Attempt to open the file. */
|
|
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);
|
|
|
|
/* Check the return status. */
|
|
if (status != FX_SUCCESS)
|
|
{
|
|
|
|
/* Send an error to the client. */
|
|
_nx_tftp_server_send_error(server_ptr, ip_address, port, NX_TFTP_ERROR_FILE_NOT_FOUND, "NetX TFTP Server: File Open Failed");
|
|
|
|
/* Unable to open the file, release the packet. */
|
|
nx_packet_release(packet_ptr);
|
|
return;
|
|
}
|
|
|
|
/* The file has been opened successfully, now try to read up to 512 bytes. */
|
|
|
|
/* Allocate packet for the read packet. Determine whether we are sending IP packets. */
|
|
status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_UDP_PACKET, NX_WAIT_FOREVER);
|
|
/* Check for successful packet allocation. */
|
|
if (status != NX_SUCCESS)
|
|
{
|
|
|
|
/* Increment the number of server allocation errors. */
|
|
server_ptr -> nx_tftp_server_allocation_errors++;
|
|
|
|
/* Unable to allocate net packet, release the original. */
|
|
nx_packet_release(packet_ptr);
|
|
return;
|
|
}
|
|
|
|
if (4u + NX_TFTP_FILE_TRANSFER_MAX > ((ULONG)(new_packet -> nx_packet_data_end) - (ULONG)(new_packet -> nx_packet_append_ptr)))
|
|
{
|
|
/* Release the original packet. */
|
|
nx_packet_release(packet_ptr);
|
|
|
|
nx_packet_release(new_packet);
|
|
return;
|
|
}
|
|
|
|
client_request_ptr -> nx_tftp_client_file_size = file_size;
|
|
|
|
/* Read data when length of file is larger then 0. */
|
|
if(file_size)
|
|
{
|
|
|
|
/* Attempt to read the requested file. */
|
|
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);
|
|
|
|
/* Check for successful file read. */
|
|
if ((status != NX_SUCCESS) ||
|
|
((file_size > NX_TFTP_FILE_TRANSFER_MAX) && (actual_size != NX_TFTP_FILE_TRANSFER_MAX)) ||
|
|
((file_size < NX_TFTP_FILE_TRANSFER_MAX) && (actual_size != file_size)))
|
|
{
|
|
|
|
/* Send an error to the client. */
|
|
_nx_tftp_server_send_error(server_ptr, ip_address, port, NX_TFTP_ERROR_NOT_DEFINED, "NetX TFTP Server: File Read Error");
|
|
|
|
/* Unable to read the file, close it and release the packet. */
|
|
fx_file_close(&(client_request_ptr ->nx_tftp_client_request_file));
|
|
|
|
nx_packet_release(packet_ptr);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
actual_size = 0;
|
|
}
|
|
|
|
/* Increment the number of total bytes sent. */
|
|
server_ptr -> nx_tftp_server_total_bytes_sent += actual_size;
|
|
|
|
/* Setup the client request structure. */
|
|
client_request_ptr -> nx_tftp_client_request_remaining_bytes = file_size - actual_size;
|
|
|
|
/* Determine if the file size is evenly divisible by our TFTP transfer size. */
|
|
if (file_size % NX_TFTP_FILE_TRANSFER_MAX)
|
|
{
|
|
|
|
/* Not an exact fit, ensure the exact fit flag is clear. */
|
|
client_request_ptr -> nx_tftp_client_request_exact_fit = NX_FALSE;
|
|
}
|
|
else if (file_size > 0)
|
|
{
|
|
|
|
/* Yes, the file size happens to be evenly divisible by the TFTP transfer size. In this
|
|
case, we need to send a zero-length data packet at the end of file to let the other side
|
|
know we are at the end. */
|
|
client_request_ptr -> nx_tftp_client_request_exact_fit = NX_TRUE;
|
|
}
|
|
|
|
/* Move the TFTP data code and block number into the payload before sending it to the client. */
|
|
buffer_ptr = new_packet -> nx_packet_prepend_ptr;
|
|
*buffer_ptr++ = 0;
|
|
*buffer_ptr++ = NX_TFTP_CODE_DATA;
|
|
*buffer_ptr++ = 0;
|
|
*buffer_ptr++ = 1; /* First block number of file. */
|
|
|
|
/* Setup the packet pointers appropriately. */
|
|
new_packet -> nx_packet_length = actual_size + 4;
|
|
new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr + new_packet -> nx_packet_length;
|
|
|
|
/* Send the data packet out. */
|
|
status = nx_udp_socket_send(&(server_ptr -> nx_tftp_server_socket), new_packet, ip_address, port);
|
|
|
|
/* Release packet if send fails. */
|
|
if (status)
|
|
{
|
|
nx_packet_release(new_packet);
|
|
}
|
|
|
|
/* Release the original packet. */
|
|
nx_packet_release(packet_ptr);
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _nx_tftp_server_open_for_write_process PORTABLE C */
|
|
/* 6.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Yuxin Zhou, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function opens the specified file for writing, and returns */
|
|
/* an ACK for block 0 to let the client know everything is good. */
|
|
/* */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* server_ptr Pointer to TFTP server */
|
|
/* packet_ptr Pointer to TFTP request packet*/
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* None */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* fx_file_create Create file, if necessary */
|
|
/* fx_file_close Close file on EOF or error */
|
|
/* fx_file_open Open file for reading */
|
|
/* fx_file_write Write block to file */
|
|
/* _nx_tftp_server_find_client_request Find client entry */
|
|
/* _nx_tftp_server_send_error Send error message */
|
|
/* nx_packet_allocate Allocate a new packet */
|
|
/* nx_packet_release Release packet */
|
|
/* nx_udp_socket_send Send TFTP data packet */
|
|
/* nx_udp_source_extract Extract IP and port */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* _nx_tftp_server_thread_entry TFTP Server thread task */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
|
|
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
|
|
/* resulting in version 6.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
VOID _nx_tftp_server_open_for_write_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr)
|
|
{
|
|
ULONG ip_address;
|
|
UINT port;
|
|
UCHAR *buffer_ptr;
|
|
NX_TFTP_CLIENT_REQUEST *client_request_ptr;
|
|
NX_PACKET *new_packet;
|
|
UINT status;
|
|
|
|
|
|
/* Extract the source IP and port numbers. */
|
|
nx_udp_source_extract(packet_ptr, &ip_address, &port);
|
|
|
|
/* First, try to find a matching exiting entry in the client request structure. */
|
|
client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, port, ip_address);
|
|
|
|
/* See if we need to find a new entry. */
|
|
if (client_request_ptr == NX_NULL)
|
|
{
|
|
|
|
/* Find a free entry in the client request structure. */
|
|
client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, 0, NX_NULL);
|
|
}
|
|
else
|
|
{
|
|
|
|
/* This is a dupe request. Ignore it. */
|
|
nx_packet_release(packet_ptr);
|
|
return;
|
|
}
|
|
|
|
/* Determine if there was a free entry. */
|
|
if (client_request_ptr == NX_NULL)
|
|
{
|
|
|
|
/* Increment the maximum clients errors. */
|
|
server_ptr -> nx_tftp_server_clients_exceeded_errors++;
|
|
|
|
/* Send an error to the client. */
|
|
_nx_tftp_server_send_error(server_ptr, ip_address, port, NX_TFTP_ERROR_NOT_DEFINED, "NetX TFTP Server: Too Many Clients");
|
|
|
|
/* No more clients can be serviced, release the packet. */
|
|
nx_packet_release(packet_ptr);
|
|
return;
|
|
}
|
|
|
|
/* Setup a pointer to the file name. */
|
|
buffer_ptr = (UCHAR *) (packet_ptr -> nx_packet_prepend_ptr + 2);
|
|
|
|
if (packet_ptr -> nx_packet_length < 4)
|
|
{
|
|
nx_packet_release(packet_ptr);
|
|
return;
|
|
}
|
|
|
|
/* Check if the packet buffer ends with NULL. */
|
|
if (*(UCHAR *)(packet_ptr -> nx_packet_append_ptr - 1))
|
|
{
|
|
nx_packet_release(packet_ptr);
|
|
return;
|
|
}
|
|
|
|
/* Perform a file create. This will fail if the file is already present, which we don't care about at this point. */
|
|
fx_file_delete(server_ptr -> nx_tftp_server_media_ptr, (CHAR *) buffer_ptr);
|
|
fx_file_create(server_ptr -> nx_tftp_server_media_ptr, (CHAR *) buffer_ptr);
|
|
|
|
/* Attempt to open the file. */
|
|
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);
|
|
|
|
/* Check for file is open errors. */
|
|
if (status != NX_SUCCESS)
|
|
{
|
|
|
|
/* This is an actual file open error. Send an error to the client. */
|
|
if (status == FX_ACCESS_ERROR)
|
|
_nx_tftp_server_send_error(server_ptr, ip_address, port, NX_TFTP_ERROR_ACCESS_VIOLATION, "NetX TFTP Server: File Access Error");
|
|
else
|
|
_nx_tftp_server_send_error(server_ptr, ip_address, port, NX_TFTP_ERROR_FILE_NOT_FOUND, "NetX TFTP Server: File Open Failed");
|
|
|
|
/* Unable to open the file, release the packet. */
|
|
nx_packet_release(packet_ptr);
|
|
return;
|
|
}
|
|
|
|
/* Now, attempt to build an ACK response to let the client know it can start writing. */
|
|
|
|
/* Allocate packet for the ACK packet. Determine whether we are sending IP packets. */
|
|
status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_UDP_PACKET, NX_WAIT_FOREVER);
|
|
|
|
/* Check for successful packet allocation. */
|
|
if (status != NX_SUCCESS)
|
|
{
|
|
|
|
/* Increment the number of server allocation errors. */
|
|
server_ptr -> nx_tftp_server_allocation_errors++;
|
|
|
|
/* Close the file. */
|
|
fx_file_close(&(client_request_ptr ->nx_tftp_client_request_file));
|
|
|
|
/* Unable to allocate net packet, release the original. */
|
|
nx_packet_release(packet_ptr);
|
|
return;
|
|
}
|
|
|
|
if (4u > ((ULONG)(new_packet -> nx_packet_data_end) - (ULONG)(new_packet -> nx_packet_append_ptr)))
|
|
{
|
|
nx_packet_release(new_packet);
|
|
|
|
/* Release the original packet. */
|
|
nx_packet_release(packet_ptr);
|
|
|
|
return;
|
|
}
|
|
|
|
new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr;
|
|
|
|
/* Setup the client request structure. */
|
|
client_request_ptr -> nx_tftp_client_request_ip_address = ip_address;
|
|
|
|
|
|
client_request_ptr -> nx_tftp_client_request_port = port;
|
|
client_request_ptr -> nx_tftp_client_request_block_number = 1;
|
|
client_request_ptr -> nx_tftp_client_request_open_type = NX_TFTP_STATE_WRITE_OPEN;
|
|
client_request_ptr -> nx_tftp_client_request_remaining_bytes = 0;
|
|
|
|
#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE
|
|
/* Reset retransmission timeouts and retries on current client request. */
|
|
client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT;
|
|
client_request_ptr -> nx_tftp_client_retransmit_retries = 0;
|
|
|
|
#else
|
|
|
|
/* Clear the count of data retransmits from the other side. */
|
|
client_request_ptr -> nx_tftp_client_request_retransmits = 0;
|
|
#endif
|
|
|
|
/* Create the ACK packet. */
|
|
buffer_ptr = new_packet -> nx_packet_prepend_ptr;
|
|
*buffer_ptr++ = 0;
|
|
*buffer_ptr++ = NX_TFTP_CODE_ACK;
|
|
*buffer_ptr++ = 0;
|
|
*buffer_ptr++ = 0; /* 0, just to signal server is ready. */
|
|
|
|
/* Setup the packet pointers appropriately. */
|
|
new_packet -> nx_packet_length = 4;
|
|
new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr + 4;
|
|
|
|
/* Send the data packet out. */
|
|
status = nx_udp_socket_send(&(server_ptr -> nx_tftp_server_socket), new_packet, ip_address, port);
|
|
|
|
/* Release packet if send fails. */
|
|
if (status)
|
|
{
|
|
nx_packet_release(new_packet);
|
|
}
|
|
|
|
/* Release the original packet. */
|
|
nx_packet_release(packet_ptr);
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _nx_tftp_server_data_process PORTABLE C */
|
|
/* 6.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Yuxin Zhou, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function takes the supplied data packet and writes it to the */
|
|
/* previously opened file. */
|
|
/* */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* server_ptr Pointer to TFTP server */
|
|
/* packet_ptr Pointer to TFTP request packet*/
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* None */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* fx_file_close Close file on EOF or error */
|
|
/* fx_file_write Write block to file */
|
|
/* _nx_tftp_server_find_client_request Find client entry */
|
|
/* _nx_tftp_server_send_error Send error message */
|
|
/* nx_packet_allocate Allocate a new packet */
|
|
/* nx_packet_copy Copy packet */
|
|
/* nx_packet_release Release packet */
|
|
/* nx_udp_socket_send Send TFTP ACK packet */
|
|
/* nx_udp_source_extract Extract IP and port */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* _nx_tftp_server_thread_entry TFTP Server thread loop */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
|
|
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
|
|
/* resulting in version 6.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
VOID _nx_tftp_server_data_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr)
|
|
{
|
|
|
|
ULONG ip_address;
|
|
UINT port;
|
|
USHORT block_number;
|
|
UCHAR *buffer_ptr;
|
|
NX_TFTP_CLIENT_REQUEST *client_request_ptr;
|
|
UINT status;
|
|
|
|
/* Extract the source IP and port numbers. */
|
|
nx_udp_source_extract(packet_ptr, &ip_address, &port);
|
|
|
|
/* Find the matching entry in the client request structure. */
|
|
client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, port, ip_address);
|
|
|
|
|
|
/* Determine if there was a matching entry. */
|
|
if (client_request_ptr == NX_NULL)
|
|
{
|
|
|
|
/* Increment the unknown clients errors. */
|
|
server_ptr -> nx_tftp_server_unknown_clients_errors++;
|
|
|
|
/* Send an error to the client. */
|
|
_nx_tftp_server_send_error(server_ptr, ip_address, port, NX_TFTP_ERROR_NO_SUCH_USER, "NetX TFTP Server: Unknown connection");
|
|
|
|
/* No more clients can be serviced, release the packet. */
|
|
nx_packet_release(packet_ptr);
|
|
|
|
return;
|
|
}
|
|
|
|
/* Setup a pointer to the block number. */
|
|
buffer_ptr = (UCHAR *) (packet_ptr -> nx_packet_prepend_ptr + 2);
|
|
|
|
if (packet_ptr -> nx_packet_length < 4)
|
|
{
|
|
nx_packet_release(packet_ptr);
|
|
return;
|
|
}
|
|
|
|
/* Pickup the block number. */
|
|
block_number = (USHORT)(*buffer_ptr++);
|
|
block_number = (USHORT)((block_number << 8) | (*buffer_ptr));
|
|
|
|
/* Determine if this block number matches the current client block number. */
|
|
if (client_request_ptr -> nx_tftp_client_request_block_number != block_number)
|
|
{
|
|
|
|
/* No, it does not. */
|
|
|
|
/* Check if it matches our previous ACK e.g. it could be a retransmit from the other side. */
|
|
if (client_request_ptr -> nx_tftp_client_request_block_number == (USHORT)(block_number + 1))
|
|
{
|
|
|
|
#ifndef NX_TFTP_SERVER_RETRANSMIT_ENABLE
|
|
|
|
/* It does. Update how many we have received. */
|
|
client_request_ptr -> nx_tftp_client_request_retransmits++;
|
|
|
|
/* Decide if we should close the client request. */
|
|
if (client_request_ptr -> nx_tftp_client_request_retransmits <= NX_TFTP_MAX_CLIENT_RETRANSMITS)
|
|
{
|
|
|
|
/* Not yet. Just drop the packet for now. */
|
|
nx_packet_release(packet_ptr);
|
|
|
|
return;
|
|
}
|
|
/* Else handle as an error. */
|
|
#else
|
|
nx_packet_release(packet_ptr);
|
|
|
|
/* (Let the retransmit timeout handler retransmit our ACK to the client.) */
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
/* Send an error to the client. */
|
|
_nx_tftp_server_send_error(server_ptr, ip_address, port, NX_TFTP_ERROR_ILLEGAL_OPERATION, "NetX TFTP Server: Bad block number");
|
|
|
|
/* Error, close the file, release the packet and delete the client request. */
|
|
fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
|
|
|
|
/* Release the packet. */
|
|
nx_packet_release(packet_ptr);
|
|
|
|
memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST));
|
|
|
|
return;
|
|
}
|
|
|
|
/* At this point we have a valid packet. */
|
|
|
|
#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE
|
|
|
|
/* Reset the retransmit retry counter and retransmit timeout. */
|
|
client_request_ptr -> nx_tftp_client_retransmit_retries = 0;
|
|
client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT;
|
|
#else
|
|
|
|
/* Clear the count of retransmits from the other side. */
|
|
client_request_ptr -> nx_tftp_client_request_retransmits = 0;
|
|
#endif
|
|
|
|
/* Determine if there is anything to write. */
|
|
if (packet_ptr -> nx_packet_length > 4)
|
|
{
|
|
|
|
/* At this point, we need to write the next block of the file. */
|
|
|
|
/* Determine if the current packet is chained. */
|
|
if (packet_ptr -> nx_packet_next)
|
|
{
|
|
|
|
NX_PACKET *temp_ptr;
|
|
|
|
|
|
/* Yes, the packet is chained. We have to copy the receive packet into a packet with the
|
|
a payload of at least 560 bytes so the write request can be supplied with just the
|
|
payload pointer. */
|
|
status = nx_packet_copy(packet_ptr, &temp_ptr, server_ptr -> nx_tftp_server_packet_pool_ptr, NX_WAIT_FOREVER);
|
|
|
|
/* Check for successful packet copy. */
|
|
if (status != NX_SUCCESS)
|
|
{
|
|
|
|
/* Increment the number of server allocation errors. */
|
|
server_ptr -> nx_tftp_server_allocation_errors++;
|
|
|
|
/* Unable to allocate net packet, release the original. */
|
|
fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
|
|
|
|
nx_packet_release(packet_ptr);
|
|
|
|
memset(client_request_ptr,0, sizeof(NX_TFTP_CLIENT_REQUEST));
|
|
|
|
return;
|
|
}
|
|
|
|
/* Successful packet copy. Release the original packet and reassign the packet pointer variable. */
|
|
nx_packet_release(packet_ptr);
|
|
packet_ptr = temp_ptr;
|
|
}
|
|
|
|
/* Attempt to write the block to the file. */
|
|
status = fx_file_write(&(client_request_ptr -> nx_tftp_client_request_file), packet_ptr -> nx_packet_prepend_ptr+4,
|
|
packet_ptr -> nx_packet_length - 4);
|
|
|
|
/* Check for successful file write. */
|
|
if (status != NX_SUCCESS)
|
|
{
|
|
|
|
/* Send an error to the client. */
|
|
_nx_tftp_server_send_error(server_ptr, ip_address, port, NX_TFTP_ERROR_NOT_DEFINED, "NetX TFTP Server: File Write Error");
|
|
|
|
/* Unable to write the file, close it and release the packet. */
|
|
fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
|
|
|
|
nx_packet_release(packet_ptr);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Check the last packet. */
|
|
if (packet_ptr -> nx_packet_length - 4 < NX_TFTP_FILE_TRANSFER_MAX)
|
|
{
|
|
fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
|
|
}
|
|
|
|
status = _nx_tftp_server_send_ack(server_ptr, client_request_ptr, NX_FALSE);
|
|
|
|
if (status == NX_SUCCESS)
|
|
{
|
|
|
|
/* Increment the number of total bytes received. */
|
|
server_ptr -> nx_tftp_server_total_bytes_received += (packet_ptr -> nx_packet_length - 4);
|
|
|
|
/* Determine if this was the last write. */
|
|
if ((packet_ptr -> nx_packet_length - 4) < NX_TFTP_FILE_TRANSFER_MAX)
|
|
{
|
|
|
|
/* No, nothing left to write. Close the file, release the packet and delete
|
|
the client request. */
|
|
fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
|
|
memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST));
|
|
}
|
|
}
|
|
|
|
/* Release the original packet. */
|
|
nx_packet_release(packet_ptr);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _nx_tftp_server_ack_process PORTABLE C */
|
|
/* 6.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Yuxin Zhou, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function processes an ACK to the previous file read */
|
|
/* operation and prepares the next data packet to send if necessary. */
|
|
/* */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* server_ptr Pointer to TFTP server */
|
|
/* packet_ptr Pointer to TFTP request packet*/
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* None */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* fx_file_close Close file on EOF or error */
|
|
/* fx_file_read Read block from file */
|
|
/* _nx_tftp_server_find_client_request Find client entry */
|
|
/* _nx_tftp_server_send_error Send error message */
|
|
/* nx_packet_allocate Allocate a new packet */
|
|
/* nx_packet_copy Copy packet */
|
|
/* nx_packet_release Release packet */
|
|
/* nx_udp_socket_send Send TFTP data packet */
|
|
/* nx_udp_source_extract Extract IP and port */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* _nx_tftp_server_thread_entry TFTP Server thread */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
|
|
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
|
|
/* resulting in version 6.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
VOID _nx_tftp_server_ack_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr)
|
|
{
|
|
|
|
ULONG ip_address;
|
|
UINT port;
|
|
USHORT block_number;
|
|
UCHAR *buffer_ptr;
|
|
NX_TFTP_CLIENT_REQUEST *client_request_ptr;
|
|
|
|
|
|
/* Extract the source IP and port numbers. */
|
|
nx_udp_source_extract(packet_ptr, &ip_address, &port);
|
|
|
|
|
|
/* Find a matching entry in the client request structure. */
|
|
client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, port, ip_address);
|
|
|
|
/* Determine if there was a matching entry. */
|
|
if (client_request_ptr == NX_NULL)
|
|
{
|
|
|
|
/* Increment the unknown clients errors. */
|
|
server_ptr -> nx_tftp_server_unknown_clients_errors++;
|
|
|
|
/* Send an error to the client. */
|
|
_nx_tftp_server_send_error(server_ptr, ip_address, port, NX_TFTP_ERROR_NO_SUCH_USER, "NetX TFTP Server: Unknown connection");
|
|
|
|
/* No more clients can be serviced, release the packet. */
|
|
nx_packet_release(packet_ptr);
|
|
return;
|
|
}
|
|
|
|
/* Setup a pointer to the block number. */
|
|
buffer_ptr = (UCHAR *) (packet_ptr -> nx_packet_prepend_ptr + 2);
|
|
|
|
if (packet_ptr -> nx_packet_length < 4)
|
|
{
|
|
nx_packet_release(packet_ptr);
|
|
return;
|
|
}
|
|
|
|
/* Pickup the block number. */
|
|
block_number = (USHORT)(*buffer_ptr++);
|
|
block_number = (USHORT)((block_number << 8) | (*buffer_ptr));
|
|
|
|
/* Determine if this block number matches the request. */
|
|
if (client_request_ptr -> nx_tftp_client_request_block_number != block_number)
|
|
{
|
|
|
|
/* Check if this is a retransmitted ACK e.g. our previous data packet was dropped our
|
|
delayed. */
|
|
if (client_request_ptr -> nx_tftp_client_request_block_number == (USHORT)(block_number + 1))
|
|
{
|
|
|
|
#ifndef NX_TFTP_SERVER_RETRANSMIT_ENABLE
|
|
|
|
/* It does. Update how many we have received. */
|
|
client_request_ptr -> nx_tftp_client_request_retransmits++;
|
|
|
|
/* Decide if we should close the client request. */
|
|
if (client_request_ptr -> nx_tftp_client_request_retransmits <= NX_TFTP_MAX_CLIENT_RETRANSMITS)
|
|
{
|
|
|
|
/* Not yet. Just drop the packet for now. */
|
|
nx_packet_release(packet_ptr);
|
|
|
|
return;
|
|
}
|
|
|
|
/* Else handle as an error. */
|
|
#else
|
|
nx_packet_release(packet_ptr);
|
|
|
|
/* (Let the retransmit timeout handler retransmit our data to the client.) */
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
/* Send an error to the client. */
|
|
_nx_tftp_server_send_error(server_ptr, ip_address, port, NX_TFTP_ERROR_ILLEGAL_OPERATION, "NetX TFTP Server: Bad block number");
|
|
|
|
/* Error, close the file, release the packet and delete the client request. */
|
|
fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
|
|
|
|
nx_packet_release(packet_ptr);
|
|
|
|
memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST));
|
|
|
|
return;
|
|
}
|
|
|
|
/* The block number matches, see if there is anything left to send. */
|
|
if ((client_request_ptr -> nx_tftp_client_request_remaining_bytes == 0) &&
|
|
(client_request_ptr -> nx_tftp_client_request_exact_fit == NX_FALSE))
|
|
{
|
|
|
|
/* No, nothing left to send. Close the file, release the packet and delete
|
|
the client request. */
|
|
fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
|
|
|
|
nx_packet_release(packet_ptr);
|
|
|
|
memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST));
|
|
|
|
return;
|
|
}
|
|
|
|
#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE
|
|
/* We have a valid ACK. Reset the retransmit retry counter and retransmit timeout. */
|
|
client_request_ptr -> nx_tftp_client_retransmit_retries = 0;
|
|
client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT;
|
|
#endif
|
|
|
|
/* At this point, we need to send the next block of the file. */
|
|
_nx_tftp_server_send_data(server_ptr, client_request_ptr, NX_FALSE);
|
|
|
|
/* Release the original packet. */
|
|
nx_packet_release(packet_ptr);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _nx_tftp_server_send_data PORTABLE C */
|
|
/* 6.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Yuxin Zhou, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function creates a data packet based on the last ACK received */
|
|
/* and sends it out. This will also retransmit a data packet if */
|
|
/* specified. On error it will close the file and the client request. */
|
|
/* It does not update the Client request e.g. block number. */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* server_ptr Pointer to TFTP server */
|
|
/* client_request_ptr Pointer to Client request */
|
|
/* retransmit Indicate if retransmiting a */
|
|
/* previously sent ACK */
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* status Completion status */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* _nx_tftp_server_close_client_request Terminate a client request */
|
|
/* _nx_tftp_server_send_error Send error status to Client */
|
|
/* nx_packet_allocate Allocate a new packet */
|
|
/* nx_udp_socket_send Send TFTP data packet */
|
|
/* fx_file_seek Set location in file */
|
|
/* fx_file_read Read from set location in file*/
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* _nx_tftp_server_timer_process TFTP timeout event */
|
|
/* _nx_tftp_server_ack_process Process a received ACK */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
|
|
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
|
|
/* resulting in version 6.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
UINT _nx_tftp_server_send_data(NX_TFTP_SERVER *server_ptr, NX_TFTP_CLIENT_REQUEST *client_request_ptr, UINT retransmit)
|
|
{
|
|
|
|
UINT status;
|
|
ULONG actual_size = 0;
|
|
NX_PACKET *new_packet;
|
|
UCHAR *buffer_ptr;
|
|
|
|
|
|
/* Allocate packet for the read packet. Determine whether we are sending IP packets. */
|
|
status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_UDP_PACKET, NX_WAIT_FOREVER);
|
|
|
|
|
|
/* Check for successful packet allocation. */
|
|
if (status != NX_SUCCESS)
|
|
{
|
|
|
|
/* Increment the number of server allocation errors. */
|
|
server_ptr -> nx_tftp_server_allocation_errors++;
|
|
|
|
/* Unable to allocate net packet, release the original. */
|
|
fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
|
|
|
|
memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST));
|
|
|
|
return status;
|
|
}
|
|
|
|
if (4u + NX_TFTP_FILE_TRANSFER_MAX > ((ULONG)(new_packet -> nx_packet_data_end) - (ULONG)(new_packet -> nx_packet_append_ptr)))
|
|
{
|
|
nx_packet_release(new_packet);
|
|
return(NX_SIZE_ERROR);
|
|
}
|
|
|
|
new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr;
|
|
|
|
/* Determine if there are more bytes to read. */
|
|
if (client_request_ptr -> nx_tftp_client_request_remaining_bytes)
|
|
{
|
|
|
|
status = NX_SUCCESS;
|
|
|
|
/* Are we retransmitting? */
|
|
if (retransmit)
|
|
{
|
|
|
|
/* Yes, figure out where to reset the file pointer to the previous
|
|
file read so we can retrieve the previous data we sent. */
|
|
UINT index = client_request_ptr -> nx_tftp_client_file_size -
|
|
client_request_ptr -> nx_tftp_client_request_remaining_bytes -
|
|
client_request_ptr -> nx_tftp_client_previous_write_size;
|
|
|
|
status = fx_file_seek(&(client_request_ptr -> nx_tftp_client_request_file), index);
|
|
}
|
|
|
|
/* Are we still ok to do a file read? */
|
|
if (status == NX_SUCCESS)
|
|
{
|
|
|
|
/* Yes. Attempt to read the requested file. */
|
|
UINT status_read = 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);
|
|
|
|
/* Check for successful file read. */
|
|
if ((status_read != NX_SUCCESS) ||
|
|
((client_request_ptr -> nx_tftp_client_request_remaining_bytes > NX_TFTP_FILE_TRANSFER_MAX) && (actual_size < NX_TFTP_FILE_TRANSFER_MAX)) ||
|
|
((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)))
|
|
{
|
|
|
|
/* Update our 'status' variable with the result from file read. */
|
|
status = status_read;
|
|
}
|
|
}
|
|
|
|
/* Are we ok to transmit more data? */
|
|
if (status != NX_SUCCESS)
|
|
{
|
|
|
|
/* No, send an error back to the client. */
|
|
_nx_tftp_server_send_error(server_ptr, client_request_ptr -> nx_tftp_client_request_ip_address,
|
|
client_request_ptr -> nx_tftp_client_request_port,
|
|
NX_TFTP_ERROR_NOT_DEFINED, "NetX TFTP Server: File Read Error");
|
|
|
|
memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST));
|
|
|
|
/* Unable to read the file, close it and release the packet. */
|
|
fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
|
|
|
|
nx_packet_release(new_packet);
|
|
|
|
return status;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
/* Clear the exact fit flag since the only way we can be here is if the TFTP transfer size
|
|
evenly divided into the file size and we need to send a zero length data buffer to signal
|
|
the end of the file. */
|
|
client_request_ptr -> nx_tftp_client_request_exact_fit = NX_FALSE;
|
|
|
|
/* Set the actual size to zero for exact fit case. */
|
|
actual_size = 0;
|
|
}
|
|
|
|
/* Increment the number of total bytes sent. */
|
|
server_ptr -> nx_tftp_server_total_bytes_sent += actual_size;
|
|
|
|
/* Is this new data being sent (not a retransmit)? */
|
|
if (retransmit == NX_FALSE)
|
|
{
|
|
|
|
/* Yes, so advance the block number and number of bytes of the file sent. */
|
|
client_request_ptr -> nx_tftp_client_request_block_number++;
|
|
|
|
client_request_ptr -> nx_tftp_client_request_remaining_bytes -= actual_size;
|
|
}
|
|
|
|
client_request_ptr -> nx_tftp_client_previous_write_size = actual_size;
|
|
|
|
/* Move the TFTP data code and block number into the payload before sending it to the client. */
|
|
buffer_ptr = new_packet -> nx_packet_prepend_ptr;
|
|
*buffer_ptr++ = 0;
|
|
*buffer_ptr++ = NX_TFTP_CODE_DATA;
|
|
*buffer_ptr++ = (UCHAR) (client_request_ptr -> nx_tftp_client_request_block_number >> 8);
|
|
*buffer_ptr++ = (UCHAR) (client_request_ptr -> nx_tftp_client_request_block_number & 0xFF);
|
|
|
|
/* Setup the packet pointers appropriately. */
|
|
new_packet -> nx_packet_length = actual_size + 4;
|
|
new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr + new_packet -> nx_packet_length;
|
|
|
|
/* Send the data packet out. */
|
|
status = nx_udp_socket_send(&(server_ptr -> nx_tftp_server_socket), new_packet, client_request_ptr -> nx_tftp_client_request_ip_address,
|
|
client_request_ptr -> nx_tftp_client_request_port);
|
|
|
|
/* Release packet if send fails. */
|
|
if (status)
|
|
{
|
|
nx_packet_release(new_packet);
|
|
}
|
|
|
|
return NX_SUCCESS;
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _nx_tftp_server_send_ack PORTABLE C */
|
|
/* 6.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Yuxin Zhou, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function creates an ACK packet based on the last block of data */
|
|
/* received, and sends it out. This will also retransmit an ACK if */
|
|
/* specified. On error it will close the file and the client request. */
|
|
/* It does not update the Client request e.g. block number. */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* server_ptr Pointer to TFTP server */
|
|
/* client_request_ptr Pointer to Client request */
|
|
/* retransmit Indicate if retransmiting a */
|
|
/* previously sent ACK */
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* status Completion status */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* _nx_tftp_server_close_client_request Terminate a client request */
|
|
/* nx_packet_allocate Allocate a new packet */
|
|
/* nx_udp_socket_send Send TFTP data packet */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* _nx_tftp_server_timer_process TFTP timeout event */
|
|
/* _nx_tftp_server_data_process Process a received packet */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
|
|
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
|
|
/* resulting in version 6.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
UINT _nx_tftp_server_send_ack(NX_TFTP_SERVER *server_ptr, NX_TFTP_CLIENT_REQUEST *client_request_ptr, UINT retransmit)
|
|
{
|
|
|
|
UINT status;
|
|
UCHAR *buffer_ptr;
|
|
NX_PACKET *new_packet;
|
|
|
|
|
|
/* Allocate packet for the ACK. Determine whether we are sending IP packets. */
|
|
status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_UDP_PACKET, NX_WAIT_FOREVER);
|
|
|
|
/* Check for successful packet allocation. */
|
|
if (status != NX_SUCCESS)
|
|
{
|
|
|
|
/* Increment the number of server allocation errors. */
|
|
server_ptr -> nx_tftp_server_allocation_errors++;
|
|
|
|
/* Unable to allocate net packet, release the original. */
|
|
fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file));
|
|
|
|
memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST));
|
|
|
|
return status;
|
|
}
|
|
|
|
if (4u > ((ULONG)(new_packet -> nx_packet_data_end) - (ULONG)(new_packet -> nx_packet_append_ptr)))
|
|
{
|
|
nx_packet_release(new_packet);
|
|
return(NX_SIZE_ERROR);
|
|
}
|
|
|
|
new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr;
|
|
|
|
/* Now build the ACK message to the client. */
|
|
buffer_ptr = new_packet -> nx_packet_prepend_ptr;
|
|
*buffer_ptr++ = 0;
|
|
*buffer_ptr++ = NX_TFTP_CODE_ACK;
|
|
|
|
/* If we are retransmitting, send the block number of the previous ACK. */
|
|
if (retransmit)
|
|
{
|
|
|
|
*buffer_ptr++ = (UCHAR) ((client_request_ptr -> nx_tftp_client_request_block_number - 1) >> 8);
|
|
*buffer_ptr++ = (UCHAR) ((client_request_ptr -> nx_tftp_client_request_block_number - 1) & 0xFF);
|
|
}
|
|
else
|
|
{
|
|
|
|
*buffer_ptr++ = (UCHAR) ((client_request_ptr -> nx_tftp_client_request_block_number) >> 8);
|
|
*buffer_ptr++ = (UCHAR) (client_request_ptr -> nx_tftp_client_request_block_number & 0xFF);
|
|
}
|
|
|
|
/* Setup the packet pointers appropriately. */
|
|
new_packet -> nx_packet_length = 4;
|
|
new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr + 4;
|
|
|
|
/* Send the ACK packet out. */
|
|
status = nx_udp_socket_send(&(server_ptr -> nx_tftp_server_socket), new_packet, client_request_ptr -> nx_tftp_client_request_ip_address,
|
|
client_request_ptr -> nx_tftp_client_request_port);
|
|
|
|
/* Release packet if send fails. */
|
|
if (status)
|
|
{
|
|
nx_packet_release(new_packet);
|
|
}
|
|
|
|
/* Is this ACK for new data received (e.g. not a retransmit)? */
|
|
if (retransmit == NX_FALSE)
|
|
{
|
|
|
|
/* Yes, so increase the block number. */
|
|
client_request_ptr -> nx_tftp_client_request_block_number++;
|
|
}
|
|
|
|
return NX_SUCCESS;
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _nx_tftp_server_error_process PORTABLE C */
|
|
/* 6.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Yuxin Zhou, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function processes an error sent by a client. */
|
|
/* */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* server_ptr Pointer to TFTP server */
|
|
/* packet_ptr Pointer to TFTP request packet*/
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* None */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* nx_packet_release Release packet */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* _nx_tftp_server_thread_entry TFTP Server thread task */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
|
|
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
|
|
/* resulting in version 6.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
VOID _nx_tftp_server_error_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr)
|
|
{
|
|
|
|
UINT i;
|
|
UCHAR *buffer_ptr;
|
|
UINT port;
|
|
ULONG ip_address;
|
|
NX_TFTP_CLIENT_REQUEST *client_request_ptr;
|
|
|
|
|
|
/* Pickup a pointer to the error code in the buffer. */
|
|
buffer_ptr = packet_ptr -> nx_packet_prepend_ptr + 2;
|
|
|
|
if (packet_ptr -> nx_packet_length < 4)
|
|
{
|
|
nx_packet_release(packet_ptr);
|
|
return;
|
|
}
|
|
|
|
/* Set the error code in the server control block. */
|
|
server_ptr -> nx_tftp_server_error_code = (((UINT) (*buffer_ptr)) << 8);
|
|
buffer_ptr++;
|
|
server_ptr -> nx_tftp_server_error_code |= ((UINT) (*buffer_ptr) & 0xFF);
|
|
buffer_ptr++;
|
|
|
|
/* Loop to save error message. */
|
|
server_ptr -> nx_tftp_server_error_string[sizeof(server_ptr -> nx_tftp_server_error_string) - 1] = NX_NULL;
|
|
for (i = 0; i < NX_TFTP_ERROR_STRING_MAX; i++)
|
|
{
|
|
|
|
/* Store desired file name. */
|
|
server_ptr -> nx_tftp_server_error_string[i] = (CHAR) *buffer_ptr++;
|
|
|
|
/* Check for NULL character. */
|
|
if (server_ptr -> nx_tftp_server_error_string[i] == NX_NULL)
|
|
break;
|
|
|
|
/* Check for packet buffer boundary. */
|
|
if (buffer_ptr >= packet_ptr -> nx_packet_append_ptr)
|
|
break;
|
|
}
|
|
|
|
/* Extract the source IP and port numbers. */
|
|
|
|
nx_udp_source_extract(packet_ptr, &ip_address, &port);
|
|
|
|
/* First, try to find a matching existing entry in the client request structure. */
|
|
client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, port, ip_address);
|
|
|
|
/* Reset the retransmit timeout on the client request. */
|
|
if (client_request_ptr)
|
|
{
|
|
#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE
|
|
|
|
client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT;
|
|
client_request_ptr -> nx_tftp_client_retransmit_retries = 0;
|
|
#else
|
|
|
|
client_request_ptr -> nx_tftp_client_request_retransmits = 0;
|
|
|
|
#endif /* NX_TFTP_SERVER_RETRANSMIT_ENABLE */
|
|
}
|
|
|
|
/* Release the packet. */
|
|
nx_packet_release(packet_ptr);
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _nx_tftp_server_find_client_request PORTABLE C */
|
|
/* 6.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Yuxin Zhou, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function attempts to find the specified IP and port number in */
|
|
/* the client request array of this TFTP server instance. */
|
|
/* */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* server_ptr Pointer to TFTP server */
|
|
/* port Client port number */
|
|
/* ip_address Client IP address */
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* NX_TFTP_CLIENT_REQUEST * NULL if not found */
|
|
/* Non null if match found */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* nx_packet_release Release packet */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* _nx_tftp_server_ack_process ACK processing */
|
|
/* _nx_tftp_server_data_process Data packet processing */
|
|
/* _nx_tftp_server_open_for_write_process Open for write processing */
|
|
/* _nx_tftp_server_open_for_read_process Open for read processing */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
|
|
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
|
|
/* resulting in version 6.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
NX_TFTP_CLIENT_REQUEST * _nx_tftp_server_find_client_request(NX_TFTP_SERVER *server_ptr, UINT port, ULONG ip_address)
|
|
{
|
|
|
|
UINT i;
|
|
NX_TFTP_CLIENT_REQUEST *client_request_ptr;
|
|
|
|
/* First, find a free entry in the client request structure. */
|
|
i = 0;
|
|
for (i = 0; i < NX_TFTP_MAX_CLIENTS; i++)
|
|
{
|
|
client_request_ptr = &(server_ptr -> nx_tftp_server_client_list[i]);
|
|
|
|
/* First check if we are adding an address. If the caller sends in a blank
|
|
address and port, we are. */
|
|
if (port == 0)
|
|
{
|
|
|
|
/* We are adding an address. Now check if this slot is empty. */
|
|
|
|
if (client_request_ptr -> nx_tftp_client_request_port == 0)
|
|
{
|
|
|
|
/* If there is no port number, this is an empty slot. But let's clear the slot anyway. */
|
|
memset(&(server_ptr -> nx_tftp_server_client_list[i]), 0, sizeof(NX_TFTP_CLIENT_REQUEST));
|
|
|
|
break;
|
|
}
|
|
}
|
|
/* This is a valid address. Does it match the current entry? */
|
|
else
|
|
{
|
|
if((client_request_ptr -> nx_tftp_client_request_port == port) &&
|
|
(client_request_ptr -> nx_tftp_client_request_ip_address == ip_address ))
|
|
{
|
|
/* Yes, they match. */
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Determine if a match was found. */
|
|
if (i < NX_TFTP_MAX_CLIENTS)
|
|
{
|
|
/* Return a pointer to the matching client request. */
|
|
return(&(server_ptr -> nx_tftp_server_client_list[i]));
|
|
}
|
|
else
|
|
{
|
|
/* Return a NULL pointer indicating no match found. */
|
|
return((NX_TFTP_CLIENT_REQUEST *)NX_NULL);
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _nx_tftp_server_send_error PORTABLE C */
|
|
/* 6.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Yuxin Zhou, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function send a TFTP error message to the client specified */
|
|
/* by the port and IP address. */
|
|
/* */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* server_ptr Pointer to TFTP server */
|
|
/* ip_address Client IP address */
|
|
/* port Client port number */
|
|
/* error TFTP error code */
|
|
/* error_message Error string */
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* None */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* nx_packet_allocate Allocate error packet */
|
|
/* nx_udp_socket_send Send TFPT error packet */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* _nx_tftp_server_ack_process ACK processing */
|
|
/* _nx_tftp_server_data_process Data packet processing */
|
|
/* _nx_tftp_server_open_for_write_process Open for write processing */
|
|
/* _nx_tftp_server_open_for_read_process Open for read processing */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
|
|
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
|
|
/* resulting in version 6.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
VOID _nx_tftp_server_send_error(NX_TFTP_SERVER *server_ptr, ULONG ip_address, UINT port, UINT error, CHAR *error_message)
|
|
{
|
|
|
|
UINT status;
|
|
UCHAR *buffer_ptr;
|
|
NX_PACKET *new_packet;
|
|
|
|
|
|
/* Allocate packet for the read packet. Determine whether we are sending IP packets. */
|
|
status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_UDP_PACKET, NX_WAIT_FOREVER);
|
|
|
|
/* Check for successful packet allocation. */
|
|
if (status != NX_SUCCESS)
|
|
{
|
|
|
|
/* Increment the number of server allocation errors. */
|
|
server_ptr -> nx_tftp_server_allocation_errors++;
|
|
|
|
/* Unable to allocate packet for error message, just return! */
|
|
return;
|
|
}
|
|
|
|
if (6u > ((ULONG)(new_packet -> nx_packet_data_end) - (ULONG)(new_packet -> nx_packet_append_ptr)))
|
|
{
|
|
nx_packet_release(new_packet);
|
|
return;
|
|
}
|
|
|
|
new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr;
|
|
|
|
/* Move the TFTP error code and message into the payload before sending it to the client. */
|
|
buffer_ptr = new_packet -> nx_packet_prepend_ptr;
|
|
*buffer_ptr++ = 0;
|
|
*buffer_ptr++ = NX_TFTP_CODE_ERROR;
|
|
*buffer_ptr++ = 0;
|
|
*buffer_ptr++ = (UCHAR) (error & 0xFF);
|
|
|
|
/* Loop to copy the error message into the buffer. */
|
|
do
|
|
{
|
|
|
|
/* Copy a byte of the error message into the buffer. */
|
|
*buffer_ptr = (UCHAR) *error_message;
|
|
|
|
/* Determine if a NULL is present. */
|
|
if (*buffer_ptr == NX_NULL)
|
|
{
|
|
|
|
/* Yes, we are at the end of the string end the loop. */
|
|
break;
|
|
}
|
|
|
|
/* Move both pointers to the next character. */
|
|
buffer_ptr++;
|
|
error_message++;
|
|
} while (buffer_ptr < (new_packet -> nx_packet_data_end - 1));
|
|
|
|
/* Ensure a NULL is in the last position! */
|
|
*buffer_ptr++ = NX_NULL;
|
|
|
|
/* Setup the packet pointers appropriately. */
|
|
new_packet -> nx_packet_length = (ULONG)(buffer_ptr - new_packet -> nx_packet_prepend_ptr);
|
|
new_packet -> nx_packet_append_ptr = buffer_ptr;
|
|
|
|
/* Send the data packet out. */
|
|
status = nx_udp_socket_send(&(server_ptr -> nx_tftp_server_socket), new_packet, ip_address, port);
|
|
|
|
/* Release packet if send fails. */
|
|
if (status)
|
|
{
|
|
nx_packet_release(new_packet);
|
|
}
|
|
}
|