diff options
author | darylm503 <darylm503@6f19259b-4bc3-4df7-8a09-765794883524> | 2011-08-05 23:57:34 +0000 |
---|---|---|
committer | darylm503 <darylm503@6f19259b-4bc3-4df7-8a09-765794883524> | 2011-08-05 23:57:34 +0000 |
commit | 7dc1329100c370992cdd430359512443bd1ee9f2 (patch) | |
tree | 045e04a1051626910da63fba85cf208a5a517734 /AppPkg/Applications/Sockets/TftpServer | |
parent | 59d13433e7cbc810a6268d38141b0d1db353fa6e (diff) | |
download | edk2-platforms-7dc1329100c370992cdd430359512443bd1ee9f2.tar.xz |
Fix @return Doxygen commands to be singular instead of plural.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12094 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'AppPkg/Applications/Sockets/TftpServer')
-rw-r--r-- | AppPkg/Applications/Sockets/TftpServer/TftpServer.c | 3054 |
1 files changed, 1527 insertions, 1527 deletions
diff --git a/AppPkg/Applications/Sockets/TftpServer/TftpServer.c b/AppPkg/Applications/Sockets/TftpServer/TftpServer.c index a1e19c26f9..9b522d1b55 100644 --- a/AppPkg/Applications/Sockets/TftpServer/TftpServer.c +++ b/AppPkg/Applications/Sockets/TftpServer/TftpServer.c @@ -1,1527 +1,1527 @@ -/*++ - This file contains an 'Intel UEFI Application' and is - licensed for Intel CPUs and chipsets under the terms of your - license agreement with Intel or your vendor. This file may - be modified by the user, subject to additional terms of the - license agreement ---*/ -/*++ - -Copyright (c) 2011 Intel Corporation. All rights reserved -This software and associated documentation (if any) is furnished -under a license and may only be used or copied in accordance -with the terms of the license. Except as permitted by such -license, no part of this software or documentation may be -reproduced, stored in a retrieval system, or transmitted in any -form or by any means without the express written consent of -Intel Corporation. - ---*/ - -/** @file - This is a simple TFTP server application - -**/ - -#include <TftpServer.h> - -TSDT_TFTP_SERVER mTftpServer; ///< TFTP server's control structure - - -/** - Add a connection context to the list of connection contexts. - - @param [in] pTftpServer The TFTP server control structure address. - - @retval Context structure address, NULL if allocation fails - -**/ -TSDT_CONNECTION_CONTEXT * -ContextAdd ( - IN TSDT_TFTP_SERVER * pTftpServer - ) -{ - size_t LengthInBytes; - TSDT_CONNECTION_CONTEXT * pContext; - EFI_STATUS Status; - - DBG_ENTER ( ); - - // - // Use for/break instead of goto - // - for ( ; ; ) { - // - // Allocate a new context - // - LengthInBytes = sizeof ( *pContext ); - Status = gBS->AllocatePool ( EfiRuntimeServicesData, - LengthInBytes, - (VOID **)&pContext ); - if ( EFI_ERROR ( Status )) { - DEBUG (( DEBUG_ERROR | DEBUG_POOL, - "ERROR - Failed to allocate the context, Status: %r\r\n", - Status )); - pContext = NULL; - break; - } - - // - // Initialize the context - // - ZeroMem ( pContext, LengthInBytes ); - CopyMem ( &pContext->RemoteAddress, - &pTftpServer->RemoteAddress, - sizeof ( pContext->RemoteAddress )); - pContext->BlockSize = TFTP_MAX_BLOCK_SIZE; - pContext->pBuffer = &pContext->FileData[0]; - pContext->pEnd = &pContext->pBuffer[sizeof ( pContext->pBuffer )]; - pContext->MaxTransferSize = 0; - pContext->MaxTransferSize -= 1; - - // - // Display the new context - // - DEBUG (( DEBUG_PORT_WORK | DEBUG_INFO, - "0x%08x: Context for %d.%d.%d.%d:%d\r\n", - pContext, - (UINT8)pContext->RemoteAddress.sin_addr.s_addr, - (UINT8)( pContext->RemoteAddress.sin_addr.s_addr >> 8 ), - (UINT8)( pContext->RemoteAddress.sin_addr.s_addr >> 16 ), - (UINT8)( pContext->RemoteAddress.sin_addr.s_addr >> 24 ), - htons ( pContext->RemoteAddress.sin_port ))); - - // - // Add the context to the context list - // - pContext->pNext = pTftpServer->pContextList; - pTftpServer->pContextList = pContext; - - // - // All done - // - break; - } - - // - // Return the connection context - // - DBG_EXIT_STATUS ( pContext ); - return pContext; -} - - -/** - Locate a remote connection context. - - @param [in] pTftpServer The TFTP server control structure address. - - @param [in] pIpAddress The start of the remote IP address in network order - - @param [in] Port The remote port number - - @retval Context structure address, NULL if not found - -**/ -TSDT_CONNECTION_CONTEXT * -ContextFind ( - IN TSDT_TFTP_SERVER * pTftpServer - ) -{ - TSDT_CONNECTION_CONTEXT * pContext; - - DBG_ENTER ( ); - - // - // Walk the list of connection contexts - // - pContext = pTftpServer->pContextList; - while ( NULL != pContext ) { - // - // Attempt to locate the remote network connection - // - if (( pTftpServer->RemoteAddress.sin_addr.s_addr == pContext->RemoteAddress.sin_addr.s_addr ) - && ( pTftpServer->RemoteAddress.sin_port == pContext->RemoteAddress.sin_port )) { - // - // The connection was found - // - DEBUG (( DEBUG_TFTP_REQUEST, - "0x%08x: pContext found\r\n", - pContext )); - break; - } - - // - // Set the next context - // - pContext = pContext->pNext; - } - - // - // Return the connection context structure address - // - DBG_EXIT_HEX ( pContext ); - return pContext; -} - - -/** - Remove a context from the list. - - @param [in] pTftpServer The TFTP server control structure address. - - @param [in] pContext The context structure address. - -**/ -VOID -ContextRemove ( - IN TSDT_TFTP_SERVER * pTftpServer, - IN TSDT_CONNECTION_CONTEXT * pContext - ) -{ - TSDT_CONNECTION_CONTEXT * pNextContext; - TSDT_CONNECTION_CONTEXT * pPreviousContext; - - DBG_ENTER ( ); - - // - // Attempt to locate the context in the list - // - pPreviousContext = NULL; - pNextContext = pTftpServer->pContextList; - while ( NULL != pNextContext ) { - // - // Determine if the context was found - // - if ( pNextContext == pContext ) { - // - // Remove the context from the list - // - if ( NULL == pPreviousContext ) { - pTftpServer->pContextList = pContext->pNext; - } - else { - pPreviousContext->pNext = pContext->pNext; - } - break; - } - - // - // Set the next context - // - pPreviousContext = pNextContext; - pNextContext = pNextContext->pNext; - } - - // - // Determine if the context was found - // - if ( NULL != pContext ) { - // - // Return the resources - // - gBS->FreePool ( pContext ); - } - - DBG_EXIT ( ); -} - - -/** - Process the work for the sockets. - - @param [in] pTftpServer The TFTP server control structure address. - -**/ -VOID -PortWork ( - IN TSDT_TFTP_SERVER * pTftpServer - ) -{ - TSDT_CONNECTION_CONTEXT * pContext; - socklen_t RemoteAddressLength; - - DBG_ENTER ( ); - - // - // Handle input events - // - if ( 0 != ( pTftpServer->TftpPort.revents & POLLRDNORM )) { - // - // Receive the message from the remote system - // - RemoteAddressLength = sizeof ( pTftpServer->RemoteAddress ); - pTftpServer->RxBytes = recvfrom ( pTftpServer->TftpPort.fd, - &pTftpServer->RxBuffer[0], - sizeof ( pTftpServer->RxBuffer ), - 0, - (struct sockaddr *) &pTftpServer->RemoteAddress, - &RemoteAddressLength ); - if ( -1 != pTftpServer->RxBytes ) { - pTftpServer->RemoteAddress.sin_len = (UINT8) RemoteAddressLength; - DEBUG (( DEBUG_TFTP_PORT, - "Received %d bytes from %d.%d.%d.%d:%d\r\n", - pTftpServer->RxBytes, - pTftpServer->RemoteAddress.sin_addr.s_addr & 0xff, - ( pTftpServer->RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff, - ( pTftpServer->RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff, - ( pTftpServer->RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff, - htons ( pTftpServer->RemoteAddress.sin_port ))); - - // - // Lookup connection context using the remote system address and port - // to determine if an existing connection to this remote - // system exists - // - pContext = ContextFind ( pTftpServer ); - - // - // Process the received message - // - TftpProcessRequest ( pTftpServer, pContext ); - } - else { - // - // Receive error on the TFTP server port - // Close the server socket - // - DEBUG (( DEBUG_ERROR, - "ERROR - Failed receive on TFTP server port, errno: 0x%08x\r\n", - errno )); - pTftpServer->TftpPort.revents |= POLLHUP; - } - } - - // - // Handle the close event - // - if ( 0 != ( pTftpServer->TftpPort.revents & POLLHUP )) { - // - // Close the port - // - close ( pTftpServer->TftpPort.fd ); - pTftpServer->TftpPort.fd = -1; - } - - DBG_EXIT ( ); -} - - -/** - Scan the list of sockets and process any pending work - - @param [in] pTftpServer The TFTP server control structure address. - -**/ -VOID -SocketPoll ( - IN TSDT_TFTP_SERVER * pTftpServer - ) -{ - int FDCount; - - DEBUG (( DEBUG_SOCKET_POLL, "Entering SocketPoll\r\n" )); - - // - // Determine if any ports are active - // - FDCount = poll ( &pTftpServer->TftpPort, - 1, - CLIENT_POLL_DELAY ); - if ( -1 == FDCount ) { - DEBUG (( DEBUG_ERROR | DEBUG_SOCKET_POLL, - "ERROR - errno: %d\r\n", - errno )); - } - - if ( 0 < FDCount ) { - // - // Process this port - // - PortWork ( pTftpServer ); - pTftpServer->TftpPort.revents = 0; - } - - DEBUG (( DEBUG_SOCKET_POLL, "Exiting SocketPoll\r\n" )); -} - - -/** - Convert a character to lower case - - @param [in] Character The character to convert - - @returns The lower case equivalent of the character - -**/ -int -tolower ( - int Character - ) -{ - // - // Determine if the character is upper case - // - if (( 'A' <= Character ) && ( 'Z' >= Character )) { - // - // Convert the character to lower caes - // - Character += 'a' - 'A'; - } - - // - // Return the converted character - // - return Character; -} - - -/** - Case independent string comparison - - @param [in] pString1 Zero terminated string address - @param [in] pString2 Zero terminated string address - - @returns Returns the first character difference between string 1 - and string 2. - -**/ -int -stricmp ( - char * pString1, - char * pString2 - ) -{ - int Char1; - int Char2; - int Difference; - - // - // Walk the length of the strings - // - do { - // - // Get the next characters - // - Char1 = (UINT8)*pString1++; - Char2 = (UINT8)*pString2++; - - // - // Convert them to lower case - // - Char1 = tolower ( Char1 ); - Char2 = tolower ( Char2 ); - - // - // Done when the characters differ - // - Difference = Char1 - Char2; - if ( 0 != Difference ) { - break; - } - - // - // Done at the end of the string - // - } while ( 0 != Char1 ); - - // - // Return the difference - // - return Difference; -} - - -/** - Get the next TFTP option - - @param [in] pOption Address of a zero terminated option string - @param [in] pEnd End of buffer address - @param [in] ppNextOption Address to receive the address of the next - zero terminated option string - - @retval EFI_SUCCESS Message processed successfully - -**/ -EFI_STATUS -TftpOptionGet ( - IN UINT8 * pOption, - IN UINT8 * pEnd, - IN UINT8 ** ppNextOption - ) -{ - UINT8 * pNextOption; - EFI_STATUS Status; - - // - // Locate the end of the option - // - pNextOption = pOption; - while (( pEnd > pNextOption ) && ( 0 != *pNextOption )) { - pNextOption += 1; - } - if ( pEnd <= pNextOption ) { - // - // Error - end of buffer reached - // - DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST, - "ERROR - Option without zero termination received!\r\n" )); - Status = EFI_INVALID_PARAMETER; - } - else { - // - // Zero terminated option found - // - pNextOption += 1; - - // - // Display the zero terminated ASCII option string - // - DEBUG (( DEBUG_TFTP_REQUEST, - "Option: %a\r\n", - pOption )); - Status = EFI_SUCCESS; - } - - // - // Return the next option address - // - *ppNextOption = pNextOption; - - // - // Return the operation status - // - return Status; -} - - -/** - Place an option value into the option acknowledgement - - @param [in] pOack Option acknowledgement address - @param [in] Value Value to translate into ASCII decimal - - @returns Option acknowledgement address - -**/ -UINT8 * -TftpOptionSet ( - IN UINT8 * pOack, - IN UINT64 Value - ) -{ - UINT64 NextValue; - - // - // Determine the next value - // - NextValue = Value / 10; - - // - // Supress leading zeros - // - if ( 0 != NextValue ) { - pOack = TftpOptionSet ( pOack, NextValue ); - } - - // - // Output this digit - // - *pOack++ = (UINT8)( Value - ( NextValue * 10 ) + '0' ); - - // - // Return the next option acknowledgement location - // - return pOack; -} - - -/** - Process the TFTP request - - @param [in] pContext The context structure address. - @param [in] pOption Address of the first zero terminated option string - @param [in] pEnd End of buffer address - -**/ -VOID -TftpOptions ( - IN TSDT_CONNECTION_CONTEXT * pContext, - IN UINT8 * pOption, - IN UINT8 * pEnd - ) -{ - UINT8 * pNextOption; - UINT8 * pOack; - UINT8 * pTemp; - UINT8 * pValue; - EFI_STATUS Status; - INT32 Value; - - // - // Start the OACK packet - // Let the OACK handle the parsing errors - // See http://tools.ietf.org/html/rfc2347 - // - pOack = &pContext->TxBuffer[0]; - *pOack++ = 0; - *pOack++ = TFTP_OP_OACK; - pContext->TxBytes = 2; - - // - // Walk the list of options - // - do { - // - // Get the next option, skip junk at end of message - // - Status = TftpOptionGet ( pOption, pEnd, &pNextOption ); - if ( !EFI_ERROR ( Status )) { - // - // Process the option - // - - // - // blksize - See http://tools.ietf.org/html/rfc2348 - // - pValue = pNextOption; - if ( 0 == stricmp ((char *)pOption, "blksize" )) { - // - // Get the value - // - Status = TftpOptionGet ( pValue, pEnd, &pNextOption ); - if ( !EFI_ERROR ( Status )) { - // - // Validate the block size, skip non-numeric block sizes - // - Status = TftpOptionValue ( pValue, &Value ); - if ( !EFI_ERROR ( Status )) { - // - // Propose a smaller block size if necessary - // - if ( Value > TFTP_MAX_BLOCK_SIZE ) { - Value = TFTP_MAX_BLOCK_SIZE; - } - - // - // Set the new block size - // - pContext->BlockSize = Value; - DEBUG (( DEBUG_TFTP_REQUEST, - "Using block size of %d bytes\r\n", - pContext->BlockSize )); - - // - // Update the OACK - // - pTemp = pOack; - *pOack++ = 'b'; - *pOack++ = 'l'; - *pOack++ = 'k'; - *pOack++ = 's'; - *pOack++ = 'i'; - *pOack++ = 'z'; - *pOack++ = 'e'; - *pOack++ = 0; - pOack = TftpOptionSet ( pOack, pContext->BlockSize ); - *pOack++ = 0; - pContext->TxBytes += pOack - pTemp; - } - } - } - - // - // timeout - See http://tools.ietf.org/html/rfc2349 - // - else if ( 0 == stricmp ((char *)pOption, "timeout" )) { - // - // Get the value - // - Status = TftpOptionGet ( pValue, pEnd, &pNextOption ); - if ( !EFI_ERROR ( Status )) { - Status = TftpOptionValue ( pValue, &Value ); - if ( !EFI_ERROR ( Status )) { - // - // Set the timeout value - // - pContext->Timeout = Value; - DEBUG (( DEBUG_TFTP_REQUEST, - "Using timeout of %d seconds\r\n", - pContext->Timeout )); - - // - // Update the OACK - // - pTemp = pOack; - *pOack++ = 't'; - *pOack++ = 'i'; - *pOack++ = 'm'; - *pOack++ = 'e'; - *pOack++ = 'o'; - *pOack++ = 'u'; - *pOack++ = 't'; - *pOack++ = 0; - pOack = TftpOptionSet ( pOack, pContext->Timeout ); - *pOack++ = 0; - pContext->TxBytes += pOack - pTemp; - } - } - } - - // - // tsize - See http://tools.ietf.org/html/rfc2349 - // - else if ( 0 == stricmp ((char *)pOption, "tsize" )) { - // - // Get the value - // - Status = TftpOptionGet ( pValue, pEnd, &pNextOption ); - if ( !EFI_ERROR ( Status )) { - Status = TftpOptionValue ( pValue, &Value ); - if ( !EFI_ERROR ( Status )) { - // - // Return the file size - // - DEBUG (( DEBUG_TFTP_REQUEST, - "Returning file size of %Ld bytes\r\n", - pContext->LengthInBytes )); - - // - // Update the OACK - // - pTemp = pOack; - *pOack++ = 't'; - *pOack++ = 's'; - *pOack++ = 'i'; - *pOack++ = 'z'; - *pOack++ = 'e'; - *pOack++ = 0; - pOack = TftpOptionSet ( pOack, pContext->LengthInBytes ); - *pOack++ = 0; - pContext->TxBytes += pOack - pTemp; - } - } - } - else { - // - // Unknown option - Ignore it - // - DEBUG (( DEBUG_WARN | DEBUG_TFTP_REQUEST, - "WARNING - Skipping unknown option: %a\r\n", - pOption )); - } - } - - // - // Set the next option - // - pOption = pNextOption; - } while ( pEnd > pOption ); -} - - -/** - 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 - ) -{ - UINT8 Digit; - EFI_STATUS Status; - INT32 Value; - - // - // Assume success - // - Status = EFI_SUCCESS; - - // - // Walk the characters in the option - // - Value = 0; - while ( 0 != *pOption ) { - // - // Convert the next digit to binary - // - Digit = *pOption++; - if (( '0' <= Digit ) && ( '9' >= Digit )) { - Value *= 10; - Value += Digit - '0'; - } - else { - DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST, - "ERROR - Invalid character '0x%02x' in the value\r\n", - Digit )); - Status = EFI_INVALID_PARAMETER; - break; - } - } - - // - // Return the value - // - *pValue = Value; - - // - // Return the conversion status - // - return Status; -} - - -/** - Process the TFTP request - - @param [in] pTftpServer The TFTP server control structure address. - @param [in] pContext Connection context structure address - -**/ -VOID -TftpProcessRequest ( - IN TSDT_TFTP_SERVER * pTftpServer, - IN TSDT_CONNECTION_CONTEXT * pContext - ) -{ - BOOLEAN bCloseContext; - BOOLEAN bIgnorePacket; - UINT16 BlockNumber; - UINT16 Opcode; - UINT8 * pBuffer; - UINT8 * pEnd; - UINT8 * pFileName; - UINT8 * pMode; - UINT8 * pOption; - EFI_STATUS Status; - - DBG_ENTER ( ); - - // - // Get the opcode - // - pBuffer = &pTftpServer->RxBuffer[0]; - Opcode = HTONS ( *(UINT16 *)&pBuffer[0]); -Print ( L"TFTP Opcode: 0x%08x\r\n", Opcode ); - - // - // Validate the parameters - // - bCloseContext = FALSE; - bIgnorePacket = FALSE; - switch ( Opcode ) { - default: - DEBUG (( DEBUG_TFTP_REQUEST, - "ERROR - Unknown TFTP opcode: %d\r\n", - Opcode )); - bIgnorePacket = TRUE; - break; - - case TFTP_OP_READ_REQUEST: - break; - - case TFTP_OP_DATA: - if ( NULL == pContext ) { - DEBUG (( DEBUG_ERROR, - "ERROR - File not open for %d.%d.%d.%d:%d\r\n", - (UINT8)pTftpServer->RemoteAddress.sin_addr.s_addr, - (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 8 ), - (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 16 ), - (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 24 ), - htons ( pTftpServer->RemoteAddress.sin_port ))); - bIgnorePacket = TRUE; - break; - } - if ( pContext->bExpectAck ) { - DEBUG (( DEBUG_ERROR, - "ERROR - Expecting ACKs not data for pContext 0x%08x\r\n", - pContext )); - bIgnorePacket = TRUE; - break; - } - if ( pTftpServer->RxBytes > (ssize_t)( pContext->BlockSize + 2 + 2 )) - { - DEBUG (( DEBUG_ERROR, - "ERROR - Receive data length of %d > %d bytes (maximum block size) for pContext 0x%08x\r\n", - pTftpServer->RxBytes - 2 - 2, - pContext->BlockSize, - pContext )); - bIgnorePacket = TRUE; - break; - } - break; - - case TFTP_OP_ACK: - if ( NULL == pContext ) { - DEBUG (( DEBUG_ERROR, - "ERROR - File not open for %d.%d.%d.%d:%d\r\n", - (UINT8)pTftpServer->RemoteAddress.sin_addr.s_addr, - (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 8 ), - (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 16 ), - (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 24 ), - htons ( pTftpServer->RemoteAddress.sin_port ))); - bIgnorePacket = TRUE; - } - if ( !pContext->bExpectAck ) { - DEBUG (( DEBUG_ERROR, - "ERROR - Expecting data not ACKs for pContext 0x%08x\r\n", - pContext )); - bIgnorePacket = TRUE; - break; - } - break; - - case TFTP_OP_ERROR: - if ( NULL == pContext ) { - DEBUG (( DEBUG_ERROR, - "ERROR - File not open for %d.%d.%d.%d:%d\r\n", - (UINT8)pTftpServer->RemoteAddress.sin_addr.s_addr, - (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 8 ), - (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 16 ), - (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 24 ), - htons ( pTftpServer->RemoteAddress.sin_port ))); - bIgnorePacket = TRUE; - } - break; - } - if ( !bIgnorePacket ) { - // - // Process the request - // - switch ( Opcode ) { - default: - DEBUG (( DEBUG_TFTP_REQUEST, - "ERROR - Unable to process TFTP opcode: %d\r\n", - Opcode )); - break; - - case TFTP_OP_READ_REQUEST: - - // - // Close the context if necessary - // - if ( NULL != pContext ) { - ContextRemove ( pTftpServer, pContext ); - } - - // - // Create the connection context - // - pContext = ContextAdd ( pTftpServer ); - if ( NULL == pContext ) { - break; - } - - // - // Locate the mode - // - pFileName = &pBuffer[2]; - pEnd = &pBuffer[pTftpServer->RxBytes]; - pMode = pFileName; - while (( pEnd > pMode ) && ( 0 != *pMode )) { - pMode += 1; - } - if ( pEnd <= pMode ) { - // - // Mode not found - // - DEBUG (( DEBUG_ERROR | DEBUG_RX, - "ERROR - File mode not found\r\n" )); - // - // Tell the client of the error - // - TftpSendError ( pTftpServer, - pContext, - 0, - (UINT8 *)"File open mode not found" ); - break; - } - pMode += 1; - DEBUG (( DEBUG_TFTP_REQUEST, - "TFTP - FileName: %a\n", - pFileName )); - - // - // Locate the options - // - pOption = pMode; - while (( pEnd > pOption ) && ( 0 != *pOption )) { - pOption += 1; - } - if ( pEnd <= pOption ) { - // - // End of mode not found - // - DEBUG (( DEBUG_ERROR | DEBUG_RX, - "ERROR - File mode not valid\r\n" )); - // - // Tell the client of the error - // - TftpSendError ( pTftpServer, - pContext, - 0, - (UINT8 *)"File open mode not valid" ); - break; - } - pOption += 1; - DEBUG (( DEBUG_TFTP_REQUEST, - "TFTP - Mode: %a\r\n", - pMode )); - - // - // Verify the mode is supported - // - if ( 0 != stricmp ((char *)pMode, "octet" )) { - // - // File access mode not supported - // - DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST, - "ERROR - File mode %a not supported\r\n", - pMode )); - - // - // Tell the client of the error - // - TftpSendError ( pTftpServer, - pContext, - 0, - (UINT8 *)"File open mode not supported" ); - break; - } - - // - // Open the file, close the context on error - // -// TODO: Remove the following line -pContext->File = (EFI_HANDLE)1; - - // - // Determine the file length - // -//fstat - - // - // Process the options - // - TftpOptions ( pContext, pOption, pEnd ); - - // - // Read in the first portion of the file - // - - // - // Send the first block - // - pContext->bExpectAck = TRUE; - if ( 2 < pContext->TxBytes ) { - // - // Send the OACK - // - Status = TftpTxPacket ( pTftpServer, pContext ); - } - else { - // - // Send the first block of data - // - Status = TftpSendNextBlock ( pTftpServer, pContext ); - } - break; - - case TFTP_OP_ACK: - // - // Get the block number that is being ACKed - // - BlockNumber = pTftpServer->RxBuffer[2]; - BlockNumber <<= 8; - BlockNumber |= pTftpServer->RxBuffer[3]; - - // - // Determine if this is the correct ACK - // - DEBUG (( DEBUG_TFTP_ACK, - "ACK for block 0x%04x received\r\n", - BlockNumber )); - if (( !pContext->bExpectAck ) - || ( BlockNumber != pContext->AckNext )) - { - DEBUG (( DEBUG_WARN | DEBUG_TFTP_ACK, - "WARNING - Expecting ACK 0x%0x4 not received ACK 0x%08x\r\n", - pContext->AckNext, - BlockNumber )); - } - else { - // - // Process the expected ACK - // - if ( pContext->bEofSent ) { - bCloseContext = TRUE; - } - else { - // - // Set the next expected ACK - // - pContext->AckNext += 1; - - // - // Send the next packet of data - // - Status = TftpSendNextBlock ( pTftpServer, pContext ); - } - } - break; - } - } - - // - // Determine if the context should be closed - // - if ( bCloseContext ) { - ContextRemove ( pTftpServer, pContext ); - } - - DBG_EXIT ( ); -} - - -/** - Build and send an error packet - - @param [in] pTftpServer The TFTP server control structure address. - @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 -TftpSendError ( - IN TSDT_TFTP_SERVER * pTftpServer, - IN TSDT_CONNECTION_CONTEXT * pContext, - IN UINT16 Error, - IN UINT8 * pError - ) -{ - UINT8 Character; - UINT8 * pBuffer; - EFI_STATUS Status; - - DBG_ENTER ( ); - - // - // Build the error packet - // - pBuffer = &pContext->TxBuffer[0]; - pBuffer[0] = 0; - pBuffer[1] = TFTP_OP_ERROR; - pBuffer[2] = (UINT8)( Error >> 8 ); - pBuffer[3] = (UINT8)Error; - - // - // Copy the zero terminated string into the buffer - // - pBuffer += 4; - do { - Character = *pError++; - *pBuffer++ = Character; - } while ( 0 != Character ); - - // - // Send the error message - // - pContext->TxBytes = pBuffer - &pContext->TxBuffer[0]; - Status = TftpTxPacket ( pTftpServer, pContext ); - - // - // Return the operation status - // - DBG_EXIT_STATUS ( Status ); - return Status; -} - - -/** - Send the next block of file system data - - @param [in] pTftpServer The TFTP server control structure address. - @param [in] pContext The context structure address. - - @retval EFI_SUCCESS Message processed successfully - -**/ -EFI_STATUS -TftpSendNextBlock ( - IN TSDT_TFTP_SERVER * pTftpServer, - IN TSDT_CONNECTION_CONTEXT * pContext - ) -{ - ssize_t LengthInBytes; - UINT8 * pBuffer; - EFI_STATUS Status; - - // - // Determine how much data needs to be sent - // - LengthInBytes = pContext->BlockSize; - if (( pContext->LengthInBytes < TFTP_MAX_BLOCK_SIZE ) - || ( LengthInBytes > (ssize_t)pContext->LengthInBytes )) { - LengthInBytes = (ssize_t)pContext->LengthInBytes; - pContext->bEofSent = TRUE; - } - - // - // Set the TFTP opcode and block number - // - pBuffer = &pContext->TxBuffer[0]; - *pBuffer++ = 0; - *pBuffer++ = TFTP_OP_DATA; - *pBuffer++ = (UINT8)( pContext->AckNext >> 8 ); - *pBuffer++ = (UINT8)pContext->AckNext; - - // - // Copy the file data into the transmit buffer - // - pContext->TxBytes = 2 + 2 + LengthInBytes; - if ( 0 < LengthInBytes ) { - CopyMem ( &pBuffer, - pContext->pBuffer, - LengthInBytes ); - } - - // - // Send the next block - // - Status = TftpTxPacket ( pTftpServer, pContext ); - - // - // Return the operation status - // - return Status; -} - - -/** - Create the port for the TFTP server - - This routine polls the network layer to create the TFTP port for the - TFTP server. More than one attempt may be necessary since it may take - some time to get the IP address and initialize the upper layers of - the network stack. - - @param [in] pTftpServer The TFTP server control structure address. - -**/ -VOID -TftpServerTimer ( - IN TSDT_TFTP_SERVER * pTftpServer - ) -{ - UINT16 TftpPort; - int SocketStatus; - EFI_STATUS Status; - - DEBUG (( DEBUG_SERVER_TIMER, "Entering TftpServerTimer\r\n" )); - - // - // Open the TFTP port on the server - // - do { - do { - // - // Wait for a while - // - Status = gBS->CheckEvent ( pTftpServer->TimerEvent ); - } while ( EFI_SUCCESS != Status ); - - // - // Attempt to create the socket for the TFTP server - // - pTftpServer->TftpPort.events = POLLRDNORM | POLLHUP; - pTftpServer->TftpPort.revents = 0; - pTftpServer->TftpPort.fd = socket ( AF_INET, - SOCK_DGRAM, - IPPROTO_UDP ); - if ( -1 != pTftpServer->TftpPort.fd ) - { - // - // Set the socket address - // - ZeroMem ( &pTftpServer->TftpServerAddress, - sizeof ( pTftpServer->TftpServerAddress )); - TftpPort = 69; - DEBUG (( DEBUG_TFTP_PORT, - "TFTP Port: %d\r\n", - TftpPort )); - pTftpServer->TftpServerAddress.sin_len = sizeof ( pTftpServer->TftpServerAddress ); - pTftpServer->TftpServerAddress.sin_family = AF_INET; - pTftpServer->TftpServerAddress.sin_addr.s_addr = INADDR_ANY; - pTftpServer->TftpServerAddress.sin_port = htons ( TftpPort ); - - // - // Bind the socket to the TFTP port - // - SocketStatus = bind ( pTftpServer->TftpPort.fd, - (struct sockaddr *) &pTftpServer->TftpServerAddress, - pTftpServer->TftpServerAddress.sin_len ); - if ( -1 != SocketStatus ) { - DEBUG (( DEBUG_TFTP_PORT, - "0x%08x: Socket bound to port %d\r\n", - pTftpServer->TftpPort.fd, - TftpPort )); - } - - // - // Release the socket if necessary - // - if ( -1 == SocketStatus ) { - close ( pTftpServer->TftpPort.fd ); - pTftpServer->TftpPort.fd = -1; - } - } - - // - // Wait until the socket is open - // - }while ( -1 == pTftpServer->TftpPort.fd ); - - DEBUG (( DEBUG_SERVER_TIMER, "Exiting TftpServerTimer\r\n" )); -} - - -/** - Start the TFTP server port creation timer - - @param [in] pTftpServer The TFTP server control structure address. - - @retval EFI_SUCCESS The timer was successfully started. - @retval EFI_ALREADY_STARTED The timer is already running. - @retval Other The timer failed to start. - -**/ -EFI_STATUS -TftpServerTimerStart ( - IN TSDT_TFTP_SERVER * pTftpServer - ) -{ - EFI_STATUS Status; - UINT64 TriggerTime; - - DBG_ENTER ( ); - - // - // Assume the timer is already running - // - Status = EFI_ALREADY_STARTED; - if ( !pTftpServer->bTimerRunning ) { - // - // Compute the poll interval - // - TriggerTime = TFTP_PORT_POLL_DELAY * ( 1000 * 10 ); - Status = gBS->SetTimer ( pTftpServer->TimerEvent, - TimerPeriodic, - TriggerTime ); - if ( !EFI_ERROR ( Status )) { - DEBUG (( DEBUG_TFTP_PORT, "TFTP port timer started\r\n" )); - - // - // Mark the timer running - // - pTftpServer->bTimerRunning = TRUE; - } - else { - DEBUG (( DEBUG_ERROR | DEBUG_TFTP_PORT, - "ERROR - Failed to start TFTP port timer, Status: %r\r\n", - Status )); - } - } - - // - // Return the operation status - // - DBG_EXIT_STATUS ( Status ); - return Status; -} - - -/** - Stop the TFTP server port creation timer - - @param [in] pTftpServer The TFTP server control structure address. - - @retval EFI_SUCCESS The TFTP port timer is stopped - @retval Other Failed to stop the TFTP port timer - -**/ -EFI_STATUS -TftpServerTimerStop ( - IN TSDT_TFTP_SERVER * pTftpServer - ) -{ - EFI_STATUS Status; - - DBG_ENTER ( ); - - // - // Assume the timer is stopped - // - Status = EFI_SUCCESS; - if ( pTftpServer->bTimerRunning ) { - // - // Stop the port creation polling - // - Status = gBS->SetTimer ( pTftpServer->TimerEvent, - TimerCancel, - 0 ); - if ( !EFI_ERROR ( Status )) { - DEBUG (( DEBUG_TFTP_PORT, "TFT[ port timer stopped\r\n" )); - - // - // Mark the timer stopped - // - pTftpServer->bTimerRunning = FALSE; - } - else { - DEBUG (( DEBUG_ERROR | DEBUG_TFTP_PORT, - "ERROR - Failed to stop TFT[ port timer, Status: %r\r\n", - Status )); - } - } - - // - // Return the operation status - // - DBG_EXIT_STATUS ( Status ); - return Status; -} - -/** - Send the next TFTP packet - - @param [in] pTftpServer The TFTP server control structure address. - @param [in] pContext The context structure address. - - @retval EFI_SUCCESS Message processed successfully - -**/ -EFI_STATUS -TftpTxPacket ( - IN TSDT_TFTP_SERVER * pTftpServer, - IN TSDT_CONNECTION_CONTEXT * pContext - ) -{ - ssize_t LengthInBytes; - EFI_STATUS Status; - - DBG_ENTER ( ); - - // - // Assume success - // - Status = EFI_SUCCESS; - - // - // Send the TFTP packet - // - DEBUG (( DEBUG_TX, - "0x%08x: pContext sending 0x%08x bytes\r\n", - pContext, - pContext->TxBytes )); - LengthInBytes = sendto ( pTftpServer->TftpPort.fd, - &pContext->TxBuffer[0], - pContext->TxBytes, - 0, - (struct sockaddr *)&pContext->RemoteAddress, - pContext->RemoteAddress.sin_len ); - if ( -1 == LengthInBytes ) { - DEBUG (( DEBUG_ERROR | DEBUG_TX, - "ERROR - Transmit failure, errno: 0x%08x\r\n", - errno )); - Status = EFI_DEVICE_ERROR; - } - - // - // Return the operation status - // - DBG_EXIT_STATUS ( Status ); - return Status; -} - - -/** - Entry point for the TFTP server application. - - @param [in] Argc The number of arguments - @param [in] Argv The argument value array - - @retval 0 The application exited normally. - @retval Other An error occurred. -**/ -int -main ( - IN int Argc, - IN char **Argv - ) -{ - TSDT_TFTP_SERVER * pTftpServer; - EFI_STATUS Status; - - // - // Create a timer event to start TFTP port - // - pTftpServer = &mTftpServer; - Status = gBS->CreateEvent ( EVT_TIMER, - TPL_TFTP_SERVER, - NULL, - NULL, - &pTftpServer->TimerEvent ); - if ( !EFI_ERROR ( Status )) { - Status = TftpServerTimerStart ( pTftpServer ); - if ( !EFI_ERROR ( Status )) { - // - // Run the TFTP server forever - // - for ( ; ; ) { - // - // Poll the network layer to create the TFTP port - // for the tftp server. More than one attempt may - // be necessary since it may take some time to get - // the IP address and initialize the upper layers - // of the network stack. - // - TftpServerTimer ( pTftpServer ); - - // - // Poll the socket for activity - // - do { - SocketPoll ( pTftpServer ); - } while ( -1 != pTftpServer->TftpPort.fd ); - -// -// TODO: Remove the following test code -// Exit when the network connection is broken -// -break; - } - - // - // Done with the timer event - // - TftpServerTimerStop ( pTftpServer ); - Status = gBS->CloseEvent ( pTftpServer->TimerEvent ); - } - } - - // - // Return the final status - // - DBG_EXIT_STATUS ( Status ); - return Status; -} +/*++
+ This file contains an 'Intel UEFI Application' and is
+ licensed for Intel CPUs and chipsets under the terms of your
+ license agreement with Intel or your vendor. This file may
+ be modified by the user, subject to additional terms of the
+ license agreement
+--*/
+/*++
+
+Copyright (c) 2011 Intel Corporation. All rights reserved
+This software and associated documentation (if any) is furnished
+under a license and may only be used or copied in accordance
+with the terms of the license. Except as permitted by such
+license, no part of this software or documentation may be
+reproduced, stored in a retrieval system, or transmitted in any
+form or by any means without the express written consent of
+Intel Corporation.
+
+--*/
+
+/** @file
+ This is a simple TFTP server application
+
+**/
+
+#include <TftpServer.h>
+
+TSDT_TFTP_SERVER mTftpServer; ///< TFTP server's control structure
+
+
+/**
+ Add a connection context to the list of connection contexts.
+
+ @param [in] pTftpServer The TFTP server control structure address.
+
+ @retval Context structure address, NULL if allocation fails
+
+**/
+TSDT_CONNECTION_CONTEXT *
+ContextAdd (
+ IN TSDT_TFTP_SERVER * pTftpServer
+ )
+{
+ size_t LengthInBytes;
+ TSDT_CONNECTION_CONTEXT * pContext;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Use for/break instead of goto
+ //
+ for ( ; ; ) {
+ //
+ // Allocate a new context
+ //
+ LengthInBytes = sizeof ( *pContext );
+ Status = gBS->AllocatePool ( EfiRuntimeServicesData,
+ LengthInBytes,
+ (VOID **)&pContext );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR | DEBUG_POOL,
+ "ERROR - Failed to allocate the context, Status: %r\r\n",
+ Status ));
+ pContext = NULL;
+ break;
+ }
+
+ //
+ // Initialize the context
+ //
+ ZeroMem ( pContext, LengthInBytes );
+ CopyMem ( &pContext->RemoteAddress,
+ &pTftpServer->RemoteAddress,
+ sizeof ( pContext->RemoteAddress ));
+ pContext->BlockSize = TFTP_MAX_BLOCK_SIZE;
+ pContext->pBuffer = &pContext->FileData[0];
+ pContext->pEnd = &pContext->pBuffer[sizeof ( pContext->pBuffer )];
+ pContext->MaxTransferSize = 0;
+ pContext->MaxTransferSize -= 1;
+
+ //
+ // Display the new context
+ //
+ DEBUG (( DEBUG_PORT_WORK | DEBUG_INFO,
+ "0x%08x: Context for %d.%d.%d.%d:%d\r\n",
+ pContext,
+ (UINT8)pContext->RemoteAddress.sin_addr.s_addr,
+ (UINT8)( pContext->RemoteAddress.sin_addr.s_addr >> 8 ),
+ (UINT8)( pContext->RemoteAddress.sin_addr.s_addr >> 16 ),
+ (UINT8)( pContext->RemoteAddress.sin_addr.s_addr >> 24 ),
+ htons ( pContext->RemoteAddress.sin_port )));
+
+ //
+ // Add the context to the context list
+ //
+ pContext->pNext = pTftpServer->pContextList;
+ pTftpServer->pContextList = pContext;
+
+ //
+ // All done
+ //
+ break;
+ }
+
+ //
+ // Return the connection context
+ //
+ DBG_EXIT_STATUS ( pContext );
+ return pContext;
+}
+
+
+/**
+ Locate a remote connection context.
+
+ @param [in] pTftpServer The TFTP server control structure address.
+
+ @param [in] pIpAddress The start of the remote IP address in network order
+
+ @param [in] Port The remote port number
+
+ @retval Context structure address, NULL if not found
+
+**/
+TSDT_CONNECTION_CONTEXT *
+ContextFind (
+ IN TSDT_TFTP_SERVER * pTftpServer
+ )
+{
+ TSDT_CONNECTION_CONTEXT * pContext;
+
+ DBG_ENTER ( );
+
+ //
+ // Walk the list of connection contexts
+ //
+ pContext = pTftpServer->pContextList;
+ while ( NULL != pContext ) {
+ //
+ // Attempt to locate the remote network connection
+ //
+ if (( pTftpServer->RemoteAddress.sin_addr.s_addr == pContext->RemoteAddress.sin_addr.s_addr )
+ && ( pTftpServer->RemoteAddress.sin_port == pContext->RemoteAddress.sin_port )) {
+ //
+ // The connection was found
+ //
+ DEBUG (( DEBUG_TFTP_REQUEST,
+ "0x%08x: pContext found\r\n",
+ pContext ));
+ break;
+ }
+
+ //
+ // Set the next context
+ //
+ pContext = pContext->pNext;
+ }
+
+ //
+ // Return the connection context structure address
+ //
+ DBG_EXIT_HEX ( pContext );
+ return pContext;
+}
+
+
+/**
+ Remove a context from the list.
+
+ @param [in] pTftpServer The TFTP server control structure address.
+
+ @param [in] pContext The context structure address.
+
+**/
+VOID
+ContextRemove (
+ IN TSDT_TFTP_SERVER * pTftpServer,
+ IN TSDT_CONNECTION_CONTEXT * pContext
+ )
+{
+ TSDT_CONNECTION_CONTEXT * pNextContext;
+ TSDT_CONNECTION_CONTEXT * pPreviousContext;
+
+ DBG_ENTER ( );
+
+ //
+ // Attempt to locate the context in the list
+ //
+ pPreviousContext = NULL;
+ pNextContext = pTftpServer->pContextList;
+ while ( NULL != pNextContext ) {
+ //
+ // Determine if the context was found
+ //
+ if ( pNextContext == pContext ) {
+ //
+ // Remove the context from the list
+ //
+ if ( NULL == pPreviousContext ) {
+ pTftpServer->pContextList = pContext->pNext;
+ }
+ else {
+ pPreviousContext->pNext = pContext->pNext;
+ }
+ break;
+ }
+
+ //
+ // Set the next context
+ //
+ pPreviousContext = pNextContext;
+ pNextContext = pNextContext->pNext;
+ }
+
+ //
+ // Determine if the context was found
+ //
+ if ( NULL != pContext ) {
+ //
+ // Return the resources
+ //
+ gBS->FreePool ( pContext );
+ }
+
+ DBG_EXIT ( );
+}
+
+
+/**
+ Process the work for the sockets.
+
+ @param [in] pTftpServer The TFTP server control structure address.
+
+**/
+VOID
+PortWork (
+ IN TSDT_TFTP_SERVER * pTftpServer
+ )
+{
+ TSDT_CONNECTION_CONTEXT * pContext;
+ socklen_t RemoteAddressLength;
+
+ DBG_ENTER ( );
+
+ //
+ // Handle input events
+ //
+ if ( 0 != ( pTftpServer->TftpPort.revents & POLLRDNORM )) {
+ //
+ // Receive the message from the remote system
+ //
+ RemoteAddressLength = sizeof ( pTftpServer->RemoteAddress );
+ pTftpServer->RxBytes = recvfrom ( pTftpServer->TftpPort.fd,
+ &pTftpServer->RxBuffer[0],
+ sizeof ( pTftpServer->RxBuffer ),
+ 0,
+ (struct sockaddr *) &pTftpServer->RemoteAddress,
+ &RemoteAddressLength );
+ if ( -1 != pTftpServer->RxBytes ) {
+ pTftpServer->RemoteAddress.sin_len = (UINT8) RemoteAddressLength;
+ DEBUG (( DEBUG_TFTP_PORT,
+ "Received %d bytes from %d.%d.%d.%d:%d\r\n",
+ pTftpServer->RxBytes,
+ pTftpServer->RemoteAddress.sin_addr.s_addr & 0xff,
+ ( pTftpServer->RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,
+ ( pTftpServer->RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,
+ ( pTftpServer->RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,
+ htons ( pTftpServer->RemoteAddress.sin_port )));
+
+ //
+ // Lookup connection context using the remote system address and port
+ // to determine if an existing connection to this remote
+ // system exists
+ //
+ pContext = ContextFind ( pTftpServer );
+
+ //
+ // Process the received message
+ //
+ TftpProcessRequest ( pTftpServer, pContext );
+ }
+ else {
+ //
+ // Receive error on the TFTP server port
+ // Close the server socket
+ //
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed receive on TFTP server port, errno: 0x%08x\r\n",
+ errno ));
+ pTftpServer->TftpPort.revents |= POLLHUP;
+ }
+ }
+
+ //
+ // Handle the close event
+ //
+ if ( 0 != ( pTftpServer->TftpPort.revents & POLLHUP )) {
+ //
+ // Close the port
+ //
+ close ( pTftpServer->TftpPort.fd );
+ pTftpServer->TftpPort.fd = -1;
+ }
+
+ DBG_EXIT ( );
+}
+
+
+/**
+ Scan the list of sockets and process any pending work
+
+ @param [in] pTftpServer The TFTP server control structure address.
+
+**/
+VOID
+SocketPoll (
+ IN TSDT_TFTP_SERVER * pTftpServer
+ )
+{
+ int FDCount;
+
+ DEBUG (( DEBUG_SOCKET_POLL, "Entering SocketPoll\r\n" ));
+
+ //
+ // Determine if any ports are active
+ //
+ FDCount = poll ( &pTftpServer->TftpPort,
+ 1,
+ CLIENT_POLL_DELAY );
+ if ( -1 == FDCount ) {
+ DEBUG (( DEBUG_ERROR | DEBUG_SOCKET_POLL,
+ "ERROR - errno: %d\r\n",
+ errno ));
+ }
+
+ if ( 0 < FDCount ) {
+ //
+ // Process this port
+ //
+ PortWork ( pTftpServer );
+ pTftpServer->TftpPort.revents = 0;
+ }
+
+ DEBUG (( DEBUG_SOCKET_POLL, "Exiting SocketPoll\r\n" ));
+}
+
+
+/**
+ Convert a character to lower case
+
+ @param [in] Character The character to convert
+
+ @return The lower case equivalent of the character
+
+**/
+int
+tolower (
+ int Character
+ )
+{
+ //
+ // Determine if the character is upper case
+ //
+ if (( 'A' <= Character ) && ( 'Z' >= Character )) {
+ //
+ // Convert the character to lower caes
+ //
+ Character += 'a' - 'A';
+ }
+
+ //
+ // Return the converted character
+ //
+ return Character;
+}
+
+
+/**
+ Case independent string comparison
+
+ @param [in] pString1 Zero terminated string address
+ @param [in] pString2 Zero terminated string address
+
+ @return Returns the first character difference between string 1
+ and string 2.
+
+**/
+int
+stricmp (
+ char * pString1,
+ char * pString2
+ )
+{
+ int Char1;
+ int Char2;
+ int Difference;
+
+ //
+ // Walk the length of the strings
+ //
+ do {
+ //
+ // Get the next characters
+ //
+ Char1 = (UINT8)*pString1++;
+ Char2 = (UINT8)*pString2++;
+
+ //
+ // Convert them to lower case
+ //
+ Char1 = tolower ( Char1 );
+ Char2 = tolower ( Char2 );
+
+ //
+ // Done when the characters differ
+ //
+ Difference = Char1 - Char2;
+ if ( 0 != Difference ) {
+ break;
+ }
+
+ //
+ // Done at the end of the string
+ //
+ } while ( 0 != Char1 );
+
+ //
+ // Return the difference
+ //
+ return Difference;
+}
+
+
+/**
+ Get the next TFTP option
+
+ @param [in] pOption Address of a zero terminated option string
+ @param [in] pEnd End of buffer address
+ @param [in] ppNextOption Address to receive the address of the next
+ zero terminated option string
+
+ @retval EFI_SUCCESS Message processed successfully
+
+**/
+EFI_STATUS
+TftpOptionGet (
+ IN UINT8 * pOption,
+ IN UINT8 * pEnd,
+ IN UINT8 ** ppNextOption
+ )
+{
+ UINT8 * pNextOption;
+ EFI_STATUS Status;
+
+ //
+ // Locate the end of the option
+ //
+ pNextOption = pOption;
+ while (( pEnd > pNextOption ) && ( 0 != *pNextOption )) {
+ pNextOption += 1;
+ }
+ if ( pEnd <= pNextOption ) {
+ //
+ // Error - end of buffer reached
+ //
+ DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST,
+ "ERROR - Option without zero termination received!\r\n" ));
+ Status = EFI_INVALID_PARAMETER;
+ }
+ else {
+ //
+ // Zero terminated option found
+ //
+ pNextOption += 1;
+
+ //
+ // Display the zero terminated ASCII option string
+ //
+ DEBUG (( DEBUG_TFTP_REQUEST,
+ "Option: %a\r\n",
+ pOption ));
+ Status = EFI_SUCCESS;
+ }
+
+ //
+ // Return the next option address
+ //
+ *ppNextOption = pNextOption;
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Place an option value into the option acknowledgement
+
+ @param [in] pOack Option acknowledgement address
+ @param [in] Value Value to translate into ASCII decimal
+
+ @return Option acknowledgement address
+
+**/
+UINT8 *
+TftpOptionSet (
+ IN UINT8 * pOack,
+ IN UINT64 Value
+ )
+{
+ UINT64 NextValue;
+
+ //
+ // Determine the next value
+ //
+ NextValue = Value / 10;
+
+ //
+ // Supress leading zeros
+ //
+ if ( 0 != NextValue ) {
+ pOack = TftpOptionSet ( pOack, NextValue );
+ }
+
+ //
+ // Output this digit
+ //
+ *pOack++ = (UINT8)( Value - ( NextValue * 10 ) + '0' );
+
+ //
+ // Return the next option acknowledgement location
+ //
+ return pOack;
+}
+
+
+/**
+ Process the TFTP request
+
+ @param [in] pContext The context structure address.
+ @param [in] pOption Address of the first zero terminated option string
+ @param [in] pEnd End of buffer address
+
+**/
+VOID
+TftpOptions (
+ IN TSDT_CONNECTION_CONTEXT * pContext,
+ IN UINT8 * pOption,
+ IN UINT8 * pEnd
+ )
+{
+ UINT8 * pNextOption;
+ UINT8 * pOack;
+ UINT8 * pTemp;
+ UINT8 * pValue;
+ EFI_STATUS Status;
+ INT32 Value;
+
+ //
+ // Start the OACK packet
+ // Let the OACK handle the parsing errors
+ // See http://tools.ietf.org/html/rfc2347
+ //
+ pOack = &pContext->TxBuffer[0];
+ *pOack++ = 0;
+ *pOack++ = TFTP_OP_OACK;
+ pContext->TxBytes = 2;
+
+ //
+ // Walk the list of options
+ //
+ do {
+ //
+ // Get the next option, skip junk at end of message
+ //
+ Status = TftpOptionGet ( pOption, pEnd, &pNextOption );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Process the option
+ //
+
+ //
+ // blksize - See http://tools.ietf.org/html/rfc2348
+ //
+ pValue = pNextOption;
+ if ( 0 == stricmp ((char *)pOption, "blksize" )) {
+ //
+ // Get the value
+ //
+ Status = TftpOptionGet ( pValue, pEnd, &pNextOption );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Validate the block size, skip non-numeric block sizes
+ //
+ Status = TftpOptionValue ( pValue, &Value );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Propose a smaller block size if necessary
+ //
+ if ( Value > TFTP_MAX_BLOCK_SIZE ) {
+ Value = TFTP_MAX_BLOCK_SIZE;
+ }
+
+ //
+ // Set the new block size
+ //
+ pContext->BlockSize = Value;
+ DEBUG (( DEBUG_TFTP_REQUEST,
+ "Using block size of %d bytes\r\n",
+ pContext->BlockSize ));
+
+ //
+ // Update the OACK
+ //
+ pTemp = pOack;
+ *pOack++ = 'b';
+ *pOack++ = 'l';
+ *pOack++ = 'k';
+ *pOack++ = 's';
+ *pOack++ = 'i';
+ *pOack++ = 'z';
+ *pOack++ = 'e';
+ *pOack++ = 0;
+ pOack = TftpOptionSet ( pOack, pContext->BlockSize );
+ *pOack++ = 0;
+ pContext->TxBytes += pOack - pTemp;
+ }
+ }
+ }
+
+ //
+ // timeout - See http://tools.ietf.org/html/rfc2349
+ //
+ else if ( 0 == stricmp ((char *)pOption, "timeout" )) {
+ //
+ // Get the value
+ //
+ Status = TftpOptionGet ( pValue, pEnd, &pNextOption );
+ if ( !EFI_ERROR ( Status )) {
+ Status = TftpOptionValue ( pValue, &Value );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Set the timeout value
+ //
+ pContext->Timeout = Value;
+ DEBUG (( DEBUG_TFTP_REQUEST,
+ "Using timeout of %d seconds\r\n",
+ pContext->Timeout ));
+
+ //
+ // Update the OACK
+ //
+ pTemp = pOack;
+ *pOack++ = 't';
+ *pOack++ = 'i';
+ *pOack++ = 'm';
+ *pOack++ = 'e';
+ *pOack++ = 'o';
+ *pOack++ = 'u';
+ *pOack++ = 't';
+ *pOack++ = 0;
+ pOack = TftpOptionSet ( pOack, pContext->Timeout );
+ *pOack++ = 0;
+ pContext->TxBytes += pOack - pTemp;
+ }
+ }
+ }
+
+ //
+ // tsize - See http://tools.ietf.org/html/rfc2349
+ //
+ else if ( 0 == stricmp ((char *)pOption, "tsize" )) {
+ //
+ // Get the value
+ //
+ Status = TftpOptionGet ( pValue, pEnd, &pNextOption );
+ if ( !EFI_ERROR ( Status )) {
+ Status = TftpOptionValue ( pValue, &Value );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Return the file size
+ //
+ DEBUG (( DEBUG_TFTP_REQUEST,
+ "Returning file size of %Ld bytes\r\n",
+ pContext->LengthInBytes ));
+
+ //
+ // Update the OACK
+ //
+ pTemp = pOack;
+ *pOack++ = 't';
+ *pOack++ = 's';
+ *pOack++ = 'i';
+ *pOack++ = 'z';
+ *pOack++ = 'e';
+ *pOack++ = 0;
+ pOack = TftpOptionSet ( pOack, pContext->LengthInBytes );
+ *pOack++ = 0;
+ pContext->TxBytes += pOack - pTemp;
+ }
+ }
+ }
+ else {
+ //
+ // Unknown option - Ignore it
+ //
+ DEBUG (( DEBUG_WARN | DEBUG_TFTP_REQUEST,
+ "WARNING - Skipping unknown option: %a\r\n",
+ pOption ));
+ }
+ }
+
+ //
+ // Set the next option
+ //
+ pOption = pNextOption;
+ } while ( pEnd > pOption );
+}
+
+
+/**
+ 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
+ )
+{
+ UINT8 Digit;
+ EFI_STATUS Status;
+ INT32 Value;
+
+ //
+ // Assume success
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Walk the characters in the option
+ //
+ Value = 0;
+ while ( 0 != *pOption ) {
+ //
+ // Convert the next digit to binary
+ //
+ Digit = *pOption++;
+ if (( '0' <= Digit ) && ( '9' >= Digit )) {
+ Value *= 10;
+ Value += Digit - '0';
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST,
+ "ERROR - Invalid character '0x%02x' in the value\r\n",
+ Digit ));
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+ }
+
+ //
+ // Return the value
+ //
+ *pValue = Value;
+
+ //
+ // Return the conversion status
+ //
+ return Status;
+}
+
+
+/**
+ Process the TFTP request
+
+ @param [in] pTftpServer The TFTP server control structure address.
+ @param [in] pContext Connection context structure address
+
+**/
+VOID
+TftpProcessRequest (
+ IN TSDT_TFTP_SERVER * pTftpServer,
+ IN TSDT_CONNECTION_CONTEXT * pContext
+ )
+{
+ BOOLEAN bCloseContext;
+ BOOLEAN bIgnorePacket;
+ UINT16 BlockNumber;
+ UINT16 Opcode;
+ UINT8 * pBuffer;
+ UINT8 * pEnd;
+ UINT8 * pFileName;
+ UINT8 * pMode;
+ UINT8 * pOption;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Get the opcode
+ //
+ pBuffer = &pTftpServer->RxBuffer[0];
+ Opcode = HTONS ( *(UINT16 *)&pBuffer[0]);
+Print ( L"TFTP Opcode: 0x%08x\r\n", Opcode );
+
+ //
+ // Validate the parameters
+ //
+ bCloseContext = FALSE;
+ bIgnorePacket = FALSE;
+ switch ( Opcode ) {
+ default:
+ DEBUG (( DEBUG_TFTP_REQUEST,
+ "ERROR - Unknown TFTP opcode: %d\r\n",
+ Opcode ));
+ bIgnorePacket = TRUE;
+ break;
+
+ case TFTP_OP_READ_REQUEST:
+ break;
+
+ case TFTP_OP_DATA:
+ if ( NULL == pContext ) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - File not open for %d.%d.%d.%d:%d\r\n",
+ (UINT8)pTftpServer->RemoteAddress.sin_addr.s_addr,
+ (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 8 ),
+ (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 16 ),
+ (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 24 ),
+ htons ( pTftpServer->RemoteAddress.sin_port )));
+ bIgnorePacket = TRUE;
+ break;
+ }
+ if ( pContext->bExpectAck ) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Expecting ACKs not data for pContext 0x%08x\r\n",
+ pContext ));
+ bIgnorePacket = TRUE;
+ break;
+ }
+ if ( pTftpServer->RxBytes > (ssize_t)( pContext->BlockSize + 2 + 2 ))
+ {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Receive data length of %d > %d bytes (maximum block size) for pContext 0x%08x\r\n",
+ pTftpServer->RxBytes - 2 - 2,
+ pContext->BlockSize,
+ pContext ));
+ bIgnorePacket = TRUE;
+ break;
+ }
+ break;
+
+ case TFTP_OP_ACK:
+ if ( NULL == pContext ) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - File not open for %d.%d.%d.%d:%d\r\n",
+ (UINT8)pTftpServer->RemoteAddress.sin_addr.s_addr,
+ (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 8 ),
+ (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 16 ),
+ (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 24 ),
+ htons ( pTftpServer->RemoteAddress.sin_port )));
+ bIgnorePacket = TRUE;
+ }
+ if ( !pContext->bExpectAck ) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Expecting data not ACKs for pContext 0x%08x\r\n",
+ pContext ));
+ bIgnorePacket = TRUE;
+ break;
+ }
+ break;
+
+ case TFTP_OP_ERROR:
+ if ( NULL == pContext ) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - File not open for %d.%d.%d.%d:%d\r\n",
+ (UINT8)pTftpServer->RemoteAddress.sin_addr.s_addr,
+ (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 8 ),
+ (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 16 ),
+ (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 24 ),
+ htons ( pTftpServer->RemoteAddress.sin_port )));
+ bIgnorePacket = TRUE;
+ }
+ break;
+ }
+ if ( !bIgnorePacket ) {
+ //
+ // Process the request
+ //
+ switch ( Opcode ) {
+ default:
+ DEBUG (( DEBUG_TFTP_REQUEST,
+ "ERROR - Unable to process TFTP opcode: %d\r\n",
+ Opcode ));
+ break;
+
+ case TFTP_OP_READ_REQUEST:
+
+ //
+ // Close the context if necessary
+ //
+ if ( NULL != pContext ) {
+ ContextRemove ( pTftpServer, pContext );
+ }
+
+ //
+ // Create the connection context
+ //
+ pContext = ContextAdd ( pTftpServer );
+ if ( NULL == pContext ) {
+ break;
+ }
+
+ //
+ // Locate the mode
+ //
+ pFileName = &pBuffer[2];
+ pEnd = &pBuffer[pTftpServer->RxBytes];
+ pMode = pFileName;
+ while (( pEnd > pMode ) && ( 0 != *pMode )) {
+ pMode += 1;
+ }
+ if ( pEnd <= pMode ) {
+ //
+ // Mode not found
+ //
+ DEBUG (( DEBUG_ERROR | DEBUG_RX,
+ "ERROR - File mode not found\r\n" ));
+ //
+ // Tell the client of the error
+ //
+ TftpSendError ( pTftpServer,
+ pContext,
+ 0,
+ (UINT8 *)"File open mode not found" );
+ break;
+ }
+ pMode += 1;
+ DEBUG (( DEBUG_TFTP_REQUEST,
+ "TFTP - FileName: %a\n",
+ pFileName ));
+
+ //
+ // Locate the options
+ //
+ pOption = pMode;
+ while (( pEnd > pOption ) && ( 0 != *pOption )) {
+ pOption += 1;
+ }
+ if ( pEnd <= pOption ) {
+ //
+ // End of mode not found
+ //
+ DEBUG (( DEBUG_ERROR | DEBUG_RX,
+ "ERROR - File mode not valid\r\n" ));
+ //
+ // Tell the client of the error
+ //
+ TftpSendError ( pTftpServer,
+ pContext,
+ 0,
+ (UINT8 *)"File open mode not valid" );
+ break;
+ }
+ pOption += 1;
+ DEBUG (( DEBUG_TFTP_REQUEST,
+ "TFTP - Mode: %a\r\n",
+ pMode ));
+
+ //
+ // Verify the mode is supported
+ //
+ if ( 0 != stricmp ((char *)pMode, "octet" )) {
+ //
+ // File access mode not supported
+ //
+ DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST,
+ "ERROR - File mode %a not supported\r\n",
+ pMode ));
+
+ //
+ // Tell the client of the error
+ //
+ TftpSendError ( pTftpServer,
+ pContext,
+ 0,
+ (UINT8 *)"File open mode not supported" );
+ break;
+ }
+
+ //
+ // Open the file, close the context on error
+ //
+// TODO: Remove the following line
+pContext->File = (EFI_HANDLE)1;
+
+ //
+ // Determine the file length
+ //
+//fstat
+
+ //
+ // Process the options
+ //
+ TftpOptions ( pContext, pOption, pEnd );
+
+ //
+ // Read in the first portion of the file
+ //
+
+ //
+ // Send the first block
+ //
+ pContext->bExpectAck = TRUE;
+ if ( 2 < pContext->TxBytes ) {
+ //
+ // Send the OACK
+ //
+ Status = TftpTxPacket ( pTftpServer, pContext );
+ }
+ else {
+ //
+ // Send the first block of data
+ //
+ Status = TftpSendNextBlock ( pTftpServer, pContext );
+ }
+ break;
+
+ case TFTP_OP_ACK:
+ //
+ // Get the block number that is being ACKed
+ //
+ BlockNumber = pTftpServer->RxBuffer[2];
+ BlockNumber <<= 8;
+ BlockNumber |= pTftpServer->RxBuffer[3];
+
+ //
+ // Determine if this is the correct ACK
+ //
+ DEBUG (( DEBUG_TFTP_ACK,
+ "ACK for block 0x%04x received\r\n",
+ BlockNumber ));
+ if (( !pContext->bExpectAck )
+ || ( BlockNumber != pContext->AckNext ))
+ {
+ DEBUG (( DEBUG_WARN | DEBUG_TFTP_ACK,
+ "WARNING - Expecting ACK 0x%0x4 not received ACK 0x%08x\r\n",
+ pContext->AckNext,
+ BlockNumber ));
+ }
+ else {
+ //
+ // Process the expected ACK
+ //
+ if ( pContext->bEofSent ) {
+ bCloseContext = TRUE;
+ }
+ else {
+ //
+ // Set the next expected ACK
+ //
+ pContext->AckNext += 1;
+
+ //
+ // Send the next packet of data
+ //
+ Status = TftpSendNextBlock ( pTftpServer, pContext );
+ }
+ }
+ break;
+ }
+ }
+
+ //
+ // Determine if the context should be closed
+ //
+ if ( bCloseContext ) {
+ ContextRemove ( pTftpServer, pContext );
+ }
+
+ DBG_EXIT ( );
+}
+
+
+/**
+ Build and send an error packet
+
+ @param [in] pTftpServer The TFTP server control structure address.
+ @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
+TftpSendError (
+ IN TSDT_TFTP_SERVER * pTftpServer,
+ IN TSDT_CONNECTION_CONTEXT * pContext,
+ IN UINT16 Error,
+ IN UINT8 * pError
+ )
+{
+ UINT8 Character;
+ UINT8 * pBuffer;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Build the error packet
+ //
+ pBuffer = &pContext->TxBuffer[0];
+ pBuffer[0] = 0;
+ pBuffer[1] = TFTP_OP_ERROR;
+ pBuffer[2] = (UINT8)( Error >> 8 );
+ pBuffer[3] = (UINT8)Error;
+
+ //
+ // Copy the zero terminated string into the buffer
+ //
+ pBuffer += 4;
+ do {
+ Character = *pError++;
+ *pBuffer++ = Character;
+ } while ( 0 != Character );
+
+ //
+ // Send the error message
+ //
+ pContext->TxBytes = pBuffer - &pContext->TxBuffer[0];
+ Status = TftpTxPacket ( pTftpServer, pContext );
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Send the next block of file system data
+
+ @param [in] pTftpServer The TFTP server control structure address.
+ @param [in] pContext The context structure address.
+
+ @retval EFI_SUCCESS Message processed successfully
+
+**/
+EFI_STATUS
+TftpSendNextBlock (
+ IN TSDT_TFTP_SERVER * pTftpServer,
+ IN TSDT_CONNECTION_CONTEXT * pContext
+ )
+{
+ ssize_t LengthInBytes;
+ UINT8 * pBuffer;
+ EFI_STATUS Status;
+
+ //
+ // Determine how much data needs to be sent
+ //
+ LengthInBytes = pContext->BlockSize;
+ if (( pContext->LengthInBytes < TFTP_MAX_BLOCK_SIZE )
+ || ( LengthInBytes > (ssize_t)pContext->LengthInBytes )) {
+ LengthInBytes = (ssize_t)pContext->LengthInBytes;
+ pContext->bEofSent = TRUE;
+ }
+
+ //
+ // Set the TFTP opcode and block number
+ //
+ pBuffer = &pContext->TxBuffer[0];
+ *pBuffer++ = 0;
+ *pBuffer++ = TFTP_OP_DATA;
+ *pBuffer++ = (UINT8)( pContext->AckNext >> 8 );
+ *pBuffer++ = (UINT8)pContext->AckNext;
+
+ //
+ // Copy the file data into the transmit buffer
+ //
+ pContext->TxBytes = 2 + 2 + LengthInBytes;
+ if ( 0 < LengthInBytes ) {
+ CopyMem ( &pBuffer,
+ pContext->pBuffer,
+ LengthInBytes );
+ }
+
+ //
+ // Send the next block
+ //
+ Status = TftpTxPacket ( pTftpServer, pContext );
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Create the port for the TFTP server
+
+ This routine polls the network layer to create the TFTP port for the
+ TFTP server. More than one attempt may be necessary since it may take
+ some time to get the IP address and initialize the upper layers of
+ the network stack.
+
+ @param [in] pTftpServer The TFTP server control structure address.
+
+**/
+VOID
+TftpServerTimer (
+ IN TSDT_TFTP_SERVER * pTftpServer
+ )
+{
+ UINT16 TftpPort;
+ int SocketStatus;
+ EFI_STATUS Status;
+
+ DEBUG (( DEBUG_SERVER_TIMER, "Entering TftpServerTimer\r\n" ));
+
+ //
+ // Open the TFTP port on the server
+ //
+ do {
+ do {
+ //
+ // Wait for a while
+ //
+ Status = gBS->CheckEvent ( pTftpServer->TimerEvent );
+ } while ( EFI_SUCCESS != Status );
+
+ //
+ // Attempt to create the socket for the TFTP server
+ //
+ pTftpServer->TftpPort.events = POLLRDNORM | POLLHUP;
+ pTftpServer->TftpPort.revents = 0;
+ pTftpServer->TftpPort.fd = socket ( AF_INET,
+ SOCK_DGRAM,
+ IPPROTO_UDP );
+ if ( -1 != pTftpServer->TftpPort.fd )
+ {
+ //
+ // Set the socket address
+ //
+ ZeroMem ( &pTftpServer->TftpServerAddress,
+ sizeof ( pTftpServer->TftpServerAddress ));
+ TftpPort = 69;
+ DEBUG (( DEBUG_TFTP_PORT,
+ "TFTP Port: %d\r\n",
+ TftpPort ));
+ pTftpServer->TftpServerAddress.sin_len = sizeof ( pTftpServer->TftpServerAddress );
+ pTftpServer->TftpServerAddress.sin_family = AF_INET;
+ pTftpServer->TftpServerAddress.sin_addr.s_addr = INADDR_ANY;
+ pTftpServer->TftpServerAddress.sin_port = htons ( TftpPort );
+
+ //
+ // Bind the socket to the TFTP port
+ //
+ SocketStatus = bind ( pTftpServer->TftpPort.fd,
+ (struct sockaddr *) &pTftpServer->TftpServerAddress,
+ pTftpServer->TftpServerAddress.sin_len );
+ if ( -1 != SocketStatus ) {
+ DEBUG (( DEBUG_TFTP_PORT,
+ "0x%08x: Socket bound to port %d\r\n",
+ pTftpServer->TftpPort.fd,
+ TftpPort ));
+ }
+
+ //
+ // Release the socket if necessary
+ //
+ if ( -1 == SocketStatus ) {
+ close ( pTftpServer->TftpPort.fd );
+ pTftpServer->TftpPort.fd = -1;
+ }
+ }
+
+ //
+ // Wait until the socket is open
+ //
+ }while ( -1 == pTftpServer->TftpPort.fd );
+
+ DEBUG (( DEBUG_SERVER_TIMER, "Exiting TftpServerTimer\r\n" ));
+}
+
+
+/**
+ Start the TFTP server port creation timer
+
+ @param [in] pTftpServer The TFTP server control structure address.
+
+ @retval EFI_SUCCESS The timer was successfully started.
+ @retval EFI_ALREADY_STARTED The timer is already running.
+ @retval Other The timer failed to start.
+
+**/
+EFI_STATUS
+TftpServerTimerStart (
+ IN TSDT_TFTP_SERVER * pTftpServer
+ )
+{
+ EFI_STATUS Status;
+ UINT64 TriggerTime;
+
+ DBG_ENTER ( );
+
+ //
+ // Assume the timer is already running
+ //
+ Status = EFI_ALREADY_STARTED;
+ if ( !pTftpServer->bTimerRunning ) {
+ //
+ // Compute the poll interval
+ //
+ TriggerTime = TFTP_PORT_POLL_DELAY * ( 1000 * 10 );
+ Status = gBS->SetTimer ( pTftpServer->TimerEvent,
+ TimerPeriodic,
+ TriggerTime );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_TFTP_PORT, "TFTP port timer started\r\n" ));
+
+ //
+ // Mark the timer running
+ //
+ pTftpServer->bTimerRunning = TRUE;
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_TFTP_PORT,
+ "ERROR - Failed to start TFTP port timer, Status: %r\r\n",
+ Status ));
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Stop the TFTP server port creation timer
+
+ @param [in] pTftpServer The TFTP server control structure address.
+
+ @retval EFI_SUCCESS The TFTP port timer is stopped
+ @retval Other Failed to stop the TFTP port timer
+
+**/
+EFI_STATUS
+TftpServerTimerStop (
+ IN TSDT_TFTP_SERVER * pTftpServer
+ )
+{
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Assume the timer is stopped
+ //
+ Status = EFI_SUCCESS;
+ if ( pTftpServer->bTimerRunning ) {
+ //
+ // Stop the port creation polling
+ //
+ Status = gBS->SetTimer ( pTftpServer->TimerEvent,
+ TimerCancel,
+ 0 );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_TFTP_PORT, "TFT[ port timer stopped\r\n" ));
+
+ //
+ // Mark the timer stopped
+ //
+ pTftpServer->bTimerRunning = FALSE;
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_TFTP_PORT,
+ "ERROR - Failed to stop TFT[ port timer, Status: %r\r\n",
+ Status ));
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+/**
+ Send the next TFTP packet
+
+ @param [in] pTftpServer The TFTP server control structure address.
+ @param [in] pContext The context structure address.
+
+ @retval EFI_SUCCESS Message processed successfully
+
+**/
+EFI_STATUS
+TftpTxPacket (
+ IN TSDT_TFTP_SERVER * pTftpServer,
+ IN TSDT_CONNECTION_CONTEXT * pContext
+ )
+{
+ ssize_t LengthInBytes;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Assume success
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Send the TFTP packet
+ //
+ DEBUG (( DEBUG_TX,
+ "0x%08x: pContext sending 0x%08x bytes\r\n",
+ pContext,
+ pContext->TxBytes ));
+ LengthInBytes = sendto ( pTftpServer->TftpPort.fd,
+ &pContext->TxBuffer[0],
+ pContext->TxBytes,
+ 0,
+ (struct sockaddr *)&pContext->RemoteAddress,
+ pContext->RemoteAddress.sin_len );
+ if ( -1 == LengthInBytes ) {
+ DEBUG (( DEBUG_ERROR | DEBUG_TX,
+ "ERROR - Transmit failure, errno: 0x%08x\r\n",
+ errno ));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Entry point for the TFTP server application.
+
+ @param [in] Argc The number of arguments
+ @param [in] Argv The argument value array
+
+ @retval 0 The application exited normally.
+ @retval Other An error occurred.
+**/
+int
+main (
+ IN int Argc,
+ IN char **Argv
+ )
+{
+ TSDT_TFTP_SERVER * pTftpServer;
+ EFI_STATUS Status;
+
+ //
+ // Create a timer event to start TFTP port
+ //
+ pTftpServer = &mTftpServer;
+ Status = gBS->CreateEvent ( EVT_TIMER,
+ TPL_TFTP_SERVER,
+ NULL,
+ NULL,
+ &pTftpServer->TimerEvent );
+ if ( !EFI_ERROR ( Status )) {
+ Status = TftpServerTimerStart ( pTftpServer );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Run the TFTP server forever
+ //
+ for ( ; ; ) {
+ //
+ // Poll the network layer to create the TFTP port
+ // for the tftp server. More than one attempt may
+ // be necessary since it may take some time to get
+ // the IP address and initialize the upper layers
+ // of the network stack.
+ //
+ TftpServerTimer ( pTftpServer );
+
+ //
+ // Poll the socket for activity
+ //
+ do {
+ SocketPoll ( pTftpServer );
+ } while ( -1 != pTftpServer->TftpPort.fd );
+
+//
+// TODO: Remove the following test code
+// Exit when the network connection is broken
+//
+break;
+ }
+
+ //
+ // Done with the timer event
+ //
+ TftpServerTimerStop ( pTftpServer );
+ Status = gBS->CloseEvent ( pTftpServer->TimerEvent );
+ }
+ }
+
+ //
+ // Return the final status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
|