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