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