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
17TSDT_TFTP_SERVER mTftpServer;       ///<  TFTP server's control structure
18volatile 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**/
29BOOLEAN
30BufferFill (
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**/
116TSDT_CONNECTION_CONTEXT *
117ContextAdd (
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**/
229TSDT_CONNECTION_CONTEXT *
230ContextFind (
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**/
279VOID
280ContextRemove (
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**/
341BOOLEAN
342PacketFill (
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**/
459VOID
460PacketFree(
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**/
493TFTP_PACKET *
494PacketGet (
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**/
531BOOLEAN
532PacketQueue (
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**/
588TFTP_PACKET *
589PacketRemove(
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**/
636EFI_STATUS
637PacketTx (
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**/
718VOID
719PortWork (
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**/
845EFI_STATUS
846SendError (
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**/
898VOID
899SocketPoll (
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**/
936BOOLEAN
937TftpAck (
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**/
1152EFI_STATUS
1153TftpOptionGet (
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**/
1213UINT8 *
1214TftpOptionSet (
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**/
1253VOID
1254TftpOptions (
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**/
1455EFI_STATUS
1456TftpOptionValue (
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**/
1512VOID
1513TftpProcessRequest (
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**/
1661BOOLEAN
1662TftpRead (
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**/
1891VOID
1892TftpServerSocket (
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**/
1983VOID
1984WindowAck (
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**/
2097VOID
2098WindowTimeout (
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**/
2206int
2207main (
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