Home | History | Annotate | Download | only in TftpServer
      1 /** @file
      2   This is a simple TFTP server application
      3 
      4   Copyright (c) 2011, 2012, Intel Corporation
      5   All rights reserved. This program and the accompanying materials
      6   are licensed and made available under the terms and conditions of the BSD License
      7   which accompanies this distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include <TftpServer.h>
     16 
     17 TSDT_TFTP_SERVER mTftpServer;       ///<  TFTP server's control structure
     18 volatile BOOLEAN mbTftpServerExit;  ///<  Set TRUE to cause TFTP server to exit
     19 
     20 
     21 /**
     22   Read file data into a buffer
     23 
     24   @param [in] pContext    Connection context structure address
     25 
     26   @retval TRUE if a read error occurred
     27 
     28 **/
     29 BOOLEAN
     30 BufferFill (
     31   IN TSDT_CONNECTION_CONTEXT * pContext
     32   )
     33 {
     34   BOOLEAN bReadError;
     35   size_t BytesRead;
     36   UINT64 LengthInBytes;
     37 
     38   DBG_ENTER ( );
     39 
     40   //
     41   //  Use break instead of goto
     42   //
     43   bReadError = FALSE;
     44   for ( ; ; ) {
     45     //
     46     //  Determine if there is any work to do
     47     //
     48     LengthInBytes = DIM ( pContext->FileData ) >> 1;
     49     if (( pContext->ValidBytes > LengthInBytes )
     50       || ( 0 == pContext->BytesRemaining )) {
     51       break;
     52     }
     53 
     54     //
     55     //  Determine the number of bytes to read
     56     //
     57     if ( LengthInBytes > pContext->BytesRemaining ) {
     58       LengthInBytes = pContext->BytesRemaining;
     59     }
     60 
     61     //
     62     //  Read in the next portion of the file
     63     //
     64     BytesRead = fread ( pContext->pFill,
     65                         1,
     66                         (size_t)LengthInBytes,
     67                         pContext->File );
     68     if ( -1 == BytesRead ) {
     69       bReadError = TRUE;
     70       break;
     71     }
     72 
     73     //
     74     //  Account for the file data read
     75     //
     76     pContext->BytesRemaining -= BytesRead;
     77     pContext->ValidBytes += BytesRead;
     78     DEBUG (( DEBUG_FILE_BUFFER,
     79               "0x%08x: Buffer filled with %Ld bytes, %Ld bytes ramaining\r\n",
     80               pContext->pFill,
     81               BytesRead,
     82               pContext->BytesRemaining ));
     83 
     84     //
     85     //  Set the next buffer location
     86     //
     87     pContext->pFill += BytesRead;
     88     if ( pContext->pEnd <= pContext->pFill ) {
     89       pContext->pFill = &pContext->FileData[ 0 ];
     90     }
     91 
     92     //
     93     //  Verify that the end of the buffer is reached
     94     //
     95     ASSERT ( 0 == ( DIM ( pContext->FileData ) & 1 ));
     96     break;
     97   }
     98 
     99   //
    100   //  Return the read status
    101   //
    102   DBG_EXIT ( );
    103   return bReadError;
    104 }
    105 
    106 
    107 /**
    108   Add a connection context to the list of connection contexts.
    109 
    110   @param [in] pTftpServer   Address of the ::TSDT_TFTP_SERVER structure
    111   @param [in] SocketFd      Socket file descriptor
    112 
    113   @retval Context structure address, NULL if allocation fails
    114 
    115 **/
    116 TSDT_CONNECTION_CONTEXT *
    117 ContextAdd (
    118   IN TSDT_TFTP_SERVER * pTftpServer,
    119   IN int SocketFd
    120   )
    121 {
    122   TSDT_CONNECTION_CONTEXT * pContext;
    123   TFTP_PACKET * pEnd;
    124   TFTP_PACKET * pPacket;
    125 
    126   DBG_ENTER ( );
    127 
    128   //
    129   //  Allocate a new context
    130   //
    131   pContext = (TSDT_CONNECTION_CONTEXT *)AllocateZeroPool ( sizeof ( *pContext ));
    132   if ( NULL != pContext ) {
    133     //
    134     //  Initialize the context
    135     //
    136     pContext->SocketFd = SocketFd;
    137     CopyMem ( &pContext->RemoteAddress,
    138               &pTftpServer->RemoteAddress,
    139               sizeof ( pContext->RemoteAddress ));
    140     pContext->BlockSize = 512;
    141 
    142     //
    143     //  Buffer management
    144     //
    145     pContext->pFill = &pContext->FileData[ 0 ];
    146     pContext->pEnd = &pContext->FileData[ sizeof ( pContext->FileData )];
    147     pContext->pBuffer = pContext->pFill;
    148 
    149     //
    150     //  Window management
    151     //
    152     pContext->MaxTimeout = MultU64x32 ( PcdGet32 ( Tftp_MaxTimeoutInSec ),
    153                                         2 * 1000 * 1000 * 1000 );
    154     pContext->Rtt2x = pContext->MaxTimeout;
    155     pContext->WindowSize = MAX_PACKETS;
    156     WindowTimeout ( pContext );
    157 
    158     //
    159     //  Place the packets on the free list
    160     //
    161     pPacket = &pContext->Tx[ 0 ];
    162     pEnd = &pPacket[ DIM ( pContext->Tx )];
    163     while ( pEnd > pPacket ) {
    164       PacketFree ( pContext, pPacket );
    165       pPacket += 1;
    166     }
    167 
    168     //
    169     //  Display the new context
    170     //
    171     if ( AF_INET == pTftpServer->RemoteAddress.v4.sin_family ) {
    172       DEBUG (( DEBUG_PORT_WORK,
    173                 "0x%08x: Context for %d.%d.%d.%d:%d\r\n",
    174                 pContext,
    175                 (UINT8)pTftpServer->RemoteAddress.v4.sin_addr.s_addr,
    176                 (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 8 ),
    177                 (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 16 ),
    178                 (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 24 ),
    179                 htons ( pTftpServer->RemoteAddress.v4.sin_port )));
    180     }
    181     else {
    182       DEBUG (( DEBUG_PORT_WORK,
    183                 "0x%08x: Context for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
    184                 pContext,
    185                 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 0 ],
    186                 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 1 ],
    187                 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 2 ],
    188                 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 3 ],
    189                 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 4 ],
    190                 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 5 ],
    191                 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 6 ],
    192                 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 7 ],
    193                 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 8 ],
    194                 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 9 ],
    195                 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 10 ],
    196                 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 11 ],
    197                 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 12 ],
    198                 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 13 ],
    199                 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 14 ],
    200                 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 15 ],
    201                 htons ( pTftpServer->RemoteAddress.v6.sin6_port )));
    202     }
    203 
    204     //
    205     //  Add the context to the context list
    206     //
    207     pContext->pNext = pTftpServer->pContextList;
    208     pTftpServer->pContextList = pContext;
    209   }
    210 
    211   //
    212   //  Return the connection context
    213   //
    214   DBG_EXIT_STATUS ( pContext );
    215   return pContext;
    216 }
    217 
    218 
    219 /**
    220   Locate a remote connection context.
    221 
    222   @param [in] pTftpServer   Address of the ::TSDT_TFTP_SERVER structure
    223   @param [in] pIpAddress    The start of the remote IP address in network order
    224   @param [in] Port          The remote port number
    225 
    226   @retval Context structure address, NULL if not found
    227 
    228 **/
    229 TSDT_CONNECTION_CONTEXT *
    230 ContextFind (
    231   IN TSDT_TFTP_SERVER * pTftpServer
    232   )
    233 {
    234   TSDT_CONNECTION_CONTEXT * pContext;
    235 
    236   DBG_ENTER ( );
    237 
    238   //
    239   //  Walk the list of connection contexts
    240   //
    241   pContext = pTftpServer->pContextList;
    242   while ( NULL != pContext ) {
    243     //
    244     //  Attempt to locate the remote network connection
    245     //
    246     if ( 0 == memcmp ( &pTftpServer->RemoteAddress,
    247                        &pContext->RemoteAddress,
    248                        pTftpServer->RemoteAddress.v6.sin6_len )) {
    249       //
    250       //  The connection was found
    251       //
    252       DEBUG (( DEBUG_TFTP_REQUEST,
    253                 "0x%08x: pContext found\r\n",
    254                 pContext ));
    255       break;
    256     }
    257 
    258     //
    259     //  Set the next context
    260     //
    261     pContext = pContext->pNext;
    262   }
    263 
    264   //
    265   //  Return the connection context structure address
    266   //
    267   DBG_EXIT_HEX ( pContext );
    268   return pContext;
    269 }
    270 
    271 
    272 /**
    273   Remove a context from the list.
    274 
    275   @param [in] pTftpServer   Address of the ::TSDT_TFTP_SERVER structure
    276   @param [in] pContext      Address of a ::TSDT_CONNECTION_CONTEXT structure
    277 
    278 **/
    279 VOID
    280 ContextRemove (
    281   IN TSDT_TFTP_SERVER * pTftpServer,
    282   IN TSDT_CONNECTION_CONTEXT * pContext
    283   )
    284 {
    285   TSDT_CONNECTION_CONTEXT * pNextContext;
    286   TSDT_CONNECTION_CONTEXT * pPreviousContext;
    287 
    288   DBG_ENTER ( );
    289 
    290   //
    291   //  Attempt to locate the context in the list
    292   //
    293   pPreviousContext = NULL;
    294   pNextContext = pTftpServer->pContextList;
    295   while ( NULL != pNextContext ) {
    296     //
    297     //  Determine if the context was found
    298     //
    299     if ( pNextContext == pContext ) {
    300       //
    301       //  Remove the context from the list
    302       //
    303       if ( NULL == pPreviousContext ) {
    304         pTftpServer->pContextList = pContext->pNext;
    305       }
    306       else {
    307         pPreviousContext->pNext = pContext->pNext;
    308       }
    309       break;
    310     }
    311 
    312     //
    313     //  Set the next context
    314     //
    315     pPreviousContext = pNextContext;
    316     pNextContext = pNextContext->pNext;
    317   }
    318 
    319   //
    320   //  Determine if the context was found
    321   //
    322   if ( NULL != pContext ) {
    323     //
    324     //  Return the resources
    325     //
    326     gBS->FreePool ( pContext );
    327   }
    328 
    329   DBG_EXIT ( );
    330 }
    331 
    332 
    333 /**
    334   Queue data packets for transmission
    335 
    336   @param [in] pContext    Connection context structure address
    337 
    338   @retval TRUE if a read error occurred
    339 
    340 **/
    341 BOOLEAN
    342 PacketFill (
    343   IN TSDT_CONNECTION_CONTEXT * pContext
    344   )
    345 {
    346   BOOLEAN bReadError;
    347   UINT64 LengthInBytes;
    348   UINT8 * pBuffer;
    349   TFTP_PACKET * pPacket;
    350 
    351   DBG_ENTER ( );
    352 
    353   //
    354   //  Use break instead of goto
    355   //
    356   bReadError = FALSE;
    357   for ( ; ; ) {
    358     //
    359     //  Fill the buffer if necessary
    360     //
    361     bReadError = BufferFill ( pContext );
    362     if ( bReadError ) {
    363       //
    364       //  File access mode not supported
    365       //
    366       DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST,
    367                 "ERROR - File read failure!\r\n" ));
    368 
    369       //
    370       //  Tell the client of the error
    371       //
    372       SendError ( pContext,
    373                   TFTP_ERROR_SEE_MSG,
    374                   (UINT8 *)"Read failure" );
    375       break;
    376     }
    377 
    378     //
    379     //  Determine if any packets can be filled
    380     //
    381     if ( pContext->bEofSent
    382       || ( NULL == pContext->pFreeList )) {
    383       //
    384       //  All of the packets are filled
    385       //
    386       break;
    387     }
    388 
    389     //
    390     //  Set the TFTP opcode and block number
    391     //
    392     pPacket = PacketGet ( pContext );
    393     pBuffer = &pPacket->TxBuffer[ 0 ];
    394     *pBuffer++ = 0;
    395     *pBuffer++ = TFTP_OP_DATA;
    396     *pBuffer++ = (UINT8)( pContext->BlockNumber >> 8 );
    397     *pBuffer++ = (UINT8)pContext->BlockNumber;
    398 
    399     //
    400     //  Determine how much data needs to be sent
    401     //
    402     LengthInBytes = pContext->BlockSize;
    403     if (( pContext->BytesToSend < TFTP_MAX_BLOCK_SIZE )
    404       && ( LengthInBytes > pContext->BytesToSend )) {
    405       LengthInBytes = pContext->BytesToSend;
    406       pContext->bEofSent = TRUE;
    407     }
    408     DEBUG (( DEBUG_TX_PACKET,
    409               "0x%08x: Packet, Block %d filled with %d bytes\r\n",
    410               pPacket,
    411               pContext->BlockNumber,
    412               (UINT32)LengthInBytes ));
    413 
    414     //
    415     //  Copy the file data into the packet
    416     //
    417     pPacket->TxBytes = (ssize_t)( 2 + 2 + LengthInBytes );
    418     if ( 0 < LengthInBytes ) {
    419       CopyMem ( pBuffer,
    420                 pContext->pBuffer,
    421                 (UINTN)LengthInBytes );
    422       DEBUG (( DEBUG_FILE_BUFFER,
    423                 "0x%08x: Buffer consumed %d bytes of file data\r\n",
    424                 pContext->pBuffer,
    425                 LengthInBytes ));
    426 
    427       //
    428       //  Account for the file data consumed
    429       //
    430       pContext->ValidBytes -= LengthInBytes;
    431       pContext->BytesToSend -= LengthInBytes;
    432       pContext->pBuffer += LengthInBytes;
    433       if ( pContext->pEnd <= pContext->pBuffer ) {
    434         pContext->pBuffer = &pContext->FileData[ 0 ];
    435       }
    436     }
    437 
    438     //
    439     //  Queue the packet for transmission
    440     //
    441     PacketQueue ( pContext, pPacket );
    442   }
    443 
    444   //
    445   //  Return the read status
    446   //
    447   DBG_EXIT ( );
    448   return bReadError;
    449 }
    450 
    451 
    452 /**
    453   Free the packet
    454 
    455   @param [in] pContext    Address of a ::TSDT_CONNECTION_CONTEXT structure
    456   @param [in] pPacket     Address of a ::TFTP_PACKET structure
    457 
    458 **/
    459 VOID
    460 PacketFree(
    461   IN TSDT_CONNECTION_CONTEXT * pContext,
    462   IN TFTP_PACKET * pPacket
    463   )
    464 {
    465   DBG_ENTER ( );
    466 
    467   //
    468   //  Don't free the error packet
    469   //
    470   if ( pPacket != &pContext->ErrorPacket ) {
    471     //
    472     //  Place the packet on the free list
    473     //
    474     pPacket->pNext = pContext->pFreeList;
    475     pContext->pFreeList = pPacket;
    476     DEBUG (( DEBUG_TX_PACKET,
    477               "0x%08x: Packet queued to free list\r\n",
    478               pPacket ));
    479   }
    480 
    481   DBG_EXIT ( );
    482 }
    483 
    484 
    485 /**
    486   Get a packet from the free list for transmission
    487 
    488   @param [in] pContext    Address of a ::TSDT_CONNECTION_CONTEXT structure
    489 
    490   @retval Address of a ::TFTP_PACKET structure
    491 
    492 **/
    493 TFTP_PACKET *
    494 PacketGet (
    495   IN TSDT_CONNECTION_CONTEXT * pContext
    496   )
    497 {
    498   TFTP_PACKET * pPacket;
    499 
    500   DBG_ENTER ( );
    501 
    502   //
    503   //  Get the next packet from the free list
    504   //
    505   pPacket = pContext->pFreeList;
    506   if ( NULL != pPacket ) {
    507     pContext->pFreeList = pPacket->pNext;
    508     pPacket->RetryCount = 0;
    509     DEBUG (( DEBUG_TX_PACKET,
    510               "0x%08x: Packet removed from free list\r\n",
    511               pPacket ));
    512   }
    513 
    514   //
    515   //  Return the packet
    516   //
    517   DBG_EXIT_HEX ( pPacket );
    518   return pPacket;
    519 }
    520 
    521 
    522 /**
    523   Queue the packet for transmission
    524 
    525   @param [in] pContext    Address of a ::TSDT_CONNECTION_CONTEXT structure
    526   @param [in] pPacket     Address of a ::TFTP_PACKET structure
    527 
    528   @retval TRUE if a transmission error has occurred
    529 
    530 **/
    531 BOOLEAN
    532 PacketQueue (
    533   IN TSDT_CONNECTION_CONTEXT * pContext,
    534   IN TFTP_PACKET * pPacket
    535   )
    536 {
    537   BOOLEAN bTransmitError;
    538   TFTP_PACKET * pTail;
    539   EFI_STATUS Status;
    540 
    541   DBG_ENTER ( );
    542 
    543   //
    544   //  Account for this data block
    545   //
    546   pPacket->BlockNumber = pContext->BlockNumber;
    547   pContext->BlockNumber += 1;
    548 
    549   //
    550   //  Queue the packet for transmission
    551   //
    552   pTail = pContext->pTxTail;
    553   if ( NULL == pTail ) {
    554     pContext->pTxHead = pPacket;
    555   }
    556   else {
    557     pTail->pNext = pPacket;
    558   }
    559   pContext->pTxTail = pPacket;
    560   pPacket->pNext = NULL;
    561   DEBUG (( DEBUG_TX_PACKET,
    562             "0x%08x: Packet queued to TX list\r\n",
    563             pPacket ));
    564 
    565   //
    566   //  Start the transmission if necessary
    567   //
    568   bTransmitError = FALSE;
    569   if ( pContext->PacketsInWindow < pContext->WindowSize ) {
    570     Status = PacketTx ( pContext, pPacket );
    571     bTransmitError = (BOOLEAN)( EFI_ERROR ( Status ));
    572   }
    573 
    574   //
    575   //  Return the transmit status
    576   //
    577   DBG_EXIT_TF ( bTransmitError );
    578   return bTransmitError;
    579 }
    580 
    581 
    582 /**
    583   Remove a packet from the transmit queue
    584 
    585   @param [in] pContext    Address of a ::TSDT_CONNECTION_CONTEXT structure
    586 
    587 **/
    588 TFTP_PACKET *
    589 PacketRemove(
    590   IN TSDT_CONNECTION_CONTEXT * pContext
    591   )
    592 {
    593   TFTP_PACKET * pNext;
    594   TFTP_PACKET * pPacket;
    595 
    596   DBG_ENTER ( );
    597 
    598   //
    599   //  Remove a packet from the transmit queue
    600   //
    601   //
    602   pPacket = pContext->pTxHead;
    603   if ( NULL != pPacket ) {
    604     pNext = pPacket->pNext;
    605     pContext->pTxHead = pNext;
    606     if ( NULL == pNext ) {
    607       pContext->pTxTail = NULL;
    608     }
    609     DEBUG (( DEBUG_TX_PACKET,
    610               "0x%08x: Packet removed from TX list\r\n",
    611               pPacket ));
    612 
    613     //
    614     //  Remove this packet from the window
    615     //
    616     pContext->PacketsInWindow -= 1;
    617   }
    618 
    619   //
    620   //  Return the packet
    621   //
    622   DBG_EXIT_HEX ( pPacket );
    623   return pPacket;
    624 }
    625 
    626 
    627 /**
    628   Transmit the packet
    629 
    630   @param [in] pContext    Address of a ::TSDT_CONNECTION_CONTEXT structure
    631   @param [in] pPacket     Address of a ::TFTP_PACKET structure
    632 
    633   @retval EFI_SUCCESS   Message processed successfully
    634 
    635 **/
    636 EFI_STATUS
    637 PacketTx (
    638   IN TSDT_CONNECTION_CONTEXT * pContext,
    639   IN TFTP_PACKET * pPacket
    640   )
    641 {
    642   ssize_t LengthInBytes;
    643   EFI_STATUS Status;
    644 
    645   DBG_ENTER ( );
    646 
    647   //
    648   //  Assume success
    649   //
    650   Status = EFI_SUCCESS;
    651 
    652   //
    653   //  Determine if this packet should be transmitted
    654   //
    655   if ( PcdGet32 ( Tftp_MaxRetry ) >= pPacket->RetryCount ) {
    656     pPacket->RetryCount += 1;
    657 
    658     //
    659     //  Display the operation
    660     //
    661     DEBUG (( DEBUG_TX_PACKET,
    662               "0x%08x: Packet transmiting\r\n",
    663               pPacket ));
    664     DEBUG (( DEBUG_TX,
    665               "0x%08x: pContext sending 0x%08x bytes\r\n",
    666               pContext,
    667               pPacket->TxBytes ));
    668 
    669     //
    670     //  Keep track of when the packet was transmitted
    671     //
    672     if ( PcdGetBool ( Tftp_HighSpeed )) {
    673       pPacket->TxTime = GetPerformanceCounter ( );
    674     }
    675 
    676     //
    677     //  Send the TFTP packet
    678     //
    679     pContext->PacketsInWindow += 1;
    680     LengthInBytes = sendto ( pContext->SocketFd,
    681                              &pPacket->TxBuffer[ 0 ],
    682                              pPacket->TxBytes,
    683                              0,
    684                              (struct sockaddr *)&pContext->RemoteAddress,
    685                              pContext->RemoteAddress.sin6_len );
    686     if ( -1 == LengthInBytes ) {
    687       DEBUG (( DEBUG_ERROR | DEBUG_TX,
    688                 "ERROR - Transmit failure, errno: 0x%08x\r\n",
    689                 errno ));
    690       pContext->PacketsInWindow -= 1;
    691       Status = EFI_DEVICE_ERROR;
    692     }
    693   }
    694   else {
    695     //
    696     //  Too many retries
    697     //
    698     Status = EFI_NO_RESPONSE;
    699     DEBUG (( DEBUG_WARN | DEBUG_WINDOW,
    700               "WARNING - No response from TFTP client\r\n" ));
    701   }
    702 
    703   //
    704   //  Return the operation status
    705   //
    706   DBG_EXIT_STATUS ( Status );
    707   return Status;
    708 }
    709 
    710 
    711 /**
    712   Process the work for the sockets.
    713 
    714   @param [in] pTftpServer   Address of the ::TSDT_TFTP_SERVER structure
    715   @param [in] pIndex        Address of an index into the pollfd array
    716 
    717 **/
    718 VOID
    719 PortWork (
    720   IN TSDT_TFTP_SERVER * pTftpServer,
    721   IN int * pIndex
    722   )
    723 {
    724   int Index;
    725   TSDT_CONNECTION_CONTEXT * pContext;
    726   struct pollfd * pTftpPort;
    727   socklen_t RemoteAddressLength;
    728   int revents;
    729 
    730   DBG_ENTER ( );
    731 
    732   //
    733   //  Locate the port
    734   //
    735   Index = *pIndex;
    736   if ( -1 != Index ) {
    737     pTftpPort = &pTftpServer->TftpPort[ *pIndex ];
    738 
    739     //
    740     //  Handle input events
    741     //
    742     revents = pTftpPort->revents;
    743     pTftpPort->revents = 0;
    744     if ( 0 != ( revents & POLLRDNORM )) {
    745       //
    746       //  Receive the message from the remote system
    747       //
    748       RemoteAddressLength = sizeof ( pTftpServer->RemoteAddress );
    749       pTftpServer->RxBytes = recvfrom ( pTftpPort->fd,
    750                                         &pTftpServer->RxBuffer[ 0 ],
    751                                         sizeof ( pTftpServer->RxBuffer ),
    752                                         0,
    753                                         (struct sockaddr *) &pTftpServer->RemoteAddress,
    754                                         &RemoteAddressLength );
    755       if ( -1 != pTftpServer->RxBytes ) {
    756         if ( PcdGetBool ( Tftp_HighSpeed )) {
    757           pTftpServer->RxTime = GetPerformanceCounter ( );
    758         }
    759         if ( AF_INET == pTftpServer->RemoteAddress.v4.sin_family ) {
    760           DEBUG (( DEBUG_TFTP_PORT,
    761                    "Received %d bytes from %d.%d.%d.%d:%d\r\n",
    762                    pTftpServer->RxBytes,
    763                    pTftpServer->RemoteAddress.v4.sin_addr.s_addr & 0xff,
    764                    ( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 8 ) & 0xff,
    765                    ( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 16 ) & 0xff,
    766                    ( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 24 ) & 0xff,
    767                    htons ( pTftpServer->RemoteAddress.v4.sin_port )));
    768         }
    769         else {
    770           DEBUG (( DEBUG_TFTP_PORT,
    771                    "Received %d bytes from [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
    772                    pTftpServer->RxBytes,
    773                    pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 0 ],
    774                    pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 1 ],
    775                    pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 2 ],
    776                    pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 3 ],
    777                    pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 4 ],
    778                    pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 5 ],
    779                    pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 6 ],
    780                    pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 7 ],
    781                    pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 8 ],
    782                    pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 9 ],
    783                    pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 10 ],
    784                    pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 11 ],
    785                    pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 12 ],
    786                    pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 13 ],
    787                    pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 14 ],
    788                    pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 15 ],
    789                    htons ( pTftpServer->RemoteAddress.v6.sin6_port )));
    790         }
    791 
    792         //
    793         //  Lookup connection context using the remote system address and port
    794         //  to determine if an existing connection to this remote
    795         //  system exists
    796         //
    797         pContext = ContextFind ( pTftpServer );
    798 
    799         //
    800         //  Process the received message
    801         //
    802         TftpProcessRequest ( pTftpServer, pContext, pTftpPort->fd );
    803       }
    804       else {
    805         //
    806         //  Receive error on the TFTP server port
    807         //  Close the server socket
    808         //
    809         DEBUG (( DEBUG_ERROR,
    810                   "ERROR - Failed receive on TFTP server port, errno: 0x%08x\r\n",
    811                   errno ));
    812         revents |= POLLHUP;
    813       }
    814     }
    815 
    816     //
    817     //  Handle the close event
    818     //
    819     if ( 0 != ( revents & POLLHUP )) {
    820       //
    821       //  Close the port
    822       //
    823       close ( pTftpPort->fd );
    824       pTftpPort->fd = -1;
    825       *pIndex = -1;
    826       pTftpServer->Entries -= 1;
    827       ASSERT ( 0 <= pTftpServer->Entries );
    828     }
    829   }
    830 
    831   DBG_EXIT ( );
    832 }
    833 
    834 
    835 /**
    836   Build and send an error packet
    837 
    838   @param [in] pContext    Address of a ::TSDT_CONNECTION_CONTEXT structure
    839   @param [in] Error       Error number for the packet
    840   @param [in] pError      Zero terminated error string address
    841 
    842   @retval EFI_SUCCESS     Message processed successfully
    843 
    844 **/
    845 EFI_STATUS
    846 SendError (
    847   IN TSDT_CONNECTION_CONTEXT * pContext,
    848   IN UINT16 Error,
    849   IN UINT8 * pError
    850   )
    851 {
    852   UINT8 Character;
    853   UINT8 * pBuffer;
    854   TFTP_PACKET * pPacket;
    855   EFI_STATUS Status;
    856 
    857   DBG_ENTER ( );
    858 
    859   //
    860   //  Build the error packet
    861   //
    862   pPacket = &pContext->ErrorPacket;
    863   pBuffer = &pPacket->TxBuffer[ 0 ];
    864   pBuffer[ 0 ] = 0;
    865   pBuffer[ 1 ] = TFTP_OP_ERROR;
    866   pBuffer[ 2 ] = (UINT8)( Error >> 8 );
    867   pBuffer[ 3 ] = (UINT8)Error;
    868 
    869   //
    870   //  Copy the zero terminated string into the buffer
    871   //
    872   pBuffer += 4;
    873   do {
    874     Character = *pError++;
    875     *pBuffer++ = Character;
    876   } while ( 0 != Character );
    877 
    878   //
    879   //  Send the error message
    880   //
    881   pPacket->TxBytes = pBuffer - &pPacket->TxBuffer[ 0 ];
    882   Status = PacketTx ( pContext, pPacket );
    883 
    884   //
    885   //  Return the operation status
    886   //
    887   DBG_EXIT_STATUS ( Status );
    888   return Status;
    889 }
    890 
    891 
    892 /**
    893   Scan the list of sockets and process any pending work
    894 
    895   @param [in] pTftpServer   Address of the ::TSDT_TFTP_SERVER structure
    896 
    897 **/
    898 VOID
    899 SocketPoll (
    900   IN TSDT_TFTP_SERVER * pTftpServer
    901   )
    902 {
    903   int FDCount;
    904 
    905   DEBUG (( DEBUG_SOCKET_POLL, "Entering SocketPoll\r\n" ));
    906 
    907   //
    908   //  Determine if any ports are active
    909   //
    910   if ( 0 != pTftpServer->Entries ) {
    911     FDCount = poll ( &pTftpServer->TftpPort[ 0 ],
    912                      pTftpServer->Entries,
    913                      CLIENT_POLL_DELAY );
    914     if ( 0 < FDCount ) {
    915       //
    916       //  Process this port
    917       //
    918       PortWork ( pTftpServer, &pTftpServer->Udpv4Index );
    919       PortWork ( pTftpServer, &pTftpServer->Udpv6Index );
    920     }
    921   }
    922 
    923   DEBUG (( DEBUG_SOCKET_POLL, "Exiting SocketPoll\r\n" ));
    924 }
    925 
    926 
    927 /**
    928   Process the ACK
    929 
    930   @param [in] pTftpServer   Address of the ::TSDT_TFTP_SERVER structure
    931   @param [in] pContext    Connection context structure address
    932 
    933   @retval TRUE if the context should be closed
    934 
    935 **/
    936 BOOLEAN
    937 TftpAck (
    938   IN TSDT_TFTP_SERVER * pTftpServer,
    939   IN TSDT_CONNECTION_CONTEXT * pContext
    940   )
    941 {
    942   INTN AckNumber;
    943   BOOLEAN bCloseContext;
    944   UINT16 BlockNumber;
    945   UINT8 * pBuffer;
    946   TFTP_PACKET * pPacket;
    947   EFI_STATUS Status;
    948 
    949   DBG_ENTER ( );
    950 
    951   //
    952   //  Use break instead of goto
    953   //
    954   bCloseContext = FALSE;
    955   for ( ; ; ) {
    956     //
    957     //  Validate the parameters
    958     //
    959     if ( NULL == pContext ) {
    960       if ( AF_INET == pTftpServer->RemoteAddress.v4.sin_family ) {
    961         DEBUG (( DEBUG_ERROR,
    962                   "ERROR - File not open for %d.%d.%d.%d:%d\r\n",
    963                   (UINT8)pTftpServer->RemoteAddress.v4.sin_addr.s_addr,
    964                   (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 8 ),
    965                   (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 16 ),
    966                   (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 24 ),
    967                   htons ( pTftpServer->RemoteAddress.v4.sin_port )));
    968       }
    969       else {
    970         DEBUG (( DEBUG_ERROR,
    971                   "ERROR - File not open for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
    972                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 0 ],
    973                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 1 ],
    974                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 2 ],
    975                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 3 ],
    976                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 4 ],
    977                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 5 ],
    978                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 6 ],
    979                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 7 ],
    980                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 8 ],
    981                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 9 ],
    982                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 10 ],
    983                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 11 ],
    984                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 12 ],
    985                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 13 ],
    986                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 14 ],
    987                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 15 ],
    988                   htons ( pTftpServer->RemoteAddress.v6.sin6_port )));
    989       }
    990       break;
    991     }
    992 
    993     //
    994     //  Verify that the ACK was expected
    995     //
    996     pPacket = pContext->pTxHead;
    997     if ( NULL == pPacket ) {
    998       //
    999       //  ACK not expected!
   1000       //
   1001       DEBUG (( DEBUG_ERROR,
   1002                 "ERROR - Expecting data not ACKs for pContext 0x%08x\r\n",
   1003                 pContext ));
   1004       break;
   1005     }
   1006 
   1007     //
   1008     //  Get the ACKed block number
   1009     //
   1010     pBuffer = &pTftpServer->RxBuffer[ 0 ];
   1011     BlockNumber = HTONS ( *(UINT16 *)&pBuffer[ 2 ]);
   1012 
   1013     //
   1014     //  Determine if this is the correct ACK
   1015     //
   1016     DEBUG (( DEBUG_TFTP_ACK,
   1017               "ACK for block 0x%04x received\r\n",
   1018               BlockNumber ));
   1019     AckNumber = BlockNumber - pPacket->BlockNumber;
   1020     if (( 0 > AckNumber ) || ( AckNumber >= (INTN)pContext->PacketsInWindow )){
   1021       DEBUG (( DEBUG_WARN | DEBUG_TFTP_ACK,
   1022                 "WARNING - Expecting ACK 0x%0x4 not received ACK 0x%08x\r\n",
   1023                 pPacket->BlockNumber,
   1024                 BlockNumber ));
   1025       break;
   1026     }
   1027 
   1028     //
   1029     //  Release the ACKed packets
   1030     //
   1031     do {
   1032       //
   1033       //  Remove the packet from the transmit list and window
   1034       //
   1035       pPacket = PacketRemove ( pContext );
   1036 
   1037       //
   1038       //  Get the block number of this packet
   1039       //
   1040       AckNumber = pPacket->BlockNumber;
   1041 
   1042       //
   1043       //  Increase the size of the transmit window
   1044       //
   1045       if ( PcdGetBool ( Tftp_HighSpeed )
   1046         && ( AckNumber == BlockNumber )) {
   1047         WindowAck ( pTftpServer, pContext, pPacket );
   1048       }
   1049 
   1050       //
   1051       //  Free this packet
   1052       //
   1053       PacketFree ( pContext, pPacket );
   1054     } while (( NULL != pContext->pTxHead ) && ( AckNumber != BlockNumber ));
   1055 
   1056     //
   1057     //  Fill the window with packets
   1058     //
   1059     pPacket = pContext->pTxHead;
   1060     while (( NULL != pPacket )
   1061       && ( pContext->PacketsInWindow < pContext->WindowSize )
   1062       && ( !bCloseContext )) {
   1063       Status = PacketTx ( pContext, pPacket );
   1064       bCloseContext = (BOOLEAN)( EFI_ERROR ( Status ));
   1065       pPacket = pPacket->pNext;
   1066     }
   1067 
   1068     //
   1069     //  Get more packets ready for transmission
   1070     //
   1071     PacketFill ( pContext );
   1072 
   1073     //
   1074     //  Close the context when the last packet is ACKed
   1075     //
   1076     if ( 0 == pContext->PacketsInWindow ) {
   1077       bCloseContext = TRUE;
   1078 
   1079       //
   1080       //  Display the bandwidth
   1081       //
   1082       if ( PcdGetBool ( Tftp_Bandwidth )) {
   1083         UINT64 Bandwidth;
   1084         UINT64 DeltaTime;
   1085         UINT64 NanoSeconds;
   1086         UINT32 Value;
   1087 
   1088         //
   1089         //  Compute the download time
   1090         //
   1091         DeltaTime = GetPerformanceCounter ( );
   1092         if ( pTftpServer->Time2 > pTftpServer->Time1 ) {
   1093           DeltaTime = DeltaTime - pContext->TimeStart;
   1094         }
   1095         else {
   1096           DeltaTime = pContext->TimeStart - DeltaTime;
   1097         }
   1098         NanoSeconds = GetTimeInNanoSecond ( DeltaTime );
   1099         Bandwidth = pContext->LengthInBytes;
   1100         DEBUG (( DEBUG_WINDOW,
   1101                   "File Length %Ld, Transfer Time: %d.%03d Sec\r\n",
   1102                   Bandwidth,
   1103                   DivU64x32 ( NanoSeconds, 1000 * 1000 * 1000 ),
   1104                   ((UINT32)DivU64x32 ( NanoSeconds, 1000 * 1000 )) % 1000 ));
   1105 
   1106         //
   1107         //  Display the round trip time
   1108         //
   1109         Bandwidth = MultU64x32 ( Bandwidth, 8 * 1000 * 1000 );
   1110         Bandwidth /= NanoSeconds;
   1111         if ( 1000 > Bandwidth ) {
   1112           Value = (UINT32)Bandwidth;
   1113           Print ( L"Bandwidth: %d Kbits/Sec\r\n",
   1114                   Value );
   1115         }
   1116         else if (( 1000 * 1000 ) > Bandwidth ) {
   1117           Value = (UINT32)Bandwidth;
   1118           Print ( L"Bandwidth: %d.%03d Mbits/Sec\r\n",
   1119                   Value / 1000,
   1120                   Value % 1000 );
   1121         }
   1122         else {
   1123           Value = (UINT32)DivU64x32 ( Bandwidth, 1000 );
   1124           Print ( L"Bandwidth: %d.%03d Gbits/Sec\r\n",
   1125                   Value / 1000,
   1126                   Value % 1000 );
   1127         }
   1128       }
   1129     }
   1130     break;
   1131   }
   1132 
   1133   //
   1134   //  Return the operation status
   1135   //
   1136   DBG_EXIT ( );
   1137   return bCloseContext;
   1138 }
   1139 
   1140 
   1141 /**
   1142   Get the next TFTP option
   1143 
   1144   @param [in] pOption       Address of a zero terminated option string
   1145   @param [in] pEnd          End of buffer address
   1146   @param [in] ppNextOption  Address to receive the address of the next
   1147                             zero terminated option string
   1148 
   1149   @retval EFI_SUCCESS   Message processed successfully
   1150 
   1151 **/
   1152 EFI_STATUS
   1153 TftpOptionGet (
   1154   IN UINT8 * pOption,
   1155   IN UINT8 * pEnd,
   1156   IN UINT8 ** ppNextOption
   1157   )
   1158 {
   1159   UINT8 * pNextOption;
   1160   EFI_STATUS Status;
   1161 
   1162   //
   1163   //  Locate the end of the option
   1164   //
   1165   pNextOption = pOption;
   1166   while (( pEnd > pNextOption ) && ( 0 != *pNextOption )) {
   1167     pNextOption += 1;
   1168   }
   1169   if ( pEnd <= pNextOption ) {
   1170     //
   1171     //  Error - end of buffer reached
   1172     //
   1173     DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST,
   1174               "ERROR - Option without zero termination received!\r\n" ));
   1175     Status = EFI_INVALID_PARAMETER;
   1176   }
   1177   else {
   1178     //
   1179     //  Zero terminated option found
   1180     //
   1181     pNextOption += 1;
   1182 
   1183     //
   1184     //  Display the zero terminated ASCII option string
   1185     //
   1186     DEBUG (( DEBUG_TFTP_REQUEST,
   1187               "Option: %a\r\n",
   1188               pOption ));
   1189     Status = EFI_SUCCESS;
   1190   }
   1191 
   1192   //
   1193   //  Return the next option address
   1194   //
   1195   *ppNextOption = pNextOption;
   1196 
   1197   //
   1198   //  Return the operation status
   1199   //
   1200   return Status;
   1201 }
   1202 
   1203 
   1204 /**
   1205   Place an option value into the option acknowledgement
   1206 
   1207   @param [in] pOack     Option acknowledgement address
   1208   @param [in] Value     Value to translate into ASCII decimal
   1209 
   1210   @return               Option acknowledgement address
   1211 
   1212 **/
   1213 UINT8 *
   1214 TftpOptionSet (
   1215   IN UINT8 * pOack,
   1216   IN UINT64 Value
   1217   )
   1218 {
   1219   UINT64 NextValue;
   1220 
   1221   //
   1222   //  Determine the next value
   1223   //
   1224   NextValue = Value / 10;
   1225 
   1226   //
   1227   //  Supress leading zeros
   1228   //
   1229   if ( 0 != NextValue ) {
   1230     pOack = TftpOptionSet ( pOack, NextValue );
   1231   }
   1232 
   1233   //
   1234   //  Output this digit
   1235   //
   1236   *pOack++ = (UINT8)( Value - ( NextValue * 10 ) + '0' );
   1237 
   1238   //
   1239   //  Return the next option acknowledgement location
   1240   //
   1241   return pOack;
   1242 }
   1243 
   1244 
   1245 /**
   1246   Process the TFTP request
   1247 
   1248   @param [in] pContext  Address of a ::TSDT_CONNECTION_CONTEXT structure
   1249   @param [in] pOption   Address of the first zero terminated option string
   1250   @param [in] pEnd      End of buffer address
   1251 
   1252 **/
   1253 VOID
   1254 TftpOptions (
   1255   IN TSDT_CONNECTION_CONTEXT * pContext,
   1256   IN UINT8 * pOption,
   1257   IN UINT8 * pEnd
   1258   )
   1259 {
   1260   UINT8 * pNextOption;
   1261   UINT8 * pOack;
   1262   TFTP_PACKET * pPacket;
   1263   UINT8 * pTemp;
   1264   UINT8 * pValue;
   1265   EFI_STATUS Status;
   1266   INT32 Value;
   1267 
   1268   //
   1269   //  Get a packet
   1270   //
   1271   pPacket = PacketGet ( pContext );
   1272 
   1273   //
   1274   //  Start the OACK packet
   1275   //  Let the OACK handle the parsing errors
   1276   //  See http://tools.ietf.org/html/rfc2347
   1277   //
   1278   pOack = &pPacket->TxBuffer[ 0 ];
   1279   *pOack++ = 0;
   1280   *pOack++ = TFTP_OP_OACK;
   1281   pPacket->TxBytes = 2;
   1282   pPacket->BlockNumber = 0;
   1283 
   1284   //
   1285   //  Walk the list of options
   1286   //
   1287   do {
   1288     //
   1289     //  Get the next option, skip junk at end of message
   1290     //
   1291     Status = TftpOptionGet ( pOption, pEnd, &pNextOption );
   1292     if ( !EFI_ERROR ( Status )) {
   1293       //
   1294       //  Process the option
   1295       //
   1296 
   1297       //
   1298       //  blksize - See http://tools.ietf.org/html/rfc2348
   1299       //
   1300       pValue = pNextOption;
   1301       if ( 0 == strcasecmp ((char *)pOption, "blksize" )) {
   1302         //
   1303         //  Get the value
   1304         //
   1305         Status = TftpOptionGet ( pValue, pEnd, &pNextOption );
   1306         if ( !EFI_ERROR ( Status )) {
   1307           //
   1308           //  Validate the block size, skip non-numeric block sizes
   1309           //
   1310           Status = TftpOptionValue ( pValue, &Value );
   1311           if ( !EFI_ERROR ( Status )) {
   1312             //
   1313             //  Propose a smaller block size if necessary
   1314             //
   1315             if ( Value > TFTP_MAX_BLOCK_SIZE ) {
   1316               Value = TFTP_MAX_BLOCK_SIZE;
   1317             }
   1318 
   1319             //
   1320             //  Set the new block size
   1321             //
   1322             pContext->BlockSize = Value;
   1323             DEBUG (( DEBUG_TFTP_REQUEST,
   1324                       "Using block size of %d bytes\r\n",
   1325                       pContext->BlockSize ));
   1326 
   1327             //
   1328             //  Update the OACK
   1329             //
   1330             pTemp = pOack;
   1331             *pOack++ = 'b';
   1332             *pOack++ = 'l';
   1333             *pOack++ = 'k';
   1334             *pOack++ = 's';
   1335             *pOack++ = 'i';
   1336             *pOack++ = 'z';
   1337             *pOack++ = 'e';
   1338             *pOack++ = 0;
   1339             pOack = TftpOptionSet ( pOack, pContext->BlockSize );
   1340             *pOack++ = 0;
   1341             pPacket->TxBytes += pOack - pTemp;
   1342           }
   1343         }
   1344       }
   1345 
   1346       //
   1347       //  timeout - See http://tools.ietf.org/html/rfc2349
   1348       //
   1349       else if ( 0 == strcasecmp ((char *)pOption, "timeout" )) {
   1350         //
   1351         //  Get the value
   1352         //
   1353         Status = TftpOptionGet ( pValue, pEnd, &pNextOption );
   1354         if ( !EFI_ERROR ( Status )) {
   1355           Status = TftpOptionValue ( pValue, &Value );
   1356           if ( !EFI_ERROR ( Status )) {
   1357             //
   1358             //  Set the timeout value
   1359             //
   1360             pContext->MaxTimeout = Value;
   1361             DEBUG (( DEBUG_TFTP_REQUEST,
   1362                       "Using timeout of %d seconds\r\n",
   1363                       pContext->MaxTimeout ));
   1364 
   1365             //
   1366             //  Update the OACK
   1367             //
   1368             pTemp = pOack;
   1369             *pOack++ = 't';
   1370             *pOack++ = 'i';
   1371             *pOack++ = 'm';
   1372             *pOack++ = 'e';
   1373             *pOack++ = 'o';
   1374             *pOack++ = 'u';
   1375             *pOack++ = 't';
   1376             *pOack++ = 0;
   1377             pOack = TftpOptionSet ( pOack, pContext->MaxTimeout );
   1378             *pOack++ = 0;
   1379             pPacket->TxBytes += pOack - pTemp;
   1380           }
   1381         }
   1382       }
   1383 
   1384       //
   1385       //  tsize - See http://tools.ietf.org/html/rfc2349
   1386       //
   1387       else if ( 0 == strcasecmp ((char *)pOption, "tsize" )) {
   1388         //
   1389         //  Get the value
   1390         //
   1391         Status = TftpOptionGet ( pValue, pEnd, &pNextOption );
   1392         if ( !EFI_ERROR ( Status )) {
   1393           Status = TftpOptionValue ( pValue, &Value );
   1394           if ( !EFI_ERROR ( Status )) {
   1395             //
   1396             //  Return the file size
   1397             //
   1398             DEBUG (( DEBUG_TFTP_REQUEST,
   1399                       "Returning file size of %Ld bytes\r\n",
   1400                       pContext->LengthInBytes ));
   1401 
   1402             //
   1403             //  Update the OACK
   1404             //
   1405             pTemp = pOack;
   1406             *pOack++ = 't';
   1407             *pOack++ = 's';
   1408             *pOack++ = 'i';
   1409             *pOack++ = 'z';
   1410             *pOack++ = 'e';
   1411             *pOack++ = 0;
   1412             pOack = TftpOptionSet ( pOack, pContext->LengthInBytes );
   1413             *pOack++ = 0;
   1414             pPacket->TxBytes += pOack - pTemp;
   1415           }
   1416         }
   1417       }
   1418       else {
   1419         //
   1420         //  Unknown option - Ignore it
   1421         //
   1422         DEBUG (( DEBUG_WARN | DEBUG_TFTP_REQUEST,
   1423                   "WARNING - Skipping unknown option: %a\r\n",
   1424                   pOption ));
   1425       }
   1426     }
   1427 
   1428     //
   1429     //  Set the next option
   1430     //
   1431     pOption = pNextOption;
   1432   } while ( pEnd > pOption );
   1433 
   1434   //
   1435   //  Transmit the OACK if necessary
   1436   //
   1437   if ( 2 < pPacket->TxBytes ) {
   1438     PacketQueue ( pContext, pPacket );
   1439   }
   1440   else {
   1441     PacketFree ( pContext, pPacket );
   1442   }
   1443 }
   1444 
   1445 
   1446 /**
   1447   Process the TFTP request
   1448 
   1449   @param [in] pOption   Address of the first zero terminated option string
   1450   @param [in] pValue    Address to receive the value
   1451 
   1452   @retval EFI_SUCCESS   Option translated into a value
   1453 
   1454 **/
   1455 EFI_STATUS
   1456 TftpOptionValue (
   1457   IN UINT8 * pOption,
   1458   IN INT32 * pValue
   1459   )
   1460 {
   1461   UINT8 Digit;
   1462   EFI_STATUS Status;
   1463   INT32 Value;
   1464 
   1465   //
   1466   //  Assume success
   1467   //
   1468   Status = EFI_SUCCESS;
   1469 
   1470   //
   1471   //  Walk the characters in the option
   1472   //
   1473   Value = 0;
   1474   while ( 0 != *pOption ) {
   1475     //
   1476     //  Convert the next digit to binary
   1477     //
   1478     Digit = *pOption++;
   1479     if (( '0' <= Digit ) && ( '9' >= Digit )) {
   1480       Value *= 10;
   1481       Value += Digit - '0';
   1482     }
   1483     else {
   1484       DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST,
   1485                 "ERROR - Invalid character '0x%02x' in the value\r\n",
   1486                 Digit ));
   1487       Status = EFI_INVALID_PARAMETER;
   1488       break;
   1489     }
   1490   }
   1491 
   1492   //
   1493   //  Return the value
   1494   //
   1495   *pValue = Value;
   1496 
   1497   //
   1498   //  Return the conversion status
   1499   //
   1500   return Status;
   1501 }
   1502 
   1503 
   1504 /**
   1505   Process the TFTP request
   1506 
   1507   @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure
   1508   @param [in] pContext    Address of a ::TSDT_CONNECTION_CONTEXT structure
   1509   @param [in] SocketFd    Socket file descriptor
   1510 
   1511 **/
   1512 VOID
   1513 TftpProcessRequest (
   1514   IN TSDT_TFTP_SERVER * pTftpServer,
   1515   IN TSDT_CONNECTION_CONTEXT * pContext,
   1516   IN int SocketFd
   1517   )
   1518 {
   1519   BOOLEAN bCloseContext;
   1520   UINT16 Opcode;
   1521 
   1522   DBG_ENTER ( );
   1523 
   1524   //
   1525   //  Get the opcode
   1526   //
   1527   Opcode = HTONS ( *(UINT16 *)&pTftpServer->RxBuffer[ 0 ]);
   1528   DEBUG (( DEBUG_TFTP_REQUEST,
   1529             "TFTP Opcode: 0x%08x\r\n",
   1530             Opcode ));
   1531 
   1532   //
   1533   //  Validate the parameters
   1534   //
   1535   bCloseContext = FALSE;
   1536   switch ( Opcode ) {
   1537   default:
   1538     DEBUG (( DEBUG_TFTP_REQUEST,
   1539               "ERROR - Unknown TFTP opcode: %d\r\n",
   1540               Opcode ));
   1541     break;
   1542 
   1543   case TFTP_OP_ACK:
   1544     bCloseContext = TftpAck ( pTftpServer, pContext );
   1545     break;
   1546 
   1547   case TFTP_OP_READ_REQUEST:
   1548     bCloseContext = TftpRead ( pTftpServer, pContext, SocketFd );
   1549     break;
   1550 
   1551 
   1552 
   1553 
   1554   case TFTP_OP_DATA:
   1555     if ( NULL == pContext ) {
   1556       if ( AF_INET == pTftpServer->RemoteAddress.v4.sin_family ) {
   1557         DEBUG (( DEBUG_ERROR,
   1558                   "ERROR - File not open for %d.%d.%d.%d:%d\r\n",
   1559                   (UINT8)pTftpServer->RemoteAddress.v4.sin_addr.s_addr,
   1560                   (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 8 ),
   1561                   (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 16 ),
   1562                   (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 24 ),
   1563                   htons ( pTftpServer->RemoteAddress.v4.sin_port )));
   1564       }
   1565       else {
   1566         DEBUG (( DEBUG_ERROR,
   1567                   "ERROR - File not open for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
   1568                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 0 ],
   1569                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 1 ],
   1570                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 2 ],
   1571                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 3 ],
   1572                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 4 ],
   1573                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 5 ],
   1574                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 6 ],
   1575                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 7 ],
   1576                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 8 ],
   1577                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 9 ],
   1578                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 10 ],
   1579                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 11 ],
   1580                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 12 ],
   1581                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 13 ],
   1582                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 14 ],
   1583                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 15 ],
   1584                   htons ( pTftpServer->RemoteAddress.v6.sin6_port )));
   1585       }
   1586       break;
   1587     }
   1588     if ( 0 != pContext->PacketsInWindow ) {
   1589       DEBUG (( DEBUG_ERROR,
   1590                 "ERROR - Expecting ACKs not data for pContext 0x%08x\r\n",
   1591                 pContext ));
   1592       break;
   1593     }
   1594     if ( pTftpServer->RxBytes > (ssize_t)( pContext->BlockSize + 2 + 2 )) {
   1595       DEBUG (( DEBUG_ERROR,
   1596                 "ERROR - Receive data length of %d > %d bytes (maximum block size) for pContext 0x%08x\r\n",
   1597                 pTftpServer->RxBytes - 2 - 2,
   1598                 pContext->BlockSize,
   1599                 pContext ));
   1600       break;
   1601     }
   1602     break;
   1603 
   1604   case TFTP_OP_ERROR:
   1605     if ( NULL == pContext ) {
   1606       if ( AF_INET == pTftpServer->RemoteAddress.v4.sin_family ) {
   1607         DEBUG (( DEBUG_ERROR,
   1608                   "ERROR - File not open for %d.%d.%d.%d:%d\r\n",
   1609                   (UINT8)pTftpServer->RemoteAddress.v4.sin_addr.s_addr,
   1610                   (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 8 ),
   1611                   (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 16 ),
   1612                   (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 24 ),
   1613                   htons ( pTftpServer->RemoteAddress.v4.sin_port )));
   1614       }
   1615       else {
   1616         DEBUG (( DEBUG_ERROR,
   1617                   "ERROR - File not open for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
   1618                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 0 ],
   1619                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 1 ],
   1620                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 2 ],
   1621                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 3 ],
   1622                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 4 ],
   1623                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 5 ],
   1624                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 6 ],
   1625                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 7 ],
   1626                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 8 ],
   1627                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 9 ],
   1628                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 10 ],
   1629                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 11 ],
   1630                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 12 ],
   1631                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 13 ],
   1632                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 14 ],
   1633                   pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 15 ],
   1634                   htons ( pTftpServer->RemoteAddress.v6.sin6_port )));
   1635       }
   1636     }
   1637     break;
   1638   }
   1639 
   1640   //
   1641   //  Determine if the context should be closed
   1642   //
   1643   if ( bCloseContext ) {
   1644     ContextRemove ( pTftpServer, pContext );
   1645   }
   1646 
   1647   DBG_EXIT ( );
   1648 }
   1649 
   1650 
   1651 /**
   1652   Process the read request
   1653 
   1654   @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure
   1655   @param [in] pContext    Address of a ::TSDT_CONNECTION_CONTEXT structure
   1656   @param [in] SocketFd    Socket file descriptor
   1657 
   1658   @retval TRUE if the context should be closed
   1659 
   1660 **/
   1661 BOOLEAN
   1662 TftpRead (
   1663   IN TSDT_TFTP_SERVER * pTftpServer,
   1664   IN TSDT_CONNECTION_CONTEXT * pContext,
   1665   IN int SocketFd
   1666   )
   1667 {
   1668   BOOLEAN bCloseContext;
   1669   struct stat FileStatus;
   1670   UINT8 * pBuffer;
   1671   UINT8 * pEnd;
   1672   UINT8 * pFileName;
   1673   UINT8 * pMode;
   1674   UINT8 * pOption;
   1675   CHAR8 * pReadMode;
   1676   UINT64 TimeStart;
   1677 
   1678   DBG_ENTER ( );
   1679 
   1680   //
   1681   //  Log the receive time
   1682   //
   1683   TimeStart = 0;
   1684   if ( PcdGetBool ( Tftp_Bandwidth )) {
   1685     TimeStart = GetPerformanceCounter ( );
   1686   }
   1687 
   1688   //
   1689   //  Close the context if necessary
   1690   //
   1691   bCloseContext = FALSE;
   1692   if ( NULL != pContext ) {
   1693     ContextRemove ( pTftpServer, pContext );
   1694   }
   1695 
   1696   //
   1697   //  Use break instead of goto
   1698   //
   1699   for ( ; ; ) {
   1700     //
   1701     //  Create the connection context
   1702     //
   1703     pContext = ContextAdd ( pTftpServer, SocketFd );
   1704     if ( NULL == pContext ) {
   1705       break;
   1706     }
   1707 
   1708     //
   1709     //  Set the start time
   1710     //
   1711     if ( PcdGetBool ( Tftp_Bandwidth )) {
   1712       pContext->TimeStart = TimeStart;
   1713     }
   1714 
   1715     //
   1716     //  Locate the mode
   1717     //
   1718     pBuffer = &pTftpServer->RxBuffer[ 0 ];
   1719     pEnd = &pBuffer[ pTftpServer->RxBytes ];
   1720     pFileName = &pBuffer[ 2 ];
   1721     pMode = pFileName;
   1722     while (( pEnd > pMode ) && ( 0 != *pMode )) {
   1723       pMode += 1;
   1724     }
   1725     if ( pEnd <= pMode ) {
   1726       //
   1727       //  Mode not found
   1728       //
   1729       DEBUG (( DEBUG_ERROR | DEBUG_RX,
   1730                 "ERROR - File mode not found\r\n" ));
   1731       //
   1732       //  Tell the client of the error
   1733       //
   1734       SendError ( pContext,
   1735                   TFTP_ERROR_SEE_MSG,
   1736                   (UINT8 *)"File open mode not found" );
   1737       break;
   1738     }
   1739     pMode += 1;
   1740     DEBUG (( DEBUG_TFTP_REQUEST,
   1741               "TFTP - FileName: %a\r\n",
   1742               pFileName ));
   1743 
   1744     //
   1745     //  Locate the options
   1746     //
   1747     pOption = pMode;
   1748     while (( pEnd > pOption ) && ( 0 != *pOption )) {
   1749       pOption += 1;
   1750     }
   1751     if ( pEnd <= pOption ) {
   1752       //
   1753       //  End of mode not found
   1754       //
   1755       DEBUG (( DEBUG_ERROR | DEBUG_RX,
   1756                 "ERROR - File mode not valid\r\n" ));
   1757       //
   1758       //  Tell the client of the error
   1759       //
   1760       SendError ( pContext,
   1761                   TFTP_ERROR_SEE_MSG,
   1762                   (UINT8 *)"File open mode not valid" );
   1763       break;
   1764     }
   1765     pOption += 1;
   1766     DEBUG (( DEBUG_TFTP_REQUEST,
   1767               "TFTP - Mode: %a\r\n",
   1768               pMode ));
   1769 
   1770     //
   1771     //  Verify the mode is supported
   1772     //
   1773     pReadMode = "r";
   1774     if ( 0 == strcasecmp ((char *)pMode, "octet" )) {
   1775       //
   1776       //  Read the file as binary input
   1777       //
   1778       pReadMode = "rb";
   1779     }
   1780 
   1781     //
   1782     //  Determine the file length
   1783     //
   1784     pContext->File = fopen ((const char *)pFileName, pReadMode );
   1785     if (( NULL == pContext->File )
   1786         || ( -1 == stat ((const char *)pFileName, &FileStatus ))) {
   1787       //
   1788       //  File not found
   1789       //
   1790       DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST,
   1791                 ( NULL == pContext->File )
   1792                 ? "ERROR - File not found!\r\n"
   1793                 : "ERROR - Unable to determine file %a size!\r\n",
   1794                 pFileName ));
   1795 
   1796       //
   1797       //  Tell the client of the error
   1798       //
   1799       SendError ( pContext,
   1800                   TFTP_ERROR_NOT_FOUND,
   1801                   (UINT8 *)"File not found" );
   1802       break;
   1803     }
   1804     pContext->LengthInBytes = FileStatus.st_size;
   1805     pContext->BytesRemaining = pContext->LengthInBytes;
   1806     pContext->BytesToSend = pContext->LengthInBytes;
   1807 
   1808     //
   1809     //  Display the file size
   1810     //
   1811     DEBUG_CODE_BEGIN ( );
   1812     UINT32 Value;
   1813 
   1814     if ( 1024 > pContext->LengthInBytes ) {
   1815       Value = (UINT32)pContext->LengthInBytes;
   1816       DEBUG (( DEBUG_FILE_BUFFER,
   1817                 "%a size: %d Bytes\r\n",
   1818                 pFileName,
   1819                 Value ));
   1820     }
   1821     else if (( 1024 * 1024 ) > pContext->LengthInBytes ) {
   1822       Value = (UINT32)pContext->LengthInBytes;
   1823       DEBUG (( DEBUG_FILE_BUFFER,
   1824                 "%a size: %d.%03d KiBytes (%Ld Bytes)\r\n",
   1825                 pFileName,
   1826                 Value / 1024,
   1827                 (( Value % 1024 ) * 1000 ) / 1024,
   1828                 pContext->LengthInBytes ));
   1829     }
   1830     else if (( 1024 * 1024 * 1024 ) > pContext->LengthInBytes ) {
   1831       Value = (UINT32)DivU64x32 ( pContext->LengthInBytes, 1024 );
   1832       DEBUG (( DEBUG_FILE_BUFFER,
   1833                 "%a size: %d.%03d MiBytes (%Ld Bytes)\r\n",
   1834                 pFileName,
   1835                 Value / 1024,
   1836                 (( Value % 1024 ) * 1000 ) / 1024,
   1837                 pContext->LengthInBytes ));
   1838     }
   1839     else {
   1840       Value = (UINT32)DivU64x32 ( pContext->LengthInBytes, 1024 * 1024 );
   1841       DEBUG (( DEBUG_FILE_BUFFER,
   1842                 "%a size: %d.%03d GiBytes (%Ld Bytes)\r\n",
   1843                 pFileName,
   1844                 Value / 1024,
   1845                 (( Value % 1024 ) * 1000 ) / 1024,
   1846                 pContext->LengthInBytes ));
   1847     }
   1848     DEBUG_CODE_END ( );
   1849 
   1850     //
   1851     //  Process the options
   1852     //
   1853     if ( pEnd > pOption ) {
   1854       TftpOptions ( pContext, pOption, pEnd );
   1855     }
   1856     else {
   1857       //
   1858       //  Skip the open ACK
   1859       //
   1860       pContext->BlockNumber = 1;
   1861     }
   1862 
   1863     //
   1864     //  Send the first packet (OACK or data block)
   1865     //
   1866     bCloseContext = PacketFill ( pContext );
   1867     break;
   1868   }
   1869 
   1870   //
   1871   //  Return the close status
   1872   //
   1873   DBG_EXIT ( );
   1874   return bCloseContext;
   1875 }
   1876 
   1877 
   1878 /**
   1879   Create the port for the TFTP server
   1880 
   1881   This routine polls the network layer to create the TFTP port for the
   1882   TFTP server.  More than one attempt may be necessary since it may take
   1883   some time to get the IP address and initialize the upper layers of
   1884   the network stack.
   1885 
   1886   @param [in] pTftpServer   Address of the ::TSDT_TFTP_SERVER structure
   1887   @param [in] AddressFamily The address family to use for the conection.
   1888   @param [in] pIndex        Address of the index into the port array
   1889 
   1890 **/
   1891 VOID
   1892 TftpServerSocket (
   1893   IN TSDT_TFTP_SERVER * pTftpServer,
   1894   IN sa_family_t AddressFamily,
   1895   IN int * pIndex
   1896   )
   1897 {
   1898   int SocketStatus;
   1899   struct pollfd * pTftpPort;
   1900   UINT16 TftpPort;
   1901   union {
   1902     struct sockaddr_in v4;
   1903     struct sockaddr_in6 v6;
   1904   } TftpServerAddress;
   1905 
   1906   DEBUG (( DEBUG_SERVER_TIMER, "Entering TftpServerListen\r\n" ));
   1907 
   1908   //
   1909   //  Determine if the socket is already initialized
   1910   //
   1911   if ( -1 == *pIndex ) {
   1912     //
   1913     //  Attempt to create the socket for the TFTP server
   1914     //
   1915     pTftpPort = &pTftpServer->TftpPort[ pTftpServer->Entries ];
   1916     pTftpPort->fd = socket ( AddressFamily,
   1917                              SOCK_DGRAM,
   1918                              IPPROTO_UDP );
   1919     if ( -1 != pTftpPort->fd ) {
   1920       //
   1921       //  Initialize the poll structure
   1922       //
   1923       pTftpPort->events = POLLRDNORM | POLLHUP;
   1924       pTftpPort->revents = 0;
   1925 
   1926       //
   1927       //  Set the socket address
   1928       //
   1929       TftpPort = 69;
   1930       ZeroMem ( &TftpServerAddress, sizeof ( TftpServerAddress ));
   1931       TftpServerAddress.v4.sin_port = htons ( TftpPort );
   1932       if ( AF_INET == AddressFamily ) {
   1933         TftpServerAddress.v4.sin_len = sizeof ( TftpServerAddress.v4 );
   1934         TftpServerAddress.v4.sin_family = AF_INET;
   1935       }
   1936       else {
   1937         TftpServerAddress.v6.sin6_len = sizeof ( TftpServerAddress.v6 );
   1938         TftpServerAddress.v6.sin6_family = AF_INET6;
   1939       }
   1940 
   1941       //
   1942       //  Bind the socket to the TFTP port
   1943       //
   1944       SocketStatus = bind ( pTftpPort->fd,
   1945                             (struct sockaddr *) &TftpServerAddress,
   1946                             TftpServerAddress.v6.sin6_len );
   1947       if ( -1 != SocketStatus ) {
   1948         DEBUG (( DEBUG_TFTP_PORT,
   1949                   "0x%08x: Socket bound to port %d\r\n",
   1950                   pTftpPort->fd,
   1951                   TftpPort ));
   1952 
   1953         //
   1954         //  Account for this connection
   1955         //
   1956         *pIndex = pTftpServer->Entries;
   1957         pTftpServer->Entries += 1;
   1958         ASSERT ( DIM ( pTftpServer->TftpPort ) >= pTftpServer->Entries );
   1959       }
   1960 
   1961       //
   1962       //  Release the socket if necessary
   1963       //
   1964       if ( -1 == SocketStatus ) {
   1965         close ( pTftpPort->fd );
   1966         pTftpPort->fd = -1;
   1967       }
   1968     }
   1969   }
   1970 
   1971   DEBUG (( DEBUG_SERVER_TIMER, "Exiting TftpServerListen\r\n" ));
   1972 }
   1973 
   1974 
   1975 /**
   1976   Update the window due to the ACK
   1977 
   1978   @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure
   1979   @param [in] pContext    Address of a ::TSDT_CONNECTION_CONTEXT structure
   1980   @param [in] pPacket     Address of a ::TFTP_PACKET structure
   1981 
   1982 **/
   1983 VOID
   1984 WindowAck (
   1985   IN TSDT_TFTP_SERVER * pTftpServer,
   1986   IN TSDT_CONNECTION_CONTEXT * pContext,
   1987   IN TFTP_PACKET * pPacket
   1988   )
   1989 {
   1990   if ( PcdGetBool ( Tftp_HighSpeed )) {
   1991     UINT64 DeltaTime;
   1992     UINT64 NanoSeconds;
   1993 
   1994     DBG_ENTER ( );
   1995 
   1996     //
   1997     //  Compute the round trip time
   1998     //
   1999     if ( pTftpServer->Time2 > pTftpServer->Time1 ) {
   2000       DeltaTime = pTftpServer->RxTime - pPacket->TxTime;
   2001     }
   2002     else {
   2003       DeltaTime = pPacket->TxTime - pTftpServer->RxTime;
   2004     }
   2005 
   2006     //
   2007     //  Adjust the round trip time
   2008     //
   2009     NanoSeconds = GetTimeInNanoSecond ( DeltaTime );
   2010     DeltaTime = RShiftU64 ( pContext->Rtt2x, ACK_SHIFT );
   2011     pContext->Rtt2x += NanoSeconds + NanoSeconds - DeltaTime;
   2012     if ( pContext->Rtt2x > pContext->MaxTimeout ) {
   2013       pContext->Rtt2x = pContext->MaxTimeout;
   2014     }
   2015 
   2016     //
   2017     //  Account for the ACK
   2018     //
   2019     if ( pContext->WindowSize < MAX_PACKETS ) {
   2020       pContext->AckCount -= 1;
   2021       if ( 0 == pContext->AckCount ) {
   2022         //
   2023         //  Increase the window
   2024         //
   2025         pContext->WindowSize += 1;
   2026 
   2027         //
   2028         //  Set the ACK count
   2029         //
   2030         if ( pContext->WindowSize < pContext->Threshold ) {
   2031           pContext->AckCount = pContext->WindowSize * PcdGet32 ( Tftp_AckMultiplier );
   2032         }
   2033         else {
   2034           pContext->AckCount = PcdGet32 ( Tftp_AckLogBase ) << pContext->WindowSize;
   2035         }
   2036 
   2037         //
   2038         //  Display the round trip time
   2039         //
   2040         DEBUG_CODE_BEGIN ( );
   2041         UINT32 Value;
   2042 
   2043         DeltaTime = RShiftU64 ( pContext->Rtt2x, 1 );
   2044         if ( 1000 > DeltaTime ) {
   2045           DEBUG (( DEBUG_WINDOW,
   2046                     "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %Ld nSec\r\n",
   2047                     pContext->WindowSize,
   2048                     pContext->Threshold,
   2049                     pContext->AckCount,
   2050                     DeltaTime ));
   2051         }
   2052         else if (( 1000 * 1000 ) > DeltaTime ) {
   2053           Value = (UINT32)DeltaTime;
   2054           DEBUG (( DEBUG_WINDOW,
   2055                     "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d uSec\r\n",
   2056                     pContext->WindowSize,
   2057                     pContext->Threshold,
   2058                     pContext->AckCount,
   2059                     Value / 1000,
   2060                     Value % 1000 ));
   2061         }
   2062         else if (( 1000 * 1000 * 1000 ) > DeltaTime ) {
   2063           Value = (UINT32)DivU64x32 ( DeltaTime, 1000 );
   2064           DEBUG (( DEBUG_WINDOW,
   2065                     "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d mSec\r\n",
   2066                     pContext->WindowSize,
   2067                     pContext->Threshold,
   2068                     pContext->AckCount,
   2069                     Value / 1000,
   2070                     Value % 1000 ));
   2071         }
   2072         else {
   2073           Value = (UINT32)DivU64x32 ( DeltaTime, 1000 * 1000 );
   2074           DEBUG (( DEBUG_WINDOW,
   2075                     "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d Sec\r\n",
   2076                     pContext->WindowSize,
   2077                     pContext->Threshold,
   2078                     pContext->AckCount,
   2079                     Value / 1000,
   2080                     Value % 1000 ));
   2081         }
   2082         DEBUG_CODE_END ( );
   2083       }
   2084     }
   2085 
   2086     DBG_EXIT ( );
   2087   }
   2088 }
   2089 
   2090 
   2091 /**
   2092   A timeout has occurred, close the window
   2093 
   2094   @param [in] pContext    Address of a ::TSDT_CONNECTION_CONTEXT structure
   2095 
   2096 **/
   2097 VOID
   2098 WindowTimeout (
   2099   IN TSDT_CONNECTION_CONTEXT * pContext
   2100   )
   2101 {
   2102   if ( PcdGetBool ( Tftp_HighSpeed )) {
   2103     TFTP_PACKET * pPacket;
   2104 
   2105     DBG_ENTER ( );
   2106 
   2107     //
   2108     //  Set the threshold at half the previous window size
   2109     //
   2110     pContext->Threshold = ( pContext->WindowSize + 1 ) >> 1;
   2111 
   2112     //
   2113     //  Close the transmit window
   2114     //
   2115     pContext->WindowSize = 1;
   2116     pContext->PacketsInWindow = 0;
   2117 
   2118     //
   2119     //  Double the round trip time
   2120     //
   2121     pContext->Rtt2x = LShiftU64 ( pContext->Rtt2x, 1 );
   2122     if ( pContext->Rtt2x > pContext->MaxTimeout ) {
   2123       pContext->Rtt2x = pContext->MaxTimeout;
   2124     }
   2125 
   2126     //
   2127     //  Set the ACK count
   2128     //
   2129     if ( pContext->WindowSize < pContext->Threshold ) {
   2130       pContext->AckCount = pContext->WindowSize * PcdGet32 ( Tftp_AckMultiplier );
   2131     }
   2132     else {
   2133       pContext->AckCount = PcdGet32 ( Tftp_AckLogBase ) << pContext->WindowSize;
   2134     }
   2135 
   2136     //
   2137     //  Display the round trip time
   2138     //
   2139     DEBUG_CODE_BEGIN ( );
   2140     UINT64 DeltaTime;
   2141     UINT32 Value;
   2142 
   2143     DeltaTime = RShiftU64 ( pContext->Rtt2x, 1 );
   2144     if ( 1000 > DeltaTime ) {
   2145       DEBUG (( DEBUG_WINDOW,
   2146                 "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %Ld nSec\r\n",
   2147                 pContext->WindowSize,
   2148                 pContext->Threshold,
   2149                 pContext->AckCount,
   2150                 DeltaTime ));
   2151     }
   2152     else if (( 1000 * 1000 ) > DeltaTime ) {
   2153       Value = (UINT32)DeltaTime;
   2154       DEBUG (( DEBUG_WINDOW,
   2155                 "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d uSec\r\n",
   2156                 pContext->WindowSize,
   2157                 pContext->Threshold,
   2158                 pContext->AckCount,
   2159                 Value / 1000,
   2160                 Value % 1000 ));
   2161     }
   2162     else if (( 1000 * 1000 * 1000 ) > DeltaTime ) {
   2163       Value = (UINT32)DivU64x32 ( DeltaTime, 1000 );
   2164       DEBUG (( DEBUG_WINDOW,
   2165                 "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d mSec\r\n",
   2166                 pContext->WindowSize,
   2167                 pContext->Threshold,
   2168                 pContext->AckCount,
   2169                 Value / 1000,
   2170                 Value % 1000 ));
   2171     }
   2172     else {
   2173       Value = (UINT32)DivU64x32 ( DeltaTime, 1000 * 1000 );
   2174       DEBUG (( DEBUG_WINDOW,
   2175                 "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d Sec\r\n",
   2176                 pContext->WindowSize,
   2177                 pContext->Threshold,
   2178                 pContext->AckCount,
   2179                 Value / 1000,
   2180                 Value % 1000 ));
   2181     }
   2182     DEBUG_CODE_END ( );
   2183 
   2184     //
   2185     //  Retransmit the first packet in the window
   2186     //
   2187     pPacket = pContext->pTxHead;
   2188     if ( NULL != pPacket ) {
   2189       PacketTx ( pContext, pPacket );
   2190     }
   2191 
   2192     DBG_EXIT ( );
   2193   }
   2194 }
   2195 
   2196 
   2197 /**
   2198   Entry point for the TFTP server application.
   2199 
   2200   @param [in] Argc  The number of arguments
   2201   @param [in] Argv  The argument value array
   2202 
   2203   @retval  0        The application exited normally.
   2204   @retval  Other    An error occurred.
   2205 **/
   2206 int
   2207 main (
   2208   IN int Argc,
   2209   IN char **Argv
   2210   )
   2211 {
   2212   UINTN Index;
   2213   TSDT_TFTP_SERVER * pTftpServer;
   2214   EFI_STATUS Status;
   2215   UINT64 TriggerTime;
   2216 
   2217   //
   2218   //  Get the performance counter characteristics
   2219   //
   2220   pTftpServer = &mTftpServer;
   2221   if ( PcdGetBool ( Tftp_HighSpeed )
   2222     || PcdGetBool ( Tftp_Bandwidth )) {
   2223     pTftpServer->ClockFrequency = GetPerformanceCounterProperties ( &pTftpServer->Time1,
   2224                                                                   &pTftpServer->Time2 );
   2225   }
   2226 
   2227   //
   2228   //  Create a timer event to start TFTP port
   2229   //
   2230   Status = gBS->CreateEvent ( EVT_TIMER,
   2231                               TPL_TFTP_SERVER,
   2232                               NULL,
   2233                               NULL,
   2234                               &pTftpServer->TimerEvent );
   2235   if ( !EFI_ERROR ( Status )) {
   2236     //
   2237     //  Compute the poll interval
   2238     //
   2239     TriggerTime = TFTP_PORT_POLL_DELAY * ( 1000 * 10 );
   2240     Status = gBS->SetTimer ( pTftpServer->TimerEvent,
   2241                              TimerPeriodic,
   2242                              TriggerTime );
   2243     if ( !EFI_ERROR ( Status )) {
   2244       DEBUG (( DEBUG_TFTP_PORT, "TFTP port timer started\r\n" ));
   2245 
   2246       //
   2247       //  Run the TFTP server forever
   2248       //
   2249       pTftpServer->Udpv4Index = -1;
   2250       pTftpServer->Udpv6Index = -1;
   2251       do {
   2252         //
   2253         //  Poll the network layer to create the TFTP port
   2254         //  for the tftp server.  More than one attempt may
   2255         //  be necessary since it may take some time to get
   2256         //  the IP address and initialize the upper layers
   2257         //  of the network stack.
   2258         //
   2259         if ( DIM ( pTftpServer->TftpPort ) != pTftpServer->Entries ) {
   2260           do {
   2261             //
   2262             //  Wait a while before polling for a connection
   2263             //
   2264             if ( EFI_SUCCESS != gBS->CheckEvent ( pTftpServer->TimerEvent )) {
   2265               if ( 0 == pTftpServer->Entries ) {
   2266                 break;
   2267               }
   2268               gBS->WaitForEvent ( 1, &pTftpServer->TimerEvent, &Index );
   2269             }
   2270 
   2271             //
   2272             //  Poll for a network connection
   2273             //
   2274             TftpServerSocket ( pTftpServer,
   2275                                AF_INET,
   2276                                &pTftpServer->Udpv4Index );
   2277             TftpServerSocket ( pTftpServer,
   2278                                AF_INET6,
   2279                                &pTftpServer->Udpv6Index );
   2280           } while ( 0 == pTftpServer->Entries );
   2281         }
   2282 
   2283         //
   2284         //  Poll the socket for activity
   2285         //
   2286         do {
   2287           SocketPoll ( pTftpServer );
   2288 
   2289           //
   2290           //  Normal TFTP lets the client request the retransmit by
   2291           //  sending another ACK for the previous packet
   2292           //
   2293           if ( PcdGetBool ( Tftp_HighSpeed )) {
   2294             UINT64 CurrentTime;
   2295             UINT64 ElapsedTime;
   2296             TSDT_CONNECTION_CONTEXT * pContext;
   2297             TFTP_PACKET * pPacket;
   2298 
   2299             //
   2300             //  High speed TFTP uses an agressive retransmit to
   2301             //  get the TFTP client moving again when the ACK or
   2302             //  previous data packet was lost.
   2303             //
   2304             //  Get the current time
   2305             //
   2306             CurrentTime = GetPerformanceCounter ( );
   2307 
   2308             //
   2309             //  Walk the list of contexts
   2310             //
   2311             pContext = pTftpServer->pContextList;
   2312             while ( NULL != pContext )
   2313             {
   2314               //
   2315               //  Check for a transmit timeout
   2316               //
   2317               pPacket = pContext->pTxHead;
   2318               if ( NULL != pPacket ) {
   2319                 //
   2320                 //  Compute the elapsed time
   2321                 //
   2322                 if ( pTftpServer->Time2 > pTftpServer->Time1 ) {
   2323                   ElapsedTime = CurrentTime - pPacket->TxTime;
   2324                 }
   2325                 else {
   2326                   ElapsedTime = pPacket->TxTime - CurrentTime;
   2327                 }
   2328                 ElapsedTime = GetTimeInNanoSecond ( ElapsedTime );
   2329 
   2330                 //
   2331                 //  Determine if a retransmission is necessary
   2332                 //
   2333                 if ( ElapsedTime >= pContext->Rtt2x ) {
   2334                   DEBUG (( DEBUG_WINDOW,
   2335                             "0x%08x: Context TX timeout for packet 0x%08x, Window: %d\r\n",
   2336                             pContext,
   2337                             pPacket,
   2338                             pContext->WindowSize ));
   2339                   WindowTimeout ( pContext );
   2340                 }
   2341               }
   2342 
   2343               //
   2344               //  Set the next context
   2345               //
   2346               pContext = pContext->pNext;
   2347             }
   2348           }
   2349         } while ( DIM ( pTftpServer->TftpPort ) == pTftpServer->Entries );
   2350       } while ( !mbTftpServerExit );
   2351 
   2352       //
   2353       //  Done with the timer event
   2354       //
   2355       gBS->SetTimer ( pTftpServer->TimerEvent,
   2356                       TimerCancel,
   2357                       0 );
   2358     }
   2359     gBS->CloseEvent ( pTftpServer->TimerEvent );
   2360   }
   2361 
   2362   //
   2363   //  Return the final status
   2364   //
   2365   DBG_EXIT_STATUS ( Status );
   2366   return Status;
   2367 }
   2368