2011-07-30 02:32:15 +02:00
/** @file
Definitions for the TFTP server .
2012-02-09 20:18:06 +01:00
Copyright ( c ) 2011 , 2012 , Intel Corporation
2011-07-30 02:32:15 +02:00
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>
2012-02-09 20:18:06 +01:00
# include <stdio.h>
2011-07-30 02:32:15 +02:00
# include <stdlib.h>
# include <string.h>
# include <Uefi.h>
# include <Guid/EventGroup.h>
# include <Library/BaseMemoryLib.h>
# include <Library/DebugLib.h>
2012-02-09 20:18:06 +01:00
# include <Library/MemoryAllocationLib.h>
2011-07-30 02:32:15 +02:00
# include <Library/PcdLib.h>
2012-02-09 20:18:06 +01:00
# include <Library/TimerLib.h>
2011-07-30 02:32:15 +02:00
# include <Library/UefiApplicationEntryPoint.h>
# include <Library/UefiBootServicesTableLib.h>
# include <Library/UefiLib.h>
# include <Protocol/BlockIo.h>
# include <netinet/in.h>
2012-02-09 20:18:06 +01:00
# include <netinet6/in6.h>
2011-07-30 02:32:15 +02:00
# include <sys/EfiSysCall.h>
# include <sys/poll.h>
# include <sys/socket.h>
2012-02-09 20:18:06 +01:00
# include <sys/Stat.h>
2011-07-30 02:32:15 +02:00
//------------------------------------------------------------------------------
// Macros
//------------------------------------------------------------------------------
# if defined(_MSC_VER) /* Handle Microsoft VC++ compiler specifics. */
2012-02-09 20:18:06 +01:00
# 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
2011-07-30 02:32:15 +02:00
# 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
//------------------------------------------------------------------------------
2012-02-09 20:18:06 +01:00
# 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
2011-07-30 02:32:15 +02:00
# 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
2012-02-09 20:18:06 +01:00
# 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
2011-07-30 02:32:15 +02:00
//------------------------------------------------------------------------------
// Data Types
//------------------------------------------------------------------------------
2012-02-09 20:18:06 +01:00
/**
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 ;
2011-07-30 02:32:15 +02:00
/**
Port control structure
* */
typedef struct _TSDT_CONNECTION_CONTEXT TSDT_CONNECTION_CONTEXT ;
typedef struct _TSDT_CONNECTION_CONTEXT {
//
// Remote connection management
//
2012-02-09 20:18:06 +01:00
TSDT_CONNECTION_CONTEXT * pNext ; ///< Next context in the connection list
struct sockaddr_in6 RemoteAddress ; ///< Remote address
int SocketFd ; ///< Socket file descriptor
2011-07-30 02:32:15 +02:00
//
// File management parameters
//
2012-02-09 20:18:06 +01:00
FILE * File ; ///< NULL while file is closed
2011-07-30 02:32:15 +02:00
UINT64 LengthInBytes ; ///< Size of the file
2012-02-09 20:18:06 +01:00
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
2011-07-30 02:32:15 +02:00
BOOLEAN bEofSent ; ///< End of file sent
2012-02-09 20:18:06 +01:00
UINT8 * pFill ; ///< Next portion of the buffer to fill
2011-07-30 02:32:15 +02:00
UINT8 * pBuffer ; ///< Pointer into the file data
UINT8 * pEnd ; ///< End of the file data
2012-02-09 20:18:06 +01:00
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
2011-07-30 02:32:15 +02:00
//
// Buffer management
//
2012-02-09 20:18:06 +01:00
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
2011-07-30 02:32:15 +02:00
} GCC_TSDT_CONNECTION_CONTEXT ;
/**
TFTP server control structure
* */
typedef struct {
UINTN Signature ; ///< Structure identification
//
// Image attributes
//
EFI_HANDLE ImageHandle ; ///< Image handle
2012-02-09 20:18:06 +01:00
//
// 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
2011-07-30 02:32:15 +02:00
//
// TFTP port management
//
EFI_EVENT TimerEvent ; ///< Timer to open TFTP port
2012-02-09 20:18:06 +01:00
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)
2011-07-30 02:32:15 +02:00
//
// Request management
//
2012-02-09 20:18:06 +01:00
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
2011-07-30 02:32:15 +02:00
//
// 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
//------------------------------------------------------------------------------
/**
2012-02-09 20:18:06 +01:00
Queue data packets for transmission
2011-07-30 02:32:15 +02:00
2012-02-09 20:18:06 +01:00
@ param [ in ] pContext Connection context structure address
2011-07-30 02:32:15 +02:00
2012-02-09 20:18:06 +01:00
@ retval TRUE if a read error occurred
2011-07-30 02:32:15 +02:00
* */
2012-02-09 20:18:06 +01:00
BOOLEAN
PacketFill (
IN TSDT_CONNECTION_CONTEXT * pContext
2011-07-30 02:32:15 +02:00
) ;
/**
2012-02-09 20:18:06 +01:00
Free the packet
2011-07-30 02:32:15 +02:00
2012-02-09 20:18:06 +01:00
@ param [ in ] pContext Address of a : : TSDT_CONNECTION_CONTEXT structure
@ param [ in ] pPacket Address of a : : TFTP_PACKET structure
2011-07-30 02:32:15 +02:00
* */
VOID
2012-02-09 20:18:06 +01:00
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 (
2011-07-30 02:32:15 +02:00
IN TSDT_CONNECTION_CONTEXT * pContext
) ;
2012-02-09 20:18:06 +01:00
/**
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
) ;
2011-07-30 02:32:15 +02:00
/**
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
2012-02-09 20:18:06 +01:00
SendError (
2011-07-30 02:32:15 +02:00
IN TSDT_CONNECTION_CONTEXT * pContext ,
IN UINT16 Error ,
IN UINT8 * pError
) ;
/**
2012-02-09 20:18:06 +01:00
Process the TFTP request
2011-07-30 02:32:15 +02:00
2012-02-09 20:18:06 +01:00
@ param [ in ] pOption Address of the first zero terminated option string
@ param [ in ] pValue Address to receive the value
2011-07-30 02:32:15 +02:00
2012-02-09 20:18:06 +01:00
@ retval EFI_SUCCESS Option translated into a value
2011-07-30 02:32:15 +02:00
* */
EFI_STATUS
2012-02-09 20:18:06 +01:00
TftpOptionValue (
IN UINT8 * pOption ,
IN INT32 * pValue
2011-07-30 02:32:15 +02:00
) ;
/**
2012-02-09 20:18:06 +01:00
Process the TFTP request
2011-07-30 02:32:15 +02:00
2012-02-09 20:18:06 +01:00
@ param [ in ] pTftpServer The TFTP server control structure address .
@ param [ in ] pContext Connection context structure address
@ param [ in ] SocketFd Socket file descriptor
2011-07-30 02:32:15 +02:00
* */
VOID
2012-02-09 20:18:06 +01:00
TftpProcessRequest (
IN TSDT_TFTP_SERVER * pTftpServer ,
IN TSDT_CONNECTION_CONTEXT * pContext ,
IN int SocketFd
2011-07-30 02:32:15 +02:00
) ;
/**
2012-02-09 20:18:06 +01:00
Process the read request
2011-07-30 02:32:15 +02:00
2012-02-09 20:18:06 +01:00
@ param [ in ] pTftpServer Address of the : : TSDT_TFTP_SERVER structure
@ param [ in ] pContext Connection context structure address
@ param [ in ] SocketFd Socket file descriptor
2011-07-30 02:32:15 +02:00
2012-02-09 20:18:06 +01:00
@ retval TRUE if the context should be closed
2011-07-30 02:32:15 +02:00
* */
2012-02-09 20:18:06 +01:00
BOOLEAN
TftpRead (
IN TSDT_TFTP_SERVER * pTftpServer ,
IN TSDT_CONNECTION_CONTEXT * pContext ,
IN int SocketFd
2011-07-30 02:32:15 +02:00
) ;
/**
2012-02-09 20:18:06 +01:00
Update the window due to the ACK
2011-07-30 02:32:15 +02:00
2012-02-09 20:18:06 +01:00
@ 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
2011-07-30 02:32:15 +02:00
* */
2012-02-09 20:18:06 +01:00
VOID
WindowAck (
IN TSDT_TFTP_SERVER * pTftpServer ,
IN TSDT_CONNECTION_CONTEXT * pContext ,
IN TFTP_PACKET * pPacket
2011-07-30 02:32:15 +02:00
) ;
/**
2012-02-09 20:18:06 +01:00
A timeout has occurred , close the window
2011-07-30 02:32:15 +02:00
2012-02-09 20:18:06 +01:00
@ param [ in ] pContext Address of a : : TSDT_CONNECTION_CONTEXT structure
2011-07-30 02:32:15 +02:00
* */
2012-02-09 20:18:06 +01:00
VOID
WindowTimeout (
2011-07-30 02:32:15 +02:00
IN TSDT_CONNECTION_CONTEXT * pContext
) ;
//------------------------------------------------------------------------------
# endif // _TFTP_SERVER_H_