• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
BufferFill(IN TSDT_CONNECTION_CONTEXT * pContext)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 *
ContextAdd(IN TSDT_TFTP_SERVER * pTftpServer,IN int SocketFd)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 *
ContextFind(IN TSDT_TFTP_SERVER * pTftpServer)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
ContextRemove(IN TSDT_TFTP_SERVER * pTftpServer,IN TSDT_CONNECTION_CONTEXT * pContext)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
PacketFill(IN TSDT_CONNECTION_CONTEXT * pContext)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
PacketFree(IN TSDT_CONNECTION_CONTEXT * pContext,IN TFTP_PACKET * pPacket)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 *
PacketGet(IN TSDT_CONNECTION_CONTEXT * pContext)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
PacketQueue(IN TSDT_CONNECTION_CONTEXT * pContext,IN TFTP_PACKET * pPacket)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 *
PacketRemove(IN TSDT_CONNECTION_CONTEXT * pContext)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
PacketTx(IN TSDT_CONNECTION_CONTEXT * pContext,IN TFTP_PACKET * pPacket)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
PortWork(IN TSDT_TFTP_SERVER * pTftpServer,IN int * pIndex)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
SendError(IN TSDT_CONNECTION_CONTEXT * pContext,IN UINT16 Error,IN UINT8 * pError)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
SocketPoll(IN TSDT_TFTP_SERVER * pTftpServer)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
TftpAck(IN TSDT_TFTP_SERVER * pTftpServer,IN TSDT_CONNECTION_CONTEXT * pContext)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
TftpOptionGet(IN UINT8 * pOption,IN UINT8 * pEnd,IN UINT8 ** ppNextOption)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 *
TftpOptionSet(IN UINT8 * pOack,IN UINT64 Value)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
TftpOptions(IN TSDT_CONNECTION_CONTEXT * pContext,IN UINT8 * pOption,IN UINT8 * pEnd)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
TftpOptionValue(IN UINT8 * pOption,IN INT32 * pValue)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
TftpProcessRequest(IN TSDT_TFTP_SERVER * pTftpServer,IN TSDT_CONNECTION_CONTEXT * pContext,IN int SocketFd)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
TftpRead(IN TSDT_TFTP_SERVER * pTftpServer,IN TSDT_CONNECTION_CONTEXT * pContext,IN int SocketFd)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
TftpServerSocket(IN TSDT_TFTP_SERVER * pTftpServer,IN sa_family_t AddressFamily,IN int * pIndex)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
WindowAck(IN TSDT_TFTP_SERVER * pTftpServer,IN TSDT_CONNECTION_CONTEXT * pContext,IN TFTP_PACKET * pPacket)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
WindowTimeout(IN TSDT_CONNECTION_CONTEXT * pContext)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
main(IN int Argc,IN char ** Argv)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