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