/** @file | |
Definitions for the TFTP server. | |
Copyright (c) 2011, 2012, Intel Corporation | |
All rights reserved. This program and the accompanying materials | |
are licensed and made available under the terms and conditions of the BSD License | |
which accompanies this distribution. The full text of the license may be found at | |
http://opensource.org/licenses/bsd-license.php | |
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
**/ | |
#ifndef _TFTP_SERVER_H_ | |
#define _TFTP_SERVER_H_ | |
#include <errno.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <Uefi.h> | |
#include <Guid/EventGroup.h> | |
#include <Library/BaseMemoryLib.h> | |
#include <Library/DebugLib.h> | |
#include <Library/MemoryAllocationLib.h> | |
#include <Library/PcdLib.h> | |
#include <Library/TimerLib.h> | |
#include <Library/UefiApplicationEntryPoint.h> | |
#include <Library/UefiBootServicesTableLib.h> | |
#include <Library/UefiLib.h> | |
#include <Protocol/BlockIo.h> | |
#include <netinet/in.h> | |
#include <netinet6/in6.h> | |
#include <sys/EfiSysCall.h> | |
#include <sys/poll.h> | |
#include <sys/socket.h> | |
#include <sys/stat.h> | |
//------------------------------------------------------------------------------ | |
// Macros | |
//------------------------------------------------------------------------------ | |
#if defined(_MSC_VER) /* Handle Microsoft VC++ compiler specifics. */ | |
#define DBG_ENTER() DEBUG (( DEBUG_ENTER_EXIT, "Entering " __FUNCTION__ "\n" )) ///< Display routine entry | |
#define DBG_EXIT() DEBUG (( DEBUG_ENTER_EXIT, "Exiting " __FUNCTION__ "\n" )) ///< Display routine exit | |
#define DBG_EXIT_DEC(Status) DEBUG (( DEBUG_ENTER_EXIT, "Exiting " __FUNCTION__ ", Status: %d\n", Status )) ///< Display routine exit with decimal value | |
#define DBG_EXIT_HEX(Status) DEBUG (( DEBUG_ENTER_EXIT, "Exiting " __FUNCTION__ ", Status: 0x%08x\n", Status )) ///< Display routine exit with hex value | |
#define DBG_EXIT_STATUS(Status) DEBUG (( DEBUG_ENTER_EXIT, "Exiting " __FUNCTION__ ", Status: %r\n", Status )) ///< Display routine exit with status value | |
#define DBG_EXIT_TF(Status) DEBUG (( DEBUG_ENTER_EXIT, "Exiting " __FUNCTION__ ", returning %s\n", (FALSE == Status) ? L"FALSE" : L"TRUE" )) ///< Display routine with TRUE/FALSE value | |
#else // _MSC_VER | |
#define DBG_ENTER() | |
#define DBG_EXIT() | |
#define DBG_EXIT_DEC(Status) | |
#define DBG_EXIT_HEX(Status) | |
#define DBG_EXIT_STATUS(Status) | |
#define DBG_EXIT_TF(Status) | |
#endif // _MSC_VER | |
#define DIM(x) ( sizeof ( x ) / sizeof ( x[0] )) ///< Compute the number of entries in an array | |
//------------------------------------------------------------------------------ | |
// Constants | |
//------------------------------------------------------------------------------ | |
#define ACK_SHIFT 4 ///< Number of samples in ACK average | |
#define DEBUG_WINDOW 0x00000001 ///< Display the window messages | |
#define DEBUG_TX_PACKET 0x00000002 ///< Display the transmit packet messages | |
#define DEBUG_FILE_BUFFER 0x00000004 ///< Display the file buffer messages | |
#define DEBUG_SERVER_TIMER 0x00000008 ///< Display the socket poll messages | |
#define DEBUG_TFTP_REQUEST 0x00000010 ///< Display the TFTP request messages | |
#define DEBUG_PORT_WORK 0x00000020 ///< Display the port work messages | |
#define DEBUG_SOCKET_POLL 0x00000040 ///< Display the socket poll messages | |
#define DEBUG_TFTP_PORT 0x00000080 ///< Display the TFTP port messages | |
#define DEBUG_TX 0x00000100 ///< Display transmit messages | |
#define DEBUG_RX 0x00000200 ///< Display receive messages | |
#define DEBUG_TFTP_ACK 0x00000400 ///< Display the TFTP ACK messages | |
#define DEBUG_ENTER_EXIT 0x00000800 ///< Display entry and exit messages | |
#define MAX_PACKETS 8 ///< Maximum number of packets in the window | |
#define TFTP_PORT_POLL_DELAY ( 2 * 1000 ) ///< Delay in milliseconds for attempts to open the TFTP port | |
#define CLIENT_POLL_DELAY 50 ///< Delay in milliseconds between client polls | |
#define TPL_TFTP_SERVER TPL_CALLBACK ///< TPL for routine synchronization | |
/** | |
Verify new TPL value | |
This macro which is enabled when debug is enabled verifies that | |
the new TPL value is >= the current TPL value. | |
**/ | |
#ifdef VERIFY_TPL | |
#undef VERIFY_TPL | |
#endif // VERIFY_TPL | |
#if !defined(MDEPKG_NDEBUG) | |
#define VERIFY_TPL(tpl) \ | |
{ \ | |
EFI_TPL PreviousTpl; \ | |
\ | |
PreviousTpl = gBS->RaiseTPL ( TPL_HIGH_LEVEL ); \ | |
gBS->RestoreTPL ( PreviousTpl ); \ | |
if ( PreviousTpl > tpl ) { \ | |
DEBUG (( DEBUG_ERROR, "Current TPL: %d, New TPL: %d\r\n", PreviousTpl, tpl )); \ | |
ASSERT ( PreviousTpl <= tpl ); \ | |
} \ | |
} | |
#else // MDEPKG_NDEBUG | |
#define VERIFY_TPL(tpl) | |
#endif // MDEPKG_NDEBUG | |
#define TFTP_SERVER_SIGNATURE SIGNATURE_32('T','F','T','P') ///< TSDT_TFTP_SERVER memory signature | |
// | |
// See: http://www.rfc-editor.org/rfc/pdfrfc/rfc1350.txt.pdf | |
// | |
// TFTP Operations | |
// | |
#define TFTP_OP_READ_REQUEST 1 ///< Read request, zero terminated file name, zero terminated mode | |
#define TFTP_OP_WRITE_REQUEST 2 ///< Write request, zero terminated file name, zero terminated mode | |
#define TFTP_OP_DATA 3 ///< Data block, end-of-file indicated by short block | |
#define TFTP_OP_ACK 4 ///< ACK block number | |
#define TFTP_OP_ERROR 5 ///< Error number and explaination | |
#define TFTP_OP_OACK 6 ///< ACK the options | |
#define TFTP_MAX_BLOCK_SIZE 4096 ///< Maximum block size | |
#define TFTP_ERROR_SEE_MSG 0 ///< See the error message | |
#define TFTP_ERROR_NOT_FOUND 1 ///< File not found | |
#define TFTP_ERROR_ACCESS_VIOLATION 2 ///< Access violation | |
#define TFTP_ERROR_DISK_FULL 3 ///< Disk full | |
#define TFTP_ERROR_ILLEGAL_OP 4 ///< Illegal operation | |
#define TFTP_ERROR_UNKNOWN_XFER_ID 5 ///< Unknown transfer ID | |
#define TFTP_ERROR_FILE_EXISTS 6 ///< File already exists | |
#define TFTP_ERROR_NO_SUCH_USER 7 ///< No such user | |
//------------------------------------------------------------------------------ | |
// Data Types | |
//------------------------------------------------------------------------------ | |
/** | |
Packet structure | |
**/ | |
typedef struct _TFTP_PACKET TFTP_PACKET; | |
typedef struct _TFTP_PACKET { | |
TFTP_PACKET * pNext; ///< Next packet in list | |
UINT64 TxTime; ///< Time the transmit was performed | |
ssize_t TxBytes; ///< Bytes in the TX buffer | |
UINT32 RetryCount; ///< Number of transmissions | |
UINT16 BlockNumber; ///< Block number of this packet | |
UINT8 TxBuffer[ 2 + 2 + TFTP_MAX_BLOCK_SIZE ]; ///< Transmit buffer | |
} GCC_TFTP_PACKET; | |
/** | |
Port control structure | |
**/ | |
typedef struct _TSDT_CONNECTION_CONTEXT TSDT_CONNECTION_CONTEXT; | |
typedef struct _TSDT_CONNECTION_CONTEXT { | |
// | |
// Remote connection management | |
// | |
TSDT_CONNECTION_CONTEXT * pNext; ///< Next context in the connection list | |
struct sockaddr_in6 RemoteAddress; ///< Remote address | |
int SocketFd; ///< Socket file descriptor | |
// | |
// File management parameters | |
// | |
FILE * File; ///< NULL while file is closed | |
UINT64 LengthInBytes; ///< Size of the file | |
UINT64 BytesRemaining; ///< Number of bytes remaining to be sent | |
UINT64 BytesToSend; ///< Number of bytes to send | |
UINT64 ValidBytes; ///< Number of valid bytes in the buffer | |
BOOLEAN bEofSent; ///< End of file sent | |
UINT8 * pFill; ///< Next portion of the buffer to fill | |
UINT8 * pBuffer; ///< Pointer into the file data | |
UINT8 * pEnd; ///< End of the file data | |
UINT8 FileData[ 2 * MAX_PACKETS * TFTP_MAX_BLOCK_SIZE ]; ///< File data to send | |
UINT64 TimeStart; ///< Start of file transfer | |
// | |
// TFTP management parameters | |
// | |
UINT16 BlockNumber; ///< Next block to be transmitted | |
UINT32 BlockSize; ///< Negotiated block size | |
// | |
// Window management | |
// | |
UINT32 AckCount; ///< Number of ACKs to receive before increasing the window | |
UINT32 PacketsInWindow; ///< Number of packets in the window | |
UINT32 Threshold; ///< Size of window when ACK count becomes logrithmic | |
UINT32 WindowSize; ///< Size of the transmit window | |
UINT64 MaxTimeout; ///< Maximum number of seconds to wait before retransmission | |
UINT64 Rtt2x; ///< Twice the average round trip time in nanoseconds | |
// | |
// Buffer management | |
// | |
TFTP_PACKET * pFreeList; ///< List of free packets | |
TFTP_PACKET * pTxHead; ///< First packet in the list of packets for transmission | |
TFTP_PACKET * pTxTail; ///< Last packet in the list of packets for transmission | |
TFTP_PACKET ErrorPacket; ///< Error packet | |
TFTP_PACKET Tx[ MAX_PACKETS ];///< Transmit packets | |
}GCC_TSDT_CONNECTION_CONTEXT; | |
/** | |
TFTP server control structure | |
**/ | |
typedef struct { | |
UINTN Signature; ///< Structure identification | |
// | |
// Image attributes | |
// | |
EFI_HANDLE ImageHandle; ///< Image handle | |
// | |
// Performance management | |
// | |
UINT64 ClockFrequency; ///< Frequency of the clock | |
UINT64 Time1; ///< Clock value after rollover | |
UINT64 Time2; ///< Clock value before rollover | |
UINT64 RxTime; ///< Time when the packet was recevied | |
// | |
// TFTP port management | |
// | |
EFI_EVENT TimerEvent; ///< Timer to open TFTP port | |
int Udpv4Index; ///< Entry for UDPv4 | |
int Udpv6Index; ///< Entry for UDPv6 | |
int Entries; ///< Number of TFTP ports | |
struct pollfd TftpPort [ 2 ]; ///< Poll descriptor for the TFTP ports (UDP4, UDP6) | |
// | |
// Request management | |
// | |
union { | |
struct sockaddr_in v4; ///< UDP4 address | |
struct sockaddr_in6 v6; ///< UDP6 address | |
} RemoteAddress; ///< Remote address | |
ssize_t RxBytes; ///< Receive data length in bytes | |
UINT8 RxBuffer[ 2 + 2 + TFTP_MAX_BLOCK_SIZE ]; ///< Receive buffer | |
// | |
// Client port management | |
// | |
TSDT_CONNECTION_CONTEXT * pContextList; ///< List of connection context structures | |
} TSDT_TFTP_SERVER; | |
//#define SERVER_FROM_SERVICE(a) CR(a, TSDT_TFTP_SERVER, ServiceBinding, TFTP_SERVER_SIGNATURE) ///< Locate DT_LAYER from service binding | |
extern TSDT_TFTP_SERVER mTftpServer; | |
//------------------------------------------------------------------------------ | |
// Support routines | |
//------------------------------------------------------------------------------ | |
/** | |
Queue data packets for transmission | |
@param [in] pContext Connection context structure address | |
@retval TRUE if a read error occurred | |
**/ | |
BOOLEAN | |
PacketFill ( | |
IN TSDT_CONNECTION_CONTEXT * pContext | |
); | |
/** | |
Free the packet | |
@param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure | |
@param [in] pPacket Address of a ::TFTP_PACKET structure | |
**/ | |
VOID | |
PacketFree( | |
IN TSDT_CONNECTION_CONTEXT * pContext, | |
IN TFTP_PACKET * pPacket | |
); | |
/** | |
Get a packet for transmission | |
@param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure | |
@retval Address of a ::TFTP_PACKET structure | |
**/ | |
TFTP_PACKET * | |
PacketGet ( | |
IN TSDT_CONNECTION_CONTEXT * pContext | |
); | |
/** | |
Queue the packet for transmission | |
@param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure | |
@param [in] pPacket Address of a ::TFTP_PACKET structure | |
@retval TRUE if a transmission error has occurred | |
**/ | |
BOOLEAN | |
PacketQueue ( | |
IN TSDT_CONNECTION_CONTEXT * pContext, | |
IN TFTP_PACKET * pPacket | |
); | |
/** | |
Transmit the packet | |
@param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure | |
@param [in] pPacket Address of a ::TFTP_PACKET structure | |
@retval EFI_SUCCESS Message processed successfully | |
**/ | |
EFI_STATUS | |
PacketTx ( | |
IN TSDT_CONNECTION_CONTEXT * pContext, | |
IN TFTP_PACKET * pPacket | |
); | |
/** | |
Build and send an error packet | |
@param [in] pContext The context structure address. | |
@param [in] Error Error number for the packet | |
@param [in] pError Zero terminated error string address | |
@retval EFI_SUCCESS Message processed successfully | |
**/ | |
EFI_STATUS | |
SendError ( | |
IN TSDT_CONNECTION_CONTEXT * pContext, | |
IN UINT16 Error, | |
IN UINT8 * pError | |
); | |
/** | |
Process the TFTP request | |
@param [in] pOption Address of the first zero terminated option string | |
@param [in] pValue Address to receive the value | |
@retval EFI_SUCCESS Option translated into a value | |
**/ | |
EFI_STATUS | |
TftpOptionValue ( | |
IN UINT8 * pOption, | |
IN INT32 * pValue | |
); | |
/** | |
Process the TFTP request | |
@param [in] pTftpServer The TFTP server control structure address. | |
@param [in] pContext Connection context structure address | |
@param [in] SocketFd Socket file descriptor | |
**/ | |
VOID | |
TftpProcessRequest ( | |
IN TSDT_TFTP_SERVER * pTftpServer, | |
IN TSDT_CONNECTION_CONTEXT * pContext, | |
IN int SocketFd | |
); | |
/** | |
Process the read request | |
@param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure | |
@param [in] pContext Connection context structure address | |
@param [in] SocketFd Socket file descriptor | |
@retval TRUE if the context should be closed | |
**/ | |
BOOLEAN | |
TftpRead ( | |
IN TSDT_TFTP_SERVER * pTftpServer, | |
IN TSDT_CONNECTION_CONTEXT * pContext, | |
IN int SocketFd | |
); | |
/** | |
Update the window due to the ACK | |
@param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure | |
@param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure | |
@param [in] pPacket Address of a ::TFTP_PACKET structure | |
**/ | |
VOID | |
WindowAck ( | |
IN TSDT_TFTP_SERVER * pTftpServer, | |
IN TSDT_CONNECTION_CONTEXT * pContext, | |
IN TFTP_PACKET * pPacket | |
); | |
/** | |
A timeout has occurred, close the window | |
@param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure | |
**/ | |
VOID | |
WindowTimeout ( | |
IN TSDT_CONNECTION_CONTEXT * pContext | |
); | |
//------------------------------------------------------------------------------ | |
#endif // _TFTP_SERVER_H_ |