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