]> git.proxmox.com Git - mirror_edk2.git/blobdiff - AppPkg/Applications/Sockets/TftpServer/TftpServer.c
Merged socket development branch:
[mirror_edk2.git] / AppPkg / Applications / Sockets / TftpServer / TftpServer.c
index a1e19c26f96a2a098bfbd9c3b0b6a758c97677c7..e9ab0dee5f059537d37dc1257a27273ed66a9dbb 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;
-}
+/** @file\r
+  This is a simple TFTP server application\r
+\r
+  Copyright (c) 2011, 2012, Intel Corporation\r
+  All rights reserved. This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <TftpServer.h>\r
+\r
+TSDT_TFTP_SERVER mTftpServer;       ///<  TFTP server's control structure\r
+volatile BOOLEAN mbTftpServerExit;  ///<  Set TRUE to cause TFTP server to exit\r
+\r
+\r
+/**\r
+  Read file data into a buffer\r
+\r
+  @param [in] pContext    Connection context structure address\r
+\r
+  @retval TRUE if a read error occurred\r
+\r
+**/\r
+BOOLEAN\r
+BufferFill (\r
+  IN TSDT_CONNECTION_CONTEXT * pContext\r
+  )\r
+{\r
+  BOOLEAN bReadError;\r
+  size_t BytesRead;\r
+  UINT64 LengthInBytes;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Use break instead of goto\r
+  //\r
+  bReadError = FALSE;\r
+  for ( ; ; ) {\r
+    //\r
+    //  Determine if there is any work to do\r
+    //\r
+    LengthInBytes = DIM ( pContext->FileData ) >> 1;\r
+    if (( pContext->ValidBytes > LengthInBytes )\r
+      || ( 0 == pContext->BytesRemaining )) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Determine the number of bytes to read\r
+    //\r
+    if ( LengthInBytes > pContext->BytesRemaining ) {\r
+      LengthInBytes = pContext->BytesRemaining;\r
+    }\r
+\r
+    //\r
+    //  Read in the next portion of the file\r
+    //\r
+    BytesRead = fread ( pContext->pFill,\r
+                        1,\r
+                        (size_t)LengthInBytes,\r
+                        pContext->File );\r
+    if ( -1 == BytesRead ) {\r
+      bReadError = TRUE;\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Account for the file data read\r
+    //\r
+    pContext->BytesRemaining -= BytesRead;\r
+    pContext->ValidBytes += BytesRead;\r
+    DEBUG (( DEBUG_FILE_BUFFER,\r
+              "0x%08x: Buffer filled with %Ld bytes, %Ld bytes ramaining\r\n",\r
+              pContext->pFill,\r
+              BytesRead,\r
+              pContext->BytesRemaining ));\r
+\r
+    //\r
+    //  Set the next buffer location\r
+    //\r
+    pContext->pFill += BytesRead;\r
+    if ( pContext->pEnd <= pContext->pFill ) {\r
+      pContext->pFill = &pContext->FileData[ 0 ];\r
+    }\r
+\r
+    //\r
+    //  Verify that the end of the buffer is reached\r
+    //\r
+    ASSERT ( 0 == ( DIM ( pContext->FileData ) & 1 ));\r
+    break;\r
+  }\r
+\r
+  //\r
+  //  Return the read status\r
+  //\r
+  DBG_EXIT ( );\r
+  return bReadError;\r
+}\r
+\r
+\r
+/**\r
+  Add a connection context to the list of connection contexts.\r
+\r
+  @param [in] pTftpServer   Address of the ::TSDT_TFTP_SERVER structure\r
+  @param [in] SocketFd      Socket file descriptor\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
+  IN int SocketFd\r
+  )\r
+{\r
+  TSDT_CONNECTION_CONTEXT * pContext;\r
+  TFTP_PACKET * pEnd;\r
+  TFTP_PACKET * pPacket;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Allocate a new context\r
+  //\r
+  pContext = (TSDT_CONNECTION_CONTEXT *)AllocateZeroPool ( sizeof ( *pContext ));\r
+  if ( NULL != pContext ) {\r
+    //\r
+    //  Initialize the context\r
+    //\r
+    pContext->SocketFd = SocketFd;\r
+    CopyMem ( &pContext->RemoteAddress,\r
+              &pTftpServer->RemoteAddress,\r
+              sizeof ( pContext->RemoteAddress ));\r
+    pContext->BlockSize = 512;\r
+\r
+    //\r
+    //  Buffer management\r
+    //\r
+    pContext->pFill = &pContext->FileData[ 0 ];\r
+    pContext->pEnd = &pContext->FileData[ sizeof ( pContext->FileData )];\r
+    pContext->pBuffer = pContext->pFill;\r
+\r
+    //\r
+    //  Window management\r
+    //\r
+    pContext->MaxTimeout = MultU64x32 ( PcdGet32 ( Tftp_MaxTimeoutInSec ),\r
+                                        2 * 1000 * 1000 * 1000 );\r
+    pContext->Rtt2x = pContext->MaxTimeout;\r
+    pContext->WindowSize = MAX_PACKETS;\r
+    WindowTimeout ( pContext );\r
+\r
+    //\r
+    //  Place the packets on the free list\r
+    //\r
+    pPacket = &pContext->Tx[ 0 ];\r
+    pEnd = &pPacket[ DIM ( pContext->Tx )];\r
+    while ( pEnd > pPacket ) {\r
+      PacketFree ( pContext, pPacket );\r
+      pPacket += 1;\r
+    }\r
+\r
+    //\r
+    //  Display the new context\r
+    //\r
+    if ( AF_INET == pTftpServer->RemoteAddress.v4.sin_family ) {\r
+      DEBUG (( DEBUG_PORT_WORK,\r
+                "0x%08x: Context for %d.%d.%d.%d:%d\r\n",\r
+                pContext,\r
+                (UINT8)pTftpServer->RemoteAddress.v4.sin_addr.s_addr,\r
+                (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 8 ),\r
+                (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 16 ),\r
+                (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 24 ),\r
+                htons ( pTftpServer->RemoteAddress.v4.sin_port )));\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_PORT_WORK,\r
+                "0x%08x: Context for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",\r
+                pContext,\r
+                pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 0 ],\r
+                pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 1 ],\r
+                pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 2 ],\r
+                pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 3 ],\r
+                pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 4 ],\r
+                pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 5 ],\r
+                pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 6 ],\r
+                pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 7 ],\r
+                pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 8 ],\r
+                pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 9 ],\r
+                pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 10 ],\r
+                pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 11 ],\r
+                pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 12 ],\r
+                pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 13 ],\r
+                pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 14 ],\r
+                pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 15 ],\r
+                htons ( pTftpServer->RemoteAddress.v6.sin6_port )));\r
+    }\r
+\r
+    //\r
+    //  Add the context to the context list\r
+    //\r
+    pContext->pNext = pTftpServer->pContextList;\r
+    pTftpServer->pContextList = pContext;\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   Address of the ::TSDT_TFTP_SERVER structure\r
+  @param [in] pIpAddress    The start of the remote IP address in network order\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 ( 0 == memcmp ( &pTftpServer->RemoteAddress,\r
+                       &pContext->RemoteAddress,\r
+                       pTftpServer->RemoteAddress.v6.sin6_len )) {\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   Address of the ::TSDT_TFTP_SERVER structure\r
+  @param [in] pContext      Address of a ::TSDT_CONNECTION_CONTEXT structure\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
+  Queue data packets for transmission\r
+\r
+  @param [in] pContext    Connection context structure address\r
+\r
+  @retval TRUE if a read error occurred\r
+\r
+**/\r
+BOOLEAN\r
+PacketFill (\r
+  IN TSDT_CONNECTION_CONTEXT * pContext\r
+  )\r
+{\r
+  BOOLEAN bReadError;\r
+  UINT64 LengthInBytes;\r
+  UINT8 * pBuffer;\r
+  TFTP_PACKET * pPacket;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Use break instead of goto\r
+  //\r
+  bReadError = FALSE;\r
+  for ( ; ; ) {\r
+    //\r
+    //  Fill the buffer if necessary\r
+    //\r
+    bReadError = BufferFill ( pContext );\r
+    if ( bReadError ) {\r
+      //\r
+      //  File access mode not supported\r
+      //\r
+      DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST,\r
+                "ERROR - File read failure!\r\n" ));\r
+\r
+      //\r
+      //  Tell the client of the error\r
+      //\r
+      SendError ( pContext,\r
+                  TFTP_ERROR_SEE_MSG,\r
+                  (UINT8 *)"Read failure" );\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Determine if any packets can be filled\r
+    //\r
+    if ( pContext->bEofSent\r
+      || ( NULL == pContext->pFreeList )) {\r
+      //\r
+      //  All of the packets are filled\r
+      //\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Set the TFTP opcode and block number\r
+    //\r
+    pPacket = PacketGet ( pContext );\r
+    pBuffer = &pPacket->TxBuffer[ 0 ];\r
+    *pBuffer++ = 0;\r
+    *pBuffer++ = TFTP_OP_DATA;\r
+    *pBuffer++ = (UINT8)( pContext->BlockNumber >> 8 );\r
+    *pBuffer++ = (UINT8)pContext->BlockNumber;\r
+\r
+    //\r
+    //  Determine how much data needs to be sent\r
+    //\r
+    LengthInBytes = pContext->BlockSize;\r
+    if (( pContext->BytesToSend < TFTP_MAX_BLOCK_SIZE )\r
+      && ( LengthInBytes > pContext->BytesToSend )) {\r
+      LengthInBytes = pContext->BytesToSend;\r
+      pContext->bEofSent = TRUE;\r
+    }\r
+    DEBUG (( DEBUG_TX_PACKET,\r
+              "0x%08x: Packet, Block %d filled with %d bytes\r\n",\r
+              pPacket,\r
+              pContext->BlockNumber,\r
+              (UINT32)LengthInBytes ));\r
+    \r
+    //\r
+    //  Copy the file data into the packet\r
+    //\r
+    pPacket->TxBytes = (ssize_t)( 2 + 2 + LengthInBytes );\r
+    if ( 0 < LengthInBytes ) {\r
+      CopyMem ( pBuffer,\r
+                pContext->pBuffer,\r
+                (UINTN)LengthInBytes );\r
+      DEBUG (( DEBUG_FILE_BUFFER,\r
+                "0x%08x: Buffer consumed %d bytes of file data\r\n",\r
+                pContext->pBuffer,\r
+                LengthInBytes ));\r
+\r
+      //\r
+      //  Account for the file data consumed\r
+      //\r
+      pContext->ValidBytes -= LengthInBytes;\r
+      pContext->BytesToSend -= LengthInBytes;\r
+      pContext->pBuffer += LengthInBytes;\r
+      if ( pContext->pEnd <= pContext->pBuffer ) {\r
+        pContext->pBuffer = &pContext->FileData[ 0 ];\r
+      }\r
+    }\r
+    \r
+    //\r
+    //  Queue the packet for transmission\r
+    //\r
+    PacketQueue ( pContext, pPacket );\r
+  }\r
+\r
+  //\r
+  //  Return the read status\r
+  //\r
+  DBG_EXIT ( );\r
+  return bReadError;\r
+}\r
+\r
+\r
+/**\r
+  Free the packet\r
+\r
+  @param [in] pContext    Address of a ::TSDT_CONNECTION_CONTEXT structure\r
+  @param [in] pPacket     Address of a ::TFTP_PACKET structure\r
+\r
+**/\r
+VOID\r
+PacketFree(\r
+  IN TSDT_CONNECTION_CONTEXT * pContext,\r
+  IN TFTP_PACKET * pPacket\r
+  )\r
+{\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Don't free the error packet\r
+  //\r
+  if ( pPacket != &pContext->ErrorPacket ) {\r
+    //\r
+    //  Place the packet on the free list\r
+    //\r
+    pPacket->pNext = pContext->pFreeList;\r
+    pContext->pFreeList = pPacket;\r
+    DEBUG (( DEBUG_TX_PACKET,\r
+              "0x%08x: Packet queued to free list\r\n",\r
+              pPacket ));\r
+  }\r
+\r
+  DBG_EXIT ( );\r
+}\r
+\r
+\r
+/**\r
+  Get a packet from the free list for transmission\r
+\r
+  @param [in] pContext    Address of a ::TSDT_CONNECTION_CONTEXT structure\r
+\r
+  @retval Address of a ::TFTP_PACKET structure\r
+\r
+**/\r
+TFTP_PACKET *\r
+PacketGet (\r
+  IN TSDT_CONNECTION_CONTEXT * pContext\r
+  )\r
+{\r
+  TFTP_PACKET * pPacket;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Get the next packet from the free list\r
+  //\r
+  pPacket = pContext->pFreeList;\r
+  if ( NULL != pPacket ) {\r
+    pContext->pFreeList = pPacket->pNext;\r
+    pPacket->RetryCount = 0;\r
+    DEBUG (( DEBUG_TX_PACKET,\r
+              "0x%08x: Packet removed from free list\r\n",\r
+              pPacket ));\r
+  }\r
+\r
+  //\r
+  //  Return the packet\r
+  //\r
+  DBG_EXIT_HEX ( pPacket );\r
+  return pPacket;\r
+}\r
+\r
+\r
+/**\r
+  Queue the packet for transmission\r
+\r
+  @param [in] pContext    Address of a ::TSDT_CONNECTION_CONTEXT structure\r
+  @param [in] pPacket     Address of a ::TFTP_PACKET structure\r
+\r
+  @retval TRUE if a transmission error has occurred\r
+\r
+**/\r
+BOOLEAN\r
+PacketQueue (\r
+  IN TSDT_CONNECTION_CONTEXT * pContext,\r
+  IN TFTP_PACKET * pPacket\r
+  )\r
+{\r
+  BOOLEAN bTransmitError;\r
+  TFTP_PACKET * pTail;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Account for this data block\r
+  //\r
+  pPacket->BlockNumber = pContext->BlockNumber;\r
+  pContext->BlockNumber += 1;\r
+\r
+  //\r
+  //  Queue the packet for transmission\r
+  //\r
+  pTail = pContext->pTxTail;\r
+  if ( NULL == pTail ) {\r
+    pContext->pTxHead = pPacket;\r
+  }\r
+  else {\r
+    pTail->pNext = pPacket;\r
+  }\r
+  pContext->pTxTail = pPacket;\r
+  pPacket->pNext = NULL;\r
+  DEBUG (( DEBUG_TX_PACKET,\r
+            "0x%08x: Packet queued to TX list\r\n",\r
+            pPacket ));\r
+\r
+  //\r
+  //  Start the transmission if necessary\r
+  //\r
+  bTransmitError = FALSE;\r
+  if ( pContext->PacketsInWindow < pContext->WindowSize ) {\r
+    Status = PacketTx ( pContext, pPacket );\r
+    bTransmitError = (BOOLEAN)( EFI_ERROR ( Status ));\r
+  }\r
+\r
+  //\r
+  //  Return the transmit status\r
+  //\r
+  DBG_EXIT_TF ( bTransmitError );\r
+  return bTransmitError;\r
+}\r
+\r
+\r
+/**\r
+  Remove a packet from the transmit queue\r
+\r
+  @param [in] pContext    Address of a ::TSDT_CONNECTION_CONTEXT structure\r
+\r
+**/\r
+TFTP_PACKET *\r
+PacketRemove(\r
+  IN TSDT_CONNECTION_CONTEXT * pContext\r
+  )\r
+{\r
+  TFTP_PACKET * pNext;\r
+  TFTP_PACKET * pPacket;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Remove a packet from the transmit queue\r
+  //\r
+  //\r
+  pPacket = pContext->pTxHead;\r
+  if ( NULL != pPacket ) {\r
+    pNext = pPacket->pNext;\r
+    pContext->pTxHead = pNext;\r
+    if ( NULL == pNext ) {\r
+      pContext->pTxTail = NULL;\r
+    }\r
+    DEBUG (( DEBUG_TX_PACKET,\r
+              "0x%08x: Packet removed from TX list\r\n",\r
+              pPacket ));\r
+\r
+    //\r
+    //  Remove this packet from the window\r
+    //\r
+    pContext->PacketsInWindow -= 1;\r
+  }\r
+\r
+  //\r
+  //  Return the packet\r
+  //\r
+  DBG_EXIT_HEX ( pPacket );\r
+  return pPacket;\r
+}\r
+\r
+\r
+/**\r
+  Transmit the packet\r
+\r
+  @param [in] pContext    Address of a ::TSDT_CONNECTION_CONTEXT structure\r
+  @param [in] pPacket     Address of a ::TFTP_PACKET structure\r
+\r
+  @retval EFI_SUCCESS   Message processed successfully\r
+\r
+**/\r
+EFI_STATUS\r
+PacketTx (\r
+  IN TSDT_CONNECTION_CONTEXT * pContext,\r
+  IN TFTP_PACKET * pPacket\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
+  //  Determine if this packet should be transmitted\r
+  //\r
+  if ( PcdGet32 ( Tftp_MaxRetry ) >= pPacket->RetryCount ) {\r
+    pPacket->RetryCount += 1;\r
+\r
+    //\r
+    //  Display the operation\r
+    //\r
+    DEBUG (( DEBUG_TX_PACKET,\r
+              "0x%08x: Packet transmiting\r\n",\r
+              pPacket ));\r
+    DEBUG (( DEBUG_TX,\r
+              "0x%08x: pContext sending 0x%08x bytes\r\n",\r
+              pContext,\r
+              pPacket->TxBytes ));\r
+\r
+    //\r
+    //  Keep track of when the packet was transmitted\r
+    //\r
+    if ( PcdGetBool ( Tftp_HighSpeed )) {\r
+      pPacket->TxTime = GetPerformanceCounter ( );\r
+    }\r
+\r
+    //\r
+    //  Send the TFTP packet\r
+    //\r
+    pContext->PacketsInWindow += 1;\r
+    LengthInBytes = sendto ( pContext->SocketFd,\r
+                             &pPacket->TxBuffer[ 0 ],\r
+                             pPacket->TxBytes,\r
+                             0,\r
+                             (struct sockaddr *)&pContext->RemoteAddress,\r
+                             pContext->RemoteAddress.sin6_len );\r
+    if ( -1 == LengthInBytes ) {\r
+      DEBUG (( DEBUG_ERROR | DEBUG_TX,\r
+                "ERROR - Transmit failure, errno: 0x%08x\r\n",\r
+                errno ));\r
+      pContext->PacketsInWindow -= 1;\r
+      Status = EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+  else {\r
+    //\r
+    //  Too many retries\r
+    //\r
+    Status = EFI_NO_RESPONSE;\r
+    DEBUG (( DEBUG_WARN | DEBUG_WINDOW,\r
+              "WARNING - No response from TFTP client\r\n" ));\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Process the work for the sockets.\r
+\r
+  @param [in] pTftpServer   Address of the ::TSDT_TFTP_SERVER structure\r
+  @param [in] pIndex        Address of an index into the pollfd array\r
+\r
+**/\r
+VOID\r
+PortWork (\r
+  IN TSDT_TFTP_SERVER * pTftpServer,\r
+  IN int * pIndex\r
+  )\r
+{\r
+  int Index;\r
+  TSDT_CONNECTION_CONTEXT * pContext;\r
+  struct pollfd * pTftpPort;\r
+  socklen_t RemoteAddressLength;\r
+  int revents;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Locate the port\r
+  //\r
+  Index = *pIndex;\r
+  if ( -1 != Index ) {\r
+    pTftpPort = &pTftpServer->TftpPort[ *pIndex ];\r
+\r
+    //\r
+    //  Handle input events\r
+    //\r
+    revents = pTftpPort->revents;\r
+    pTftpPort->revents = 0;\r
+    if ( 0 != ( revents & POLLRDNORM )) {\r
+      //\r
+      //  Receive the message from the remote system\r
+      //\r
+      RemoteAddressLength = sizeof ( pTftpServer->RemoteAddress );\r
+      pTftpServer->RxBytes = recvfrom ( pTftpPort->fd,\r
+                                        &pTftpServer->RxBuffer[ 0 ],\r
+                                        sizeof ( pTftpServer->RxBuffer ),\r
+                                        0,\r
+                                        (struct sockaddr *) &pTftpServer->RemoteAddress,\r
+                                        &RemoteAddressLength );\r
+      if ( -1 != pTftpServer->RxBytes ) {\r
+        if ( PcdGetBool ( Tftp_HighSpeed )) {\r
+          pTftpServer->RxTime = GetPerformanceCounter ( );\r
+        }\r
+        if ( AF_INET == pTftpServer->RemoteAddress.v4.sin_family ) {\r
+          DEBUG (( DEBUG_TFTP_PORT,\r
+                   "Received %d bytes from %d.%d.%d.%d:%d\r\n",\r
+                   pTftpServer->RxBytes,\r
+                   pTftpServer->RemoteAddress.v4.sin_addr.s_addr & 0xff,\r
+                   ( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 8 ) & 0xff,\r
+                   ( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 16 ) & 0xff,\r
+                   ( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 24 ) & 0xff,\r
+                   htons ( pTftpServer->RemoteAddress.v4.sin_port )));\r
+        }\r
+        else {\r
+          DEBUG (( DEBUG_TFTP_PORT,\r
+                   "Received %d bytes from [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",\r
+                   pTftpServer->RxBytes,\r
+                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 0 ],\r
+                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 1 ],\r
+                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 2 ],\r
+                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 3 ],\r
+                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 4 ],\r
+                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 5 ],\r
+                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 6 ],\r
+                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 7 ],\r
+                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 8 ],\r
+                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 9 ],\r
+                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 10 ],\r
+                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 11 ],\r
+                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 12 ],\r
+                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 13 ],\r
+                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 14 ],\r
+                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 15 ],\r
+                   htons ( pTftpServer->RemoteAddress.v6.sin6_port )));\r
+        }\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, pTftpPort->fd );\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
+        revents |= POLLHUP;\r
+      }\r
+    }\r
+\r
+    //\r
+    //  Handle the close event\r
+    //\r
+    if ( 0 != ( revents & POLLHUP )) {\r
+      //\r
+      //  Close the port\r
+      //\r
+      close ( pTftpPort->fd );\r
+      pTftpPort->fd = -1;\r
+      *pIndex = -1;\r
+      pTftpServer->Entries -= 1;\r
+      ASSERT ( 0 <= pTftpServer->Entries );\r
+    }\r
+  }\r
+\r
+  DBG_EXIT ( );\r
+}\r
+\r
+\r
+/**\r
+  Build and send an error packet\r
+\r
+  @param [in] pContext    Address of a ::TSDT_CONNECTION_CONTEXT structure\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
+SendError (\r
+  IN TSDT_CONNECTION_CONTEXT * pContext,\r
+  IN UINT16 Error,\r
+  IN UINT8 * pError\r
+  )\r
+{\r
+  UINT8 Character;\r
+  UINT8 * pBuffer;\r
+  TFTP_PACKET * pPacket;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Build the error packet\r
+  //\r
+  pPacket = &pContext->ErrorPacket;\r
+  pBuffer = &pPacket->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
+  pPacket->TxBytes = pBuffer - &pPacket->TxBuffer[ 0 ];\r
+  Status = PacketTx ( pContext, pPacket );\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Scan the list of sockets and process any pending work\r
+\r
+  @param [in] pTftpServer   Address of the ::TSDT_TFTP_SERVER structure\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
+  if ( 0 != pTftpServer->Entries ) {\r
+    FDCount = poll ( &pTftpServer->TftpPort[ 0 ],\r
+                     pTftpServer->Entries,\r
+                     CLIENT_POLL_DELAY );\r
+    if ( 0 < FDCount ) {\r
+      //\r
+      //  Process this port\r
+      //\r
+      PortWork ( pTftpServer, &pTftpServer->Udpv4Index );\r
+      PortWork ( pTftpServer, &pTftpServer->Udpv6Index );\r
+    }\r
+  }\r
+\r
+  DEBUG (( DEBUG_SOCKET_POLL, "Exiting SocketPoll\r\n" ));\r
+}\r
+\r
+\r
+/**\r
+  Process the ACK\r
+\r
+  @param [in] pTftpServer   Address of the ::TSDT_TFTP_SERVER structure\r
+  @param [in] pContext    Connection context structure address\r
+\r
+  @retval TRUE if the context should be closed\r
+\r
+**/\r
+BOOLEAN\r
+TftpAck (\r
+  IN TSDT_TFTP_SERVER * pTftpServer,\r
+  IN TSDT_CONNECTION_CONTEXT * pContext\r
+  )\r
+{\r
+  INTN AckNumber;\r
+  BOOLEAN bCloseContext;\r
+  UINT16 BlockNumber;\r
+  UINT8 * pBuffer;\r
+  TFTP_PACKET * pPacket;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Use break instead of goto\r
+  //\r
+  bCloseContext = FALSE;\r
+  for ( ; ; ) {\r
+    //\r
+    //  Validate the parameters\r
+    //\r
+    if ( NULL == pContext ) {\r
+      if ( AF_INET == pTftpServer->RemoteAddress.v4.sin_family ) {\r
+        DEBUG (( DEBUG_ERROR,\r
+                  "ERROR - File not open for %d.%d.%d.%d:%d\r\n",\r
+                  (UINT8)pTftpServer->RemoteAddress.v4.sin_addr.s_addr,\r
+                  (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 8 ),\r
+                  (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 16 ),\r
+                  (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 24 ),\r
+                  htons ( pTftpServer->RemoteAddress.v4.sin_port )));\r
+      }\r
+      else {\r
+        DEBUG (( DEBUG_ERROR,\r
+                  "ERROR - File not open for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 0 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 1 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 2 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 3 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 4 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 5 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 6 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 7 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 8 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 9 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 10 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 11 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 12 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 13 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 14 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 15 ],\r
+                  htons ( pTftpServer->RemoteAddress.v6.sin6_port )));\r
+      }\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Verify that the ACK was expected\r
+    //\r
+    pPacket = pContext->pTxHead;\r
+    if ( NULL == pPacket ) {\r
+      //\r
+      //  ACK not expected!\r
+      //\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Expecting data not ACKs for pContext 0x%08x\r\n",\r
+                pContext ));\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Get the ACKed block number\r
+    //\r
+    pBuffer = &pTftpServer->RxBuffer[ 0 ];\r
+    BlockNumber = HTONS ( *(UINT16 *)&pBuffer[ 2 ]);\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
+    AckNumber = BlockNumber - pPacket->BlockNumber;\r
+    if (( 0 > AckNumber ) || ( AckNumber >= (INTN)pContext->PacketsInWindow )){\r
+      DEBUG (( DEBUG_WARN | DEBUG_TFTP_ACK,\r
+                "WARNING - Expecting ACK 0x%0x4 not received ACK 0x%08x\r\n",\r
+                pPacket->BlockNumber,\r
+                BlockNumber ));\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Release the ACKed packets\r
+    //\r
+    do {\r
+      //\r
+      //  Remove the packet from the transmit list and window\r
+      //\r
+      pPacket = PacketRemove ( pContext );\r
+\r
+      //\r
+      //  Get the block number of this packet\r
+      //\r
+      AckNumber = pPacket->BlockNumber;\r
+\r
+      //\r
+      //  Increase the size of the transmit window\r
+      //\r
+      if ( PcdGetBool ( Tftp_HighSpeed )\r
+        && ( AckNumber == BlockNumber )) {\r
+        WindowAck ( pTftpServer, pContext, pPacket );\r
+      }\r
+\r
+      //\r
+      //  Free this packet\r
+      //\r
+      PacketFree ( pContext, pPacket );\r
+    } while (( NULL != pContext->pTxHead ) && ( AckNumber != BlockNumber ));\r
+\r
+    //\r
+    //  Fill the window with packets\r
+    //\r
+    pPacket = pContext->pTxHead;\r
+    while (( NULL != pPacket )\r
+      && ( pContext->PacketsInWindow < pContext->WindowSize )\r
+      && ( !bCloseContext )) {\r
+      Status = PacketTx ( pContext, pPacket );\r
+      bCloseContext = (BOOLEAN)( EFI_ERROR ( Status ));\r
+      pPacket = pPacket->pNext;\r
+    }\r
+    \r
+    //\r
+    //  Get more packets ready for transmission\r
+    //\r
+    PacketFill ( pContext );\r
+\r
+    //\r
+    //  Close the context when the last packet is ACKed\r
+    //\r
+    if ( 0 == pContext->PacketsInWindow ) {\r
+      bCloseContext = TRUE;\r
+\r
+      //\r
+      //  Display the bandwidth\r
+      //\r
+      if ( PcdGetBool ( Tftp_Bandwidth )) {\r
+        UINT64 Bandwidth;\r
+        UINT64 DeltaTime;\r
+        UINT64 NanoSeconds;\r
+        UINT32 Value;\r
+\r
+        //\r
+        //  Compute the download time\r
+        //\r
+        DeltaTime = GetPerformanceCounter ( );\r
+        if ( pTftpServer->Time2 > pTftpServer->Time1 ) {\r
+          DeltaTime = DeltaTime - pContext->TimeStart;\r
+        }\r
+        else {\r
+          DeltaTime = pContext->TimeStart - DeltaTime;\r
+        }\r
+        NanoSeconds = GetTimeInNanoSecond ( DeltaTime );\r
+        Bandwidth = pContext->LengthInBytes;\r
+        DEBUG (( DEBUG_WINDOW,\r
+                  "File Length %Ld, Transfer Time: %d.%03d Sec\r\n",\r
+                  Bandwidth,\r
+                  DivU64x32 ( NanoSeconds, 1000 * 1000 * 1000 ),\r
+                  ((UINT32)DivU64x32 ( NanoSeconds, 1000 * 1000 )) % 1000 ));\r
+\r
+        //\r
+        //  Display the round trip time\r
+        //\r
+        Bandwidth = MultU64x32 ( Bandwidth, 8 * 1000 * 1000 );\r
+        Bandwidth /= NanoSeconds;\r
+        if ( 1000 > Bandwidth ) {\r
+          Value = (UINT32)Bandwidth;\r
+          Print ( L"Bandwidth: %d Kbits/Sec\r\n",\r
+                  Value );\r
+        }\r
+        else if (( 1000 * 1000 ) > Bandwidth ) {\r
+          Value = (UINT32)Bandwidth;\r
+          Print ( L"Bandwidth: %d.%03d Mbits/Sec\r\n",\r
+                  Value / 1000,\r
+                  Value % 1000 );\r
+        }\r
+        else {\r
+          Value = (UINT32)DivU64x32 ( Bandwidth, 1000 );\r
+          Print ( L"Bandwidth: %d.%03d Gbits/Sec\r\n",\r
+                  Value / 1000,\r
+                  Value % 1000 );\r
+        }\r
+      }\r
+    }\r
+    break;\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  DBG_EXIT ( );\r
+  return bCloseContext;\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  Address of a ::TSDT_CONNECTION_CONTEXT structure\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
+  TFTP_PACKET * pPacket;\r
+  UINT8 * pTemp;\r
+  UINT8 * pValue;\r
+  EFI_STATUS Status;\r
+  INT32 Value;\r
+\r
+  //\r
+  //  Get a packet\r
+  //\r
+  pPacket = PacketGet ( pContext );\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 = &pPacket->TxBuffer[ 0 ];\r
+  *pOack++ = 0;\r
+  *pOack++ = TFTP_OP_OACK;\r
+  pPacket->TxBytes = 2;\r
+  pPacket->BlockNumber = 0;\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 == strcasecmp ((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
+            pPacket->TxBytes += pOack - pTemp;\r
+          }\r
+        }\r
+      }\r
+\r
+      //\r
+      //  timeout - See http://tools.ietf.org/html/rfc2349\r
+      //\r
+      else if ( 0 == strcasecmp ((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->MaxTimeout = Value;\r
+            DEBUG (( DEBUG_TFTP_REQUEST,\r
+                      "Using timeout of %d seconds\r\n",\r
+                      pContext->MaxTimeout ));\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->MaxTimeout );\r
+            *pOack++ = 0;\r
+            pPacket->TxBytes += pOack - pTemp;\r
+          }\r
+        }\r
+      }\r
+\r
+      //\r
+      //  tsize - See http://tools.ietf.org/html/rfc2349\r
+      //\r
+      else if ( 0 == strcasecmp ((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
+            pPacket->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
+  //  Transmit the OACK if necessary\r
+  //\r
+  if ( 2 < pPacket->TxBytes ) {\r
+    PacketQueue ( pContext, pPacket );\r
+  }\r
+  else {\r
+    PacketFree ( pContext, pPacket );\r
+  }\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 Address of the ::TSDT_TFTP_SERVER structure\r
+  @param [in] pContext    Address of a ::TSDT_CONNECTION_CONTEXT structure\r
+  @param [in] SocketFd    Socket file descriptor\r
+\r
+**/\r
+VOID\r
+TftpProcessRequest (\r
+  IN TSDT_TFTP_SERVER * pTftpServer,\r
+  IN TSDT_CONNECTION_CONTEXT * pContext,\r
+  IN int SocketFd\r
+  )\r
+{\r
+  BOOLEAN bCloseContext;\r
+  UINT16 Opcode;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Get the opcode\r
+  //\r
+  Opcode = HTONS ( *(UINT16 *)&pTftpServer->RxBuffer[ 0 ]);\r
+  DEBUG (( DEBUG_TFTP_REQUEST,\r
+            "TFTP Opcode: 0x%08x\r\n",\r
+            Opcode ));\r
+\r
+  //\r
+  //  Validate the parameters\r
+  //\r
+  bCloseContext = FALSE;\r
+  switch ( Opcode ) {\r
+  default:\r
+    DEBUG (( DEBUG_TFTP_REQUEST,\r
+              "ERROR - Unknown TFTP opcode: %d\r\n",\r
+              Opcode ));\r
+    break;\r
+\r
+  case TFTP_OP_ACK:\r
+    bCloseContext = TftpAck ( pTftpServer, pContext );\r
+    break;\r
+\r
+  case TFTP_OP_READ_REQUEST:\r
+    bCloseContext = TftpRead ( pTftpServer, pContext, SocketFd );\r
+    break;\r
+\r
+\r
+\r
+  \r
+  case TFTP_OP_DATA:\r
+    if ( NULL == pContext ) {\r
+      if ( AF_INET == pTftpServer->RemoteAddress.v4.sin_family ) {\r
+        DEBUG (( DEBUG_ERROR,\r
+                  "ERROR - File not open for %d.%d.%d.%d:%d\r\n",\r
+                  (UINT8)pTftpServer->RemoteAddress.v4.sin_addr.s_addr,\r
+                  (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 8 ),\r
+                  (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 16 ),\r
+                  (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 24 ),\r
+                  htons ( pTftpServer->RemoteAddress.v4.sin_port )));\r
+      }\r
+      else {\r
+        DEBUG (( DEBUG_ERROR,\r
+                  "ERROR - File not open for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 0 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 1 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 2 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 3 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 4 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 5 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 6 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 7 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 8 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 9 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 10 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 11 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 12 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 13 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 14 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 15 ],\r
+                  htons ( pTftpServer->RemoteAddress.v6.sin6_port )));\r
+      }\r
+      break;\r
+    }\r
+    if ( 0 != pContext->PacketsInWindow ) {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Expecting ACKs not data for pContext 0x%08x\r\n",\r
+                pContext ));\r
+      break;\r
+    }\r
+    if ( pTftpServer->RxBytes > (ssize_t)( pContext->BlockSize + 2 + 2 )) {\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
+      break;\r
+    }\r
+    break;\r
+\r
+  case TFTP_OP_ERROR:\r
+    if ( NULL == pContext ) {\r
+      if ( AF_INET == pTftpServer->RemoteAddress.v4.sin_family ) {\r
+        DEBUG (( DEBUG_ERROR,\r
+                  "ERROR - File not open for %d.%d.%d.%d:%d\r\n",\r
+                  (UINT8)pTftpServer->RemoteAddress.v4.sin_addr.s_addr,\r
+                  (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 8 ),\r
+                  (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 16 ),\r
+                  (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 24 ),\r
+                  htons ( pTftpServer->RemoteAddress.v4.sin_port )));\r
+      }\r
+      else {\r
+        DEBUG (( DEBUG_ERROR,\r
+                  "ERROR - File not open for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 0 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 1 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 2 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 3 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 4 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 5 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 6 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 7 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 8 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 9 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 10 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 11 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 12 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 13 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 14 ],\r
+                  pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 15 ],\r
+                  htons ( pTftpServer->RemoteAddress.v6.sin6_port )));\r
+      }\r
+    }\r
+    break;\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
+  Process the read request\r
+\r
+  @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure\r
+  @param [in] pContext    Address of a ::TSDT_CONNECTION_CONTEXT structure\r
+  @param [in] SocketFd    Socket file descriptor\r
+\r
+  @retval TRUE if the context should be closed\r
+\r
+**/\r
+BOOLEAN\r
+TftpRead (\r
+  IN TSDT_TFTP_SERVER * pTftpServer,\r
+  IN TSDT_CONNECTION_CONTEXT * pContext,\r
+  IN int SocketFd\r
+  )\r
+{\r
+  BOOLEAN bCloseContext;\r
+  struct stat FileStatus;\r
+  UINT8 * pBuffer;\r
+  UINT8 * pEnd;\r
+  UINT8 * pFileName;\r
+  UINT8 * pMode;\r
+  UINT8 * pOption;\r
+  CHAR8 * pReadMode;\r
+  UINT64 TimeStart;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Log the receive time\r
+  //\r
+  TimeStart = 0;\r
+  if ( PcdGetBool ( Tftp_Bandwidth )) {\r
+    TimeStart = GetPerformanceCounter ( );\r
+  }\r
+\r
+  //\r
+  //  Close the context if necessary\r
+  //\r
+  bCloseContext = FALSE;\r
+  if ( NULL != pContext ) {\r
+    ContextRemove ( pTftpServer, pContext );\r
+  }\r
+\r
+  //\r
+  //  Use break instead of goto\r
+  //\r
+  for ( ; ; ) {\r
+    //\r
+    //  Create the connection context\r
+    //\r
+    pContext = ContextAdd ( pTftpServer, SocketFd );\r
+    if ( NULL == pContext ) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Set the start time\r
+    //\r
+    if ( PcdGetBool ( Tftp_Bandwidth )) {\r
+      pContext->TimeStart = TimeStart;\r
+    }\r
+\r
+    //\r
+    //  Locate the mode\r
+    //\r
+    pBuffer = &pTftpServer->RxBuffer[ 0 ];\r
+    pEnd = &pBuffer[ pTftpServer->RxBytes ];\r
+    pFileName = &pBuffer[ 2 ];\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
+      SendError ( pContext,\r
+                  TFTP_ERROR_SEE_MSG,\r
+                  (UINT8 *)"File open mode not found" );\r
+      break;\r
+    }\r
+    pMode += 1;\r
+    DEBUG (( DEBUG_TFTP_REQUEST,\r
+              "TFTP - FileName: %a\r\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
+      SendError ( pContext,\r
+                  TFTP_ERROR_SEE_MSG,\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
+    pReadMode = "r";\r
+    if ( 0 == strcasecmp ((char *)pMode, "octet" )) {\r
+      //\r
+      //  Read the file as binary input\r
+      //\r
+      pReadMode = "rb";\r
+    }\r
+\r
+    //\r
+    //  Determine the file length\r
+    //\r
+    pContext->File = fopen ( pFileName, pReadMode );\r
+    if (( NULL == pContext->File )\r
+        || ( -1 == stat ( pFileName, &FileStatus ))) {\r
+      //\r
+      //  File not found\r
+      //\r
+      DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST,\r
+                ( NULL == pContext->File )\r
+                ? "ERROR - File not found!\r\n"\r
+                : "ERROR - Unable to determine file %a size!\r\n",\r
+                pFileName ));\r
+\r
+      //\r
+      //  Tell the client of the error\r
+      //\r
+      SendError ( pContext,\r
+                  TFTP_ERROR_NOT_FOUND,\r
+                  (UINT8 *)"File not found" );\r
+      break;\r
+    }\r
+    pContext->LengthInBytes = FileStatus.st_size;\r
+    pContext->BytesRemaining = pContext->LengthInBytes;\r
+    pContext->BytesToSend = pContext->LengthInBytes;\r
+\r
+    //\r
+    //  Display the file size\r
+    //\r
+    DEBUG_CODE_BEGIN ( );\r
+    UINT32 Value;\r
+\r
+    if ( 1024 > pContext->LengthInBytes ) {\r
+      Value = (UINT32)pContext->LengthInBytes;\r
+      DEBUG (( DEBUG_FILE_BUFFER,\r
+                "%a size: %d Bytes\r\n",\r
+                pFileName,\r
+                Value ));\r
+    }\r
+    else if (( 1024 * 1024 ) > pContext->LengthInBytes ) {\r
+      Value = (UINT32)pContext->LengthInBytes;\r
+      DEBUG (( DEBUG_FILE_BUFFER,\r
+                "%a size: %d.%03d KiBytes (%Ld Bytes)\r\n",\r
+                pFileName,\r
+                Value / 1024,\r
+                (( Value % 1024 ) * 1000 ) / 1024,\r
+                pContext->LengthInBytes ));\r
+    }\r
+    else if (( 1024 * 1024 * 1024 ) > pContext->LengthInBytes ) {\r
+      Value = (UINT32)DivU64x32 ( pContext->LengthInBytes, 1024 );\r
+      DEBUG (( DEBUG_FILE_BUFFER,\r
+                "%a size: %d.%03d MiBytes (%Ld Bytes)\r\n",\r
+                pFileName,\r
+                Value / 1024,\r
+                (( Value % 1024 ) * 1000 ) / 1024,\r
+                pContext->LengthInBytes ));\r
+    }\r
+    else {\r
+      Value = (UINT32)DivU64x32 ( pContext->LengthInBytes, 1024 * 1024 );\r
+      DEBUG (( DEBUG_FILE_BUFFER,\r
+                "%a size: %d.%03d GiBytes (%Ld Bytes)\r\n",\r
+                pFileName,\r
+                Value / 1024,\r
+                (( Value % 1024 ) * 1000 ) / 1024,\r
+                pContext->LengthInBytes ));\r
+    }\r
+    DEBUG_CODE_END ( );\r
+\r
+    //\r
+    //  Process the options\r
+    //\r
+    if ( pEnd > pOption ) {\r
+      TftpOptions ( pContext, pOption, pEnd );\r
+    }\r
+    else {\r
+      //\r
+      //  Skip the open ACK\r
+      //\r
+      pContext->BlockNumber = 1;\r
+    }\r
+\r
+    //\r
+    //  Send the first packet (OACK or data block)\r
+    //\r
+    bCloseContext = PacketFill ( pContext );\r
+    break;\r
+  }\r
+\r
+  //\r
+  //  Return the close status\r
+  //\r
+  DBG_EXIT ( );\r
+  return bCloseContext;\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   Address of the ::TSDT_TFTP_SERVER structure\r
+  @param [in] AddressFamily The address family to use for the conection.\r
+  @param [in] pIndex        Address of the index into the port array\r
+\r
+**/\r
+VOID\r
+TftpServerSocket (\r
+  IN TSDT_TFTP_SERVER * pTftpServer,\r
+  IN sa_family_t AddressFamily,\r
+  IN int * pIndex\r
+  )\r
+{\r
+  int SocketStatus;\r
+  struct pollfd * pTftpPort;\r
+  UINT16 TftpPort;\r
+  union {\r
+    struct sockaddr_in v4;\r
+    struct sockaddr_in6 v6;\r
+  } TftpServerAddress;\r
+\r
+  DEBUG (( DEBUG_SERVER_TIMER, "Entering TftpServerListen\r\n" ));\r
+\r
+  //\r
+  //  Determine if the socket is already initialized\r
+  //\r
+  if ( -1 == *pIndex ) {\r
+    //\r
+    //  Attempt to create the socket for the TFTP server\r
+    //\r
+    pTftpPort = &pTftpServer->TftpPort[ pTftpServer->Entries ];\r
+    pTftpPort->fd = socket ( AddressFamily,\r
+                             SOCK_DGRAM,\r
+                             IPPROTO_UDP );\r
+    if ( -1 != pTftpPort->fd ) {\r
+      //\r
+      //  Initialize the poll structure\r
+      //\r
+      pTftpPort->events = POLLRDNORM | POLLHUP;\r
+      pTftpPort->revents = 0;\r
+\r
+      //\r
+      //  Set the socket address\r
+      //\r
+      TftpPort = 69;\r
+      ZeroMem ( &TftpServerAddress, sizeof ( TftpServerAddress ));\r
+      TftpServerAddress.v4.sin_port = htons ( TftpPort );\r
+      if ( AF_INET == AddressFamily ) {\r
+        TftpServerAddress.v4.sin_len = sizeof ( TftpServerAddress.v4 );\r
+        TftpServerAddress.v4.sin_family = AF_INET;\r
+      }\r
+      else {\r
+        TftpServerAddress.v6.sin6_len = sizeof ( TftpServerAddress.v6 );\r
+        TftpServerAddress.v6.sin6_family = AF_INET6;\r
+      }\r
+\r
+      //\r
+      //  Bind the socket to the TFTP port\r
+      //\r
+      SocketStatus = bind ( pTftpPort->fd,\r
+                            (struct sockaddr *) &TftpServerAddress,\r
+                            TftpServerAddress.v6.sin6_len );\r
+      if ( -1 != SocketStatus ) {\r
+        DEBUG (( DEBUG_TFTP_PORT,\r
+                  "0x%08x: Socket bound to port %d\r\n",\r
+                  pTftpPort->fd,\r
+                  TftpPort ));\r
+\r
+        //\r
+        //  Account for this connection\r
+        //\r
+        *pIndex = pTftpServer->Entries;\r
+        pTftpServer->Entries += 1;\r
+        ASSERT ( DIM ( pTftpServer->TftpPort ) >= pTftpServer->Entries );\r
+      }\r
+\r
+      //\r
+      //  Release the socket if necessary\r
+      //\r
+      if ( -1 == SocketStatus ) {\r
+        close ( pTftpPort->fd );\r
+        pTftpPort->fd = -1;\r
+      }\r
+    }\r
+  }\r
+\r
+  DEBUG (( DEBUG_SERVER_TIMER, "Exiting TftpServerListen\r\n" ));\r
+}\r
+\r
+\r
+/**\r
+  Update the window due to the ACK\r
+\r
+  @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure\r
+  @param [in] pContext    Address of a ::TSDT_CONNECTION_CONTEXT structure\r
+  @param [in] pPacket     Address of a ::TFTP_PACKET structure\r
+\r
+**/\r
+VOID\r
+WindowAck (\r
+  IN TSDT_TFTP_SERVER * pTftpServer,\r
+  IN TSDT_CONNECTION_CONTEXT * pContext,\r
+  IN TFTP_PACKET * pPacket\r
+  )\r
+{\r
+  if ( PcdGetBool ( Tftp_HighSpeed )) {\r
+    UINT64 DeltaTime;\r
+    UINT64 NanoSeconds;\r
+\r
+    DBG_ENTER ( );\r
+\r
+    //\r
+    //  Compute the round trip time\r
+    //\r
+    if ( pTftpServer->Time2 > pTftpServer->Time1 ) {\r
+      DeltaTime = pTftpServer->RxTime - pPacket->TxTime;\r
+    }\r
+    else {\r
+      DeltaTime = pPacket->TxTime - pTftpServer->RxTime;\r
+    }\r
+\r
+    //\r
+    //  Adjust the round trip time\r
+    //\r
+    NanoSeconds = GetTimeInNanoSecond ( DeltaTime );\r
+    DeltaTime = RShiftU64 ( pContext->Rtt2x, ACK_SHIFT );\r
+    pContext->Rtt2x += NanoSeconds + NanoSeconds - DeltaTime;\r
+    if ( pContext->Rtt2x > pContext->MaxTimeout ) {\r
+      pContext->Rtt2x = pContext->MaxTimeout;\r
+    }\r
+\r
+    //\r
+    //  Account for the ACK\r
+    //\r
+    if ( pContext->WindowSize < MAX_PACKETS ) {\r
+      pContext->AckCount -= 1;\r
+      if ( 0 == pContext->AckCount ) {\r
+        //\r
+        //  Increase the window\r
+        //\r
+        pContext->WindowSize += 1;\r
+\r
+        //\r
+        //  Set the ACK count\r
+        //\r
+        if ( pContext->WindowSize < pContext->Threshold ) {\r
+          pContext->AckCount = pContext->WindowSize * PcdGet32 ( Tftp_AckMultiplier );\r
+        }\r
+        else {\r
+          pContext->AckCount = PcdGet32 ( Tftp_AckLogBase ) << pContext->WindowSize;\r
+        }\r
+\r
+        //\r
+        //  Display the round trip time\r
+        //\r
+        DEBUG_CODE_BEGIN ( );\r
+        UINT32 Value;\r
+        \r
+        DeltaTime = RShiftU64 ( pContext->Rtt2x, 1 );\r
+        if ( 1000 > DeltaTime ) {\r
+          DEBUG (( DEBUG_WINDOW,\r
+                    "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %Ld nSec\r\n",\r
+                    pContext->WindowSize,\r
+                    pContext->Threshold,\r
+                    pContext->AckCount,\r
+                    DeltaTime ));\r
+        }\r
+        else if (( 1000 * 1000 ) > DeltaTime ) {\r
+          Value = (UINT32)DeltaTime;\r
+          DEBUG (( DEBUG_WINDOW,\r
+                    "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d uSec\r\n",\r
+                    pContext->WindowSize,\r
+                    pContext->Threshold,\r
+                    pContext->AckCount,\r
+                    Value / 1000,\r
+                    Value % 1000 ));\r
+        }\r
+        else if (( 1000 * 1000 * 1000 ) > DeltaTime ) {\r
+          Value = (UINT32)DivU64x32 ( DeltaTime, 1000 );\r
+          DEBUG (( DEBUG_WINDOW,\r
+                    "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d mSec\r\n",\r
+                    pContext->WindowSize,\r
+                    pContext->Threshold,\r
+                    pContext->AckCount,\r
+                    Value / 1000,\r
+                    Value % 1000 ));\r
+        }\r
+        else {\r
+          Value = (UINT32)DivU64x32 ( DeltaTime, 1000 * 1000 );\r
+          DEBUG (( DEBUG_WINDOW,\r
+                    "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d Sec\r\n",\r
+                    pContext->WindowSize,\r
+                    pContext->Threshold,\r
+                    pContext->AckCount,\r
+                    Value / 1000,\r
+                    Value % 1000 ));\r
+        }\r
+        DEBUG_CODE_END ( );\r
+      }\r
+    }\r
+\r
+    DBG_EXIT ( );\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  A timeout has occurred, close the window\r
+\r
+  @param [in] pContext    Address of a ::TSDT_CONNECTION_CONTEXT structure\r
+\r
+**/\r
+VOID\r
+WindowTimeout (\r
+  IN TSDT_CONNECTION_CONTEXT * pContext\r
+  )\r
+{\r
+  if ( PcdGetBool ( Tftp_HighSpeed )) {\r
+    TFTP_PACKET * pPacket;\r
+\r
+    DBG_ENTER ( );\r
+\r
+    //\r
+    //  Set the threshold at half the previous window size\r
+    //\r
+    pContext->Threshold = ( pContext->WindowSize + 1 ) >> 1;\r
+\r
+    //\r
+    //  Close the transmit window\r
+    //\r
+    pContext->WindowSize = 1;\r
+    pContext->PacketsInWindow = 0;\r
+\r
+    //\r
+    //  Double the round trip time\r
+    //\r
+    pContext->Rtt2x = LShiftU64 ( pContext->Rtt2x, 1 );\r
+    if ( pContext->Rtt2x > pContext->MaxTimeout ) {\r
+      pContext->Rtt2x = pContext->MaxTimeout;\r
+    }\r
+\r
+    //\r
+    //  Set the ACK count\r
+    //\r
+    if ( pContext->WindowSize < pContext->Threshold ) {\r
+      pContext->AckCount = pContext->WindowSize * PcdGet32 ( Tftp_AckMultiplier );\r
+    }\r
+    else {\r
+      pContext->AckCount = PcdGet32 ( Tftp_AckLogBase ) << pContext->WindowSize;\r
+    }\r
+\r
+    //\r
+    //  Display the round trip time\r
+    //\r
+    DEBUG_CODE_BEGIN ( );\r
+    UINT64 DeltaTime;\r
+    UINT32 Value;\r
+    \r
+    DeltaTime = RShiftU64 ( pContext->Rtt2x, 1 );\r
+    if ( 1000 > DeltaTime ) {\r
+      DEBUG (( DEBUG_WINDOW,\r
+                "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %Ld nSec\r\n",\r
+                pContext->WindowSize,\r
+                pContext->Threshold,\r
+                pContext->AckCount,\r
+                DeltaTime ));\r
+    }\r
+    else if (( 1000 * 1000 ) > DeltaTime ) {\r
+      Value = (UINT32)DeltaTime;\r
+      DEBUG (( DEBUG_WINDOW,\r
+                "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d uSec\r\n",\r
+                pContext->WindowSize,\r
+                pContext->Threshold,\r
+                pContext->AckCount,\r
+                Value / 1000,\r
+                Value % 1000 ));\r
+    }\r
+    else if (( 1000 * 1000 * 1000 ) > DeltaTime ) {\r
+      Value = (UINT32)DivU64x32 ( DeltaTime, 1000 );\r
+      DEBUG (( DEBUG_WINDOW,\r
+                "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d mSec\r\n",\r
+                pContext->WindowSize,\r
+                pContext->Threshold,\r
+                pContext->AckCount,\r
+                Value / 1000,\r
+                Value % 1000 ));\r
+    }\r
+    else {\r
+      Value = (UINT32)DivU64x32 ( DeltaTime, 1000 * 1000 );\r
+      DEBUG (( DEBUG_WINDOW,\r
+                "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d Sec\r\n",\r
+                pContext->WindowSize,\r
+                pContext->Threshold,\r
+                pContext->AckCount,\r
+                Value / 1000,\r
+                Value % 1000 ));\r
+    }\r
+    DEBUG_CODE_END ( );\r
+\r
+    //\r
+    //  Retransmit the first packet in the window\r
+    //\r
+    pPacket = pContext->pTxHead;\r
+    if ( NULL != pPacket ) {\r
+      PacketTx ( pContext, pPacket );\r
+    }\r
+    \r
+    DBG_EXIT ( );\r
+  }\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
+  UINTN Index;\r
+  TSDT_TFTP_SERVER * pTftpServer;\r
+  EFI_STATUS Status;\r
+  UINT64 TriggerTime;\r
+\r
+  //\r
+  //  Get the performance counter characteristics\r
+  //\r
+  pTftpServer = &mTftpServer;\r
+  if ( PcdGetBool ( Tftp_HighSpeed )\r
+    || PcdGetBool ( Tftp_Bandwidth )) {\r
+    pTftpServer->ClockFrequency = GetPerformanceCounterProperties ( &pTftpServer->Time1,\r
+                                                                  &pTftpServer->Time2 );\r
+  }\r
+\r
+  //\r
+  //  Create a timer event to start TFTP port\r
+  //\r
+  Status = gBS->CreateEvent ( EVT_TIMER,\r
+                              TPL_TFTP_SERVER,\r
+                              NULL,\r
+                              NULL,\r
+                              &pTftpServer->TimerEvent );\r
+  if ( !EFI_ERROR ( Status )) {\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
+      //  Run the TFTP server forever\r
+      //\r
+      pTftpServer->Udpv4Index = -1;\r
+      pTftpServer->Udpv6Index = -1;\r
+      do {\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
+        if ( DIM ( pTftpServer->TftpPort ) != pTftpServer->Entries ) {\r
+          do {\r
+            //\r
+            //  Wait a while before polling for a connection\r
+            //\r
+            if ( EFI_SUCCESS != gBS->CheckEvent ( pTftpServer->TimerEvent )) {\r
+              if ( 0 == pTftpServer->Entries ) {\r
+                break;\r
+              }\r
+              gBS->WaitForEvent ( 1, &pTftpServer->TimerEvent, &Index );\r
+            }\r
+\r
+            //\r
+            //  Poll for a network connection\r
+            //\r
+            TftpServerSocket ( pTftpServer,\r
+                               AF_INET,\r
+                               &pTftpServer->Udpv4Index );\r
+            TftpServerSocket ( pTftpServer,\r
+                               AF_INET6,\r
+                               &pTftpServer->Udpv6Index );\r
+          } while ( 0 == pTftpServer->Entries );\r
+        }\r
+\r
+        //\r
+        //  Poll the socket for activity\r
+        //\r
+        do {\r
+          SocketPoll ( pTftpServer );\r
+\r
+          //\r
+          //  Normal TFTP lets the client request the retransmit by\r
+          //  sending another ACK for the previous packet\r
+          //\r
+          if ( PcdGetBool ( Tftp_HighSpeed )) {\r
+            UINT64 CurrentTime;\r
+            UINT64 ElapsedTime;\r
+            TSDT_CONNECTION_CONTEXT * pContext;\r
+            TFTP_PACKET * pPacket;\r
+\r
+            //\r
+            //  High speed TFTP uses an agressive retransmit to\r
+            //  get the TFTP client moving again when the ACK or\r
+            //  previous data packet was lost.\r
+            //\r
+            //  Get the current time\r
+            //\r
+            CurrentTime = GetPerformanceCounter ( );\r
+\r
+            //\r
+            //  Walk the list of contexts\r
+            //\r
+            pContext = pTftpServer->pContextList;\r
+            while ( NULL != pContext )\r
+            {\r
+              //\r
+              //  Check for a transmit timeout\r
+              //\r
+              pPacket = pContext->pTxHead;\r
+              if ( NULL != pPacket ) {\r
+                //\r
+                //  Compute the elapsed time\r
+                //\r
+                if ( pTftpServer->Time2 > pTftpServer->Time1 ) {\r
+                  ElapsedTime = CurrentTime - pPacket->TxTime;\r
+                }\r
+                else {\r
+                  ElapsedTime = pPacket->TxTime - CurrentTime;\r
+                }\r
+                ElapsedTime = GetTimeInNanoSecond ( ElapsedTime );\r
+\r
+                //\r
+                //  Determine if a retransmission is necessary\r
+                //\r
+                if ( ElapsedTime >= pContext->Rtt2x ) {\r
+                  DEBUG (( DEBUG_WINDOW,\r
+                            "0x%08x: Context TX timeout for packet 0x%08x, Window: %d\r\n",\r
+                            pContext,\r
+                            pPacket,\r
+                            pContext->WindowSize ));\r
+                  WindowTimeout ( pContext );\r
+                }\r
+              }\r
+\r
+              //\r
+              //  Set the next context\r
+              //\r
+              pContext = pContext->pNext;\r
+            }\r
+          }\r
+        } while ( DIM ( pTftpServer->TftpPort ) == pTftpServer->Entries );\r
+      } while ( !mbTftpServerExit );\r
+\r
+      //\r
+      //  Done with the timer event\r
+      //\r
+      gBS->SetTimer ( pTftpServer->TimerEvent,\r
+                      TimerCancel,\r
+                      0 );\r
+    }\r
+    gBS->CloseEvent ( pTftpServer->TimerEvent );\r
+  }\r
+\r
+  //\r
+  //  Return the final status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r