| /** @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_ |