2 This file contains an 'Intel UEFI Application' and is
3 licensed for Intel CPUs and chipsets under the terms of your
4 license agreement with Intel or your vendor. This file may
5 be modified by the user, subject to additional terms of the
10 Copyright (c) 2011 Intel Corporation. All rights reserved
11 This software and associated documentation (if any) is furnished
12 under a license and may only be used or copied in accordance
13 with the terms of the license. Except as permitted by such
14 license, no part of this software or documentation may be
15 reproduced, stored in a retrieval system, or transmitted in any
16 form or by any means without the express written consent of
22 This is a simple TFTP server application
26 #include <TftpServer.h>
28 TSDT_TFTP_SERVER mTftpServer
; ///< TFTP server's control structure
32 Add a connection context to the list of connection contexts.
34 @param [in] pTftpServer The TFTP server control structure address.
36 @retval Context structure address, NULL if allocation fails
39 TSDT_CONNECTION_CONTEXT
*
41 IN TSDT_TFTP_SERVER
* pTftpServer
45 TSDT_CONNECTION_CONTEXT
* pContext
;
51 // Use for/break instead of goto
55 // Allocate a new context
57 LengthInBytes
= sizeof ( *pContext
);
58 Status
= gBS
->AllocatePool ( EfiRuntimeServicesData
,
61 if ( EFI_ERROR ( Status
)) {
62 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
,
63 "ERROR - Failed to allocate the context, Status: %r\r\n",
70 // Initialize the context
72 ZeroMem ( pContext
, LengthInBytes
);
73 CopyMem ( &pContext
->RemoteAddress
,
74 &pTftpServer
->RemoteAddress
,
75 sizeof ( pContext
->RemoteAddress
));
76 pContext
->BlockSize
= TFTP_MAX_BLOCK_SIZE
;
77 pContext
->pBuffer
= &pContext
->FileData
[0];
78 pContext
->pEnd
= &pContext
->pBuffer
[sizeof ( pContext
->pBuffer
)];
79 pContext
->MaxTransferSize
= 0;
80 pContext
->MaxTransferSize
-= 1;
83 // Display the new context
85 DEBUG (( DEBUG_PORT_WORK
| DEBUG_INFO
,
86 "0x%08x: Context for %d.%d.%d.%d:%d\r\n",
88 (UINT8
)pContext
->RemoteAddress
.sin_addr
.s_addr
,
89 (UINT8
)( pContext
->RemoteAddress
.sin_addr
.s_addr
>> 8 ),
90 (UINT8
)( pContext
->RemoteAddress
.sin_addr
.s_addr
>> 16 ),
91 (UINT8
)( pContext
->RemoteAddress
.sin_addr
.s_addr
>> 24 ),
92 htons ( pContext
->RemoteAddress
.sin_port
)));
95 // Add the context to the context list
97 pContext
->pNext
= pTftpServer
->pContextList
;
98 pTftpServer
->pContextList
= pContext
;
107 // Return the connection context
109 DBG_EXIT_STATUS ( pContext
);
115 Locate a remote connection context.
117 @param [in] pTftpServer The TFTP server control structure address.
119 @param [in] pIpAddress The start of the remote IP address in network order
121 @param [in] Port The remote port number
123 @retval Context structure address, NULL if not found
126 TSDT_CONNECTION_CONTEXT
*
128 IN TSDT_TFTP_SERVER
* pTftpServer
131 TSDT_CONNECTION_CONTEXT
* pContext
;
136 // Walk the list of connection contexts
138 pContext
= pTftpServer
->pContextList
;
139 while ( NULL
!= pContext
) {
141 // Attempt to locate the remote network connection
143 if (( pTftpServer
->RemoteAddress
.sin_addr
.s_addr
== pContext
->RemoteAddress
.sin_addr
.s_addr
)
144 && ( pTftpServer
->RemoteAddress
.sin_port
== pContext
->RemoteAddress
.sin_port
)) {
146 // The connection was found
148 DEBUG (( DEBUG_TFTP_REQUEST
,
149 "0x%08x: pContext found\r\n",
155 // Set the next context
157 pContext
= pContext
->pNext
;
161 // Return the connection context structure address
163 DBG_EXIT_HEX ( pContext
);
169 Remove a context from the list.
171 @param [in] pTftpServer The TFTP server control structure address.
173 @param [in] pContext The context structure address.
178 IN TSDT_TFTP_SERVER
* pTftpServer
,
179 IN TSDT_CONNECTION_CONTEXT
* pContext
182 TSDT_CONNECTION_CONTEXT
* pNextContext
;
183 TSDT_CONNECTION_CONTEXT
* pPreviousContext
;
188 // Attempt to locate the context in the list
190 pPreviousContext
= NULL
;
191 pNextContext
= pTftpServer
->pContextList
;
192 while ( NULL
!= pNextContext
) {
194 // Determine if the context was found
196 if ( pNextContext
== pContext
) {
198 // Remove the context from the list
200 if ( NULL
== pPreviousContext
) {
201 pTftpServer
->pContextList
= pContext
->pNext
;
204 pPreviousContext
->pNext
= pContext
->pNext
;
210 // Set the next context
212 pPreviousContext
= pNextContext
;
213 pNextContext
= pNextContext
->pNext
;
217 // Determine if the context was found
219 if ( NULL
!= pContext
) {
221 // Return the resources
223 gBS
->FreePool ( pContext
);
231 Process the work for the sockets.
233 @param [in] pTftpServer The TFTP server control structure address.
238 IN TSDT_TFTP_SERVER
* pTftpServer
241 TSDT_CONNECTION_CONTEXT
* pContext
;
242 socklen_t RemoteAddressLength
;
247 // Handle input events
249 if ( 0 != ( pTftpServer
->TftpPort
.revents
& POLLRDNORM
)) {
251 // Receive the message from the remote system
253 RemoteAddressLength
= sizeof ( pTftpServer
->RemoteAddress
);
254 pTftpServer
->RxBytes
= recvfrom ( pTftpServer
->TftpPort
.fd
,
255 &pTftpServer
->RxBuffer
[0],
256 sizeof ( pTftpServer
->RxBuffer
),
258 (struct sockaddr
*) &pTftpServer
->RemoteAddress
,
259 &RemoteAddressLength
);
260 if ( -1 != pTftpServer
->RxBytes
) {
261 pTftpServer
->RemoteAddress
.sin_len
= (UINT8
) RemoteAddressLength
;
262 DEBUG (( DEBUG_TFTP_PORT
,
263 "Received %d bytes from %d.%d.%d.%d:%d\r\n",
264 pTftpServer
->RxBytes
,
265 pTftpServer
->RemoteAddress
.sin_addr
.s_addr
& 0xff,
266 ( pTftpServer
->RemoteAddress
.sin_addr
.s_addr
>> 8 ) & 0xff,
267 ( pTftpServer
->RemoteAddress
.sin_addr
.s_addr
>> 16 ) & 0xff,
268 ( pTftpServer
->RemoteAddress
.sin_addr
.s_addr
>> 24 ) & 0xff,
269 htons ( pTftpServer
->RemoteAddress
.sin_port
)));
272 // Lookup connection context using the remote system address and port
273 // to determine if an existing connection to this remote
276 pContext
= ContextFind ( pTftpServer
);
279 // Process the received message
281 TftpProcessRequest ( pTftpServer
, pContext
);
285 // Receive error on the TFTP server port
286 // Close the server socket
288 DEBUG (( DEBUG_ERROR
,
289 "ERROR - Failed receive on TFTP server port, errno: 0x%08x\r\n",
291 pTftpServer
->TftpPort
.revents
|= POLLHUP
;
296 // Handle the close event
298 if ( 0 != ( pTftpServer
->TftpPort
.revents
& POLLHUP
)) {
302 close ( pTftpServer
->TftpPort
.fd
);
303 pTftpServer
->TftpPort
.fd
= -1;
311 Scan the list of sockets and process any pending work
313 @param [in] pTftpServer The TFTP server control structure address.
318 IN TSDT_TFTP_SERVER
* pTftpServer
323 DEBUG (( DEBUG_SOCKET_POLL
, "Entering SocketPoll\r\n" ));
326 // Determine if any ports are active
328 FDCount
= poll ( &pTftpServer
->TftpPort
,
331 if ( -1 == FDCount
) {
332 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET_POLL
,
333 "ERROR - errno: %d\r\n",
341 PortWork ( pTftpServer
);
342 pTftpServer
->TftpPort
.revents
= 0;
345 DEBUG (( DEBUG_SOCKET_POLL
, "Exiting SocketPoll\r\n" ));
350 Convert a character to lower case
352 @param [in] Character The character to convert
354 @return The lower case equivalent of the character
363 // Determine if the character is upper case
365 if (( 'A' <= Character
) && ( 'Z' >= Character
)) {
367 // Convert the character to lower caes
369 Character
+= 'a' - 'A';
373 // Return the converted character
380 Case independent string comparison
382 @param [in] pString1 Zero terminated string address
383 @param [in] pString2 Zero terminated string address
385 @return Returns the first character difference between string 1
400 // Walk the length of the strings
404 // Get the next characters
406 Char1
= (UINT8
)*pString1
++;
407 Char2
= (UINT8
)*pString2
++;
410 // Convert them to lower case
412 Char1
= tolower ( Char1
);
413 Char2
= tolower ( Char2
);
416 // Done when the characters differ
418 Difference
= Char1
- Char2
;
419 if ( 0 != Difference
) {
424 // Done at the end of the string
426 } while ( 0 != Char1
);
429 // Return the difference
436 Get the next TFTP option
438 @param [in] pOption Address of a zero terminated option string
439 @param [in] pEnd End of buffer address
440 @param [in] ppNextOption Address to receive the address of the next
441 zero terminated option string
443 @retval EFI_SUCCESS Message processed successfully
450 IN UINT8
** ppNextOption
457 // Locate the end of the option
459 pNextOption
= pOption
;
460 while (( pEnd
> pNextOption
) && ( 0 != *pNextOption
)) {
463 if ( pEnd
<= pNextOption
) {
465 // Error - end of buffer reached
467 DEBUG (( DEBUG_ERROR
| DEBUG_TFTP_REQUEST
,
468 "ERROR - Option without zero termination received!\r\n" ));
469 Status
= EFI_INVALID_PARAMETER
;
473 // Zero terminated option found
478 // Display the zero terminated ASCII option string
480 DEBUG (( DEBUG_TFTP_REQUEST
,
483 Status
= EFI_SUCCESS
;
487 // Return the next option address
489 *ppNextOption
= pNextOption
;
492 // Return the operation status
499 Place an option value into the option acknowledgement
501 @param [in] pOack Option acknowledgement address
502 @param [in] Value Value to translate into ASCII decimal
504 @return Option acknowledgement address
516 // Determine the next value
518 NextValue
= Value
/ 10;
521 // Supress leading zeros
523 if ( 0 != NextValue
) {
524 pOack
= TftpOptionSet ( pOack
, NextValue
);
530 *pOack
++ = (UINT8
)( Value
- ( NextValue
* 10 ) + '0' );
533 // Return the next option acknowledgement location
540 Process the TFTP request
542 @param [in] pContext The context structure address.
543 @param [in] pOption Address of the first zero terminated option string
544 @param [in] pEnd End of buffer address
549 IN TSDT_CONNECTION_CONTEXT
* pContext
,
562 // Start the OACK packet
563 // Let the OACK handle the parsing errors
564 // See http://tools.ietf.org/html/rfc2347
566 pOack
= &pContext
->TxBuffer
[0];
568 *pOack
++ = TFTP_OP_OACK
;
569 pContext
->TxBytes
= 2;
572 // Walk the list of options
576 // Get the next option, skip junk at end of message
578 Status
= TftpOptionGet ( pOption
, pEnd
, &pNextOption
);
579 if ( !EFI_ERROR ( Status
)) {
581 // Process the option
585 // blksize - See http://tools.ietf.org/html/rfc2348
587 pValue
= pNextOption
;
588 if ( 0 == stricmp ((char *)pOption
, "blksize" )) {
592 Status
= TftpOptionGet ( pValue
, pEnd
, &pNextOption
);
593 if ( !EFI_ERROR ( Status
)) {
595 // Validate the block size, skip non-numeric block sizes
597 Status
= TftpOptionValue ( pValue
, &Value
);
598 if ( !EFI_ERROR ( Status
)) {
600 // Propose a smaller block size if necessary
602 if ( Value
> TFTP_MAX_BLOCK_SIZE
) {
603 Value
= TFTP_MAX_BLOCK_SIZE
;
607 // Set the new block size
609 pContext
->BlockSize
= Value
;
610 DEBUG (( DEBUG_TFTP_REQUEST
,
611 "Using block size of %d bytes\r\n",
612 pContext
->BlockSize
));
626 pOack
= TftpOptionSet ( pOack
, pContext
->BlockSize
);
628 pContext
->TxBytes
+= pOack
- pTemp
;
634 // timeout - See http://tools.ietf.org/html/rfc2349
636 else if ( 0 == stricmp ((char *)pOption
, "timeout" )) {
640 Status
= TftpOptionGet ( pValue
, pEnd
, &pNextOption
);
641 if ( !EFI_ERROR ( Status
)) {
642 Status
= TftpOptionValue ( pValue
, &Value
);
643 if ( !EFI_ERROR ( Status
)) {
645 // Set the timeout value
647 pContext
->Timeout
= Value
;
648 DEBUG (( DEBUG_TFTP_REQUEST
,
649 "Using timeout of %d seconds\r\n",
650 pContext
->Timeout
));
664 pOack
= TftpOptionSet ( pOack
, pContext
->Timeout
);
666 pContext
->TxBytes
+= pOack
- pTemp
;
672 // tsize - See http://tools.ietf.org/html/rfc2349
674 else if ( 0 == stricmp ((char *)pOption
, "tsize" )) {
678 Status
= TftpOptionGet ( pValue
, pEnd
, &pNextOption
);
679 if ( !EFI_ERROR ( Status
)) {
680 Status
= TftpOptionValue ( pValue
, &Value
);
681 if ( !EFI_ERROR ( Status
)) {
683 // Return the file size
685 DEBUG (( DEBUG_TFTP_REQUEST
,
686 "Returning file size of %Ld bytes\r\n",
687 pContext
->LengthInBytes
));
699 pOack
= TftpOptionSet ( pOack
, pContext
->LengthInBytes
);
701 pContext
->TxBytes
+= pOack
- pTemp
;
707 // Unknown option - Ignore it
709 DEBUG (( DEBUG_WARN
| DEBUG_TFTP_REQUEST
,
710 "WARNING - Skipping unknown option: %a\r\n",
716 // Set the next option
718 pOption
= pNextOption
;
719 } while ( pEnd
> pOption
);
724 Process the TFTP request
726 @param [in] pOption Address of the first zero terminated option string
727 @param [in] pValue Address to receive the value
729 @retval EFI_SUCCESS Option translated into a value
745 Status
= EFI_SUCCESS
;
748 // Walk the characters in the option
751 while ( 0 != *pOption
) {
753 // Convert the next digit to binary
756 if (( '0' <= Digit
) && ( '9' >= Digit
)) {
758 Value
+= Digit
- '0';
761 DEBUG (( DEBUG_ERROR
| DEBUG_TFTP_REQUEST
,
762 "ERROR - Invalid character '0x%02x' in the value\r\n",
764 Status
= EFI_INVALID_PARAMETER
;
775 // Return the conversion status
782 Process the TFTP request
784 @param [in] pTftpServer The TFTP server control structure address.
785 @param [in] pContext Connection context structure address
790 IN TSDT_TFTP_SERVER
* pTftpServer
,
791 IN TSDT_CONNECTION_CONTEXT
* pContext
794 BOOLEAN bCloseContext
;
795 BOOLEAN bIgnorePacket
;
810 pBuffer
= &pTftpServer
->RxBuffer
[0];
811 Opcode
= HTONS ( *(UINT16
*)&pBuffer
[0]);
812 Print ( L
"TFTP Opcode: 0x%08x\r\n", Opcode
);
815 // Validate the parameters
817 bCloseContext
= FALSE
;
818 bIgnorePacket
= FALSE
;
821 DEBUG (( DEBUG_TFTP_REQUEST
,
822 "ERROR - Unknown TFTP opcode: %d\r\n",
824 bIgnorePacket
= TRUE
;
827 case TFTP_OP_READ_REQUEST
:
831 if ( NULL
== pContext
) {
832 DEBUG (( DEBUG_ERROR
,
833 "ERROR - File not open for %d.%d.%d.%d:%d\r\n",
834 (UINT8
)pTftpServer
->RemoteAddress
.sin_addr
.s_addr
,
835 (UINT8
)( pTftpServer
->RemoteAddress
.sin_addr
.s_addr
>> 8 ),
836 (UINT8
)( pTftpServer
->RemoteAddress
.sin_addr
.s_addr
>> 16 ),
837 (UINT8
)( pTftpServer
->RemoteAddress
.sin_addr
.s_addr
>> 24 ),
838 htons ( pTftpServer
->RemoteAddress
.sin_port
)));
839 bIgnorePacket
= TRUE
;
842 if ( pContext
->bExpectAck
) {
843 DEBUG (( DEBUG_ERROR
,
844 "ERROR - Expecting ACKs not data for pContext 0x%08x\r\n",
846 bIgnorePacket
= TRUE
;
849 if ( pTftpServer
->RxBytes
> (ssize_t
)( pContext
->BlockSize
+ 2 + 2 )) {
850 DEBUG (( DEBUG_ERROR
,
851 "ERROR - Receive data length of %d > %d bytes (maximum block size) for pContext 0x%08x\r\n",
852 pTftpServer
->RxBytes
- 2 - 2,
855 bIgnorePacket
= TRUE
;
861 if ( NULL
== pContext
) {
862 DEBUG (( DEBUG_ERROR
,
863 "ERROR - File not open for %d.%d.%d.%d:%d\r\n",
864 (UINT8
)pTftpServer
->RemoteAddress
.sin_addr
.s_addr
,
865 (UINT8
)( pTftpServer
->RemoteAddress
.sin_addr
.s_addr
>> 8 ),
866 (UINT8
)( pTftpServer
->RemoteAddress
.sin_addr
.s_addr
>> 16 ),
867 (UINT8
)( pTftpServer
->RemoteAddress
.sin_addr
.s_addr
>> 24 ),
868 htons ( pTftpServer
->RemoteAddress
.sin_port
)));
869 bIgnorePacket
= TRUE
;
871 if ( !pContext
->bExpectAck
) {
872 DEBUG (( DEBUG_ERROR
,
873 "ERROR - Expecting data not ACKs for pContext 0x%08x\r\n",
875 bIgnorePacket
= TRUE
;
881 if ( NULL
== pContext
) {
882 DEBUG (( DEBUG_ERROR
,
883 "ERROR - File not open for %d.%d.%d.%d:%d\r\n",
884 (UINT8
)pTftpServer
->RemoteAddress
.sin_addr
.s_addr
,
885 (UINT8
)( pTftpServer
->RemoteAddress
.sin_addr
.s_addr
>> 8 ),
886 (UINT8
)( pTftpServer
->RemoteAddress
.sin_addr
.s_addr
>> 16 ),
887 (UINT8
)( pTftpServer
->RemoteAddress
.sin_addr
.s_addr
>> 24 ),
888 htons ( pTftpServer
->RemoteAddress
.sin_port
)));
889 bIgnorePacket
= TRUE
;
893 if ( !bIgnorePacket
) {
895 // Process the request
899 DEBUG (( DEBUG_TFTP_REQUEST
,
900 "ERROR - Unable to process TFTP opcode: %d\r\n",
904 case TFTP_OP_READ_REQUEST
:
907 // Close the context if necessary
909 if ( NULL
!= pContext
) {
910 ContextRemove ( pTftpServer
, pContext
);
914 // Create the connection context
916 pContext
= ContextAdd ( pTftpServer
);
917 if ( NULL
== pContext
) {
924 pFileName
= &pBuffer
[2];
925 pEnd
= &pBuffer
[pTftpServer
->RxBytes
];
927 while (( pEnd
> pMode
) && ( 0 != *pMode
)) {
930 if ( pEnd
<= pMode
) {
934 DEBUG (( DEBUG_ERROR
| DEBUG_RX
,
935 "ERROR - File mode not found\r\n" ));
937 // Tell the client of the error
939 TftpSendError ( pTftpServer
,
942 (UINT8
*)"File open mode not found" );
946 DEBUG (( DEBUG_TFTP_REQUEST
,
947 "TFTP - FileName: %a\n",
951 // Locate the options
954 while (( pEnd
> pOption
) && ( 0 != *pOption
)) {
957 if ( pEnd
<= pOption
) {
959 // End of mode not found
961 DEBUG (( DEBUG_ERROR
| DEBUG_RX
,
962 "ERROR - File mode not valid\r\n" ));
964 // Tell the client of the error
966 TftpSendError ( pTftpServer
,
969 (UINT8
*)"File open mode not valid" );
973 DEBUG (( DEBUG_TFTP_REQUEST
,
974 "TFTP - Mode: %a\r\n",
978 // Verify the mode is supported
980 if ( 0 != stricmp ((char *)pMode
, "octet" )) {
982 // File access mode not supported
984 DEBUG (( DEBUG_ERROR
| DEBUG_TFTP_REQUEST
,
985 "ERROR - File mode %a not supported\r\n",
989 // Tell the client of the error
991 TftpSendError ( pTftpServer
,
994 (UINT8
*)"File open mode not supported" );
999 // Open the file, close the context on error
1001 // TODO: Remove the following line
1002 pContext
->File
= (EFI_HANDLE
)1;
1005 // Determine the file length
1010 // Process the options
1012 TftpOptions ( pContext
, pOption
, pEnd
);
1015 // Read in the first portion of the file
1019 // Send the first block
1021 pContext
->bExpectAck
= TRUE
;
1022 if ( 2 < pContext
->TxBytes
) {
1026 Status
= TftpTxPacket ( pTftpServer
, pContext
);
1030 // Send the first block of data
1032 Status
= TftpSendNextBlock ( pTftpServer
, pContext
);
1038 // Get the block number that is being ACKed
1040 BlockNumber
= pTftpServer
->RxBuffer
[2];
1042 BlockNumber
|= pTftpServer
->RxBuffer
[3];
1045 // Determine if this is the correct ACK
1047 DEBUG (( DEBUG_TFTP_ACK
,
1048 "ACK for block 0x%04x received\r\n",
1050 if (( !pContext
->bExpectAck
)
1051 || ( BlockNumber
!= pContext
->AckNext
)) {
1052 DEBUG (( DEBUG_WARN
| DEBUG_TFTP_ACK
,
1053 "WARNING - Expecting ACK 0x%0x4 not received ACK 0x%08x\r\n",
1059 // Process the expected ACK
1061 if ( pContext
->bEofSent
) {
1062 bCloseContext
= TRUE
;
1066 // Set the next expected ACK
1068 pContext
->AckNext
+= 1;
1071 // Send the next packet of data
1073 Status
= TftpSendNextBlock ( pTftpServer
, pContext
);
1081 // Determine if the context should be closed
1083 if ( bCloseContext
) {
1084 ContextRemove ( pTftpServer
, pContext
);
1092 Build and send an error packet
1094 @param [in] pTftpServer The TFTP server control structure address.
1095 @param [in] pContext The context structure address.
1096 @param [in] Error Error number for the packet
1097 @param [in] pError Zero terminated error string address
1099 @retval EFI_SUCCESS Message processed successfully
1104 IN TSDT_TFTP_SERVER
* pTftpServer
,
1105 IN TSDT_CONNECTION_CONTEXT
* pContext
,
1117 // Build the error packet
1119 pBuffer
= &pContext
->TxBuffer
[0];
1121 pBuffer
[1] = TFTP_OP_ERROR
;
1122 pBuffer
[2] = (UINT8
)( Error
>> 8 );
1123 pBuffer
[3] = (UINT8
)Error
;
1126 // Copy the zero terminated string into the buffer
1130 Character
= *pError
++;
1131 *pBuffer
++ = Character
;
1132 } while ( 0 != Character
);
1135 // Send the error message
1137 pContext
->TxBytes
= pBuffer
- &pContext
->TxBuffer
[0];
1138 Status
= TftpTxPacket ( pTftpServer
, pContext
);
1141 // Return the operation status
1143 DBG_EXIT_STATUS ( Status
);
1149 Send the next block of file system data
1151 @param [in] pTftpServer The TFTP server control structure address.
1152 @param [in] pContext The context structure address.
1154 @retval EFI_SUCCESS Message processed successfully
1159 IN TSDT_TFTP_SERVER
* pTftpServer
,
1160 IN TSDT_CONNECTION_CONTEXT
* pContext
1163 ssize_t LengthInBytes
;
1168 // Determine how much data needs to be sent
1170 LengthInBytes
= pContext
->BlockSize
;
1171 if (( pContext
->LengthInBytes
< TFTP_MAX_BLOCK_SIZE
)
1172 || ( LengthInBytes
> (ssize_t
)pContext
->LengthInBytes
)) {
1173 LengthInBytes
= (ssize_t
)pContext
->LengthInBytes
;
1174 pContext
->bEofSent
= TRUE
;
1178 // Set the TFTP opcode and block number
1180 pBuffer
= &pContext
->TxBuffer
[0];
1182 *pBuffer
++ = TFTP_OP_DATA
;
1183 *pBuffer
++ = (UINT8
)( pContext
->AckNext
>> 8 );
1184 *pBuffer
++ = (UINT8
)pContext
->AckNext
;
1187 // Copy the file data into the transmit buffer
1189 pContext
->TxBytes
= 2 + 2 + LengthInBytes
;
1190 if ( 0 < LengthInBytes
) {
1197 // Send the next block
1199 Status
= TftpTxPacket ( pTftpServer
, pContext
);
1202 // Return the operation status
1209 Create the port for the TFTP server
1211 This routine polls the network layer to create the TFTP port for the
1212 TFTP server. More than one attempt may be necessary since it may take
1213 some time to get the IP address and initialize the upper layers of
1216 @param [in] pTftpServer The TFTP server control structure address.
1221 IN TSDT_TFTP_SERVER
* pTftpServer
1228 DEBUG (( DEBUG_SERVER_TIMER
, "Entering TftpServerTimer\r\n" ));
1231 // Open the TFTP port on the server
1238 Status
= gBS
->CheckEvent ( pTftpServer
->TimerEvent
);
1239 } while ( EFI_SUCCESS
!= Status
);
1242 // Attempt to create the socket for the TFTP server
1244 pTftpServer
->TftpPort
.events
= POLLRDNORM
| POLLHUP
;
1245 pTftpServer
->TftpPort
.revents
= 0;
1246 pTftpServer
->TftpPort
.fd
= socket ( AF_INET
,
1249 if ( -1 != pTftpServer
->TftpPort
.fd
) {
1251 // Set the socket address
1253 ZeroMem ( &pTftpServer
->TftpServerAddress
,
1254 sizeof ( pTftpServer
->TftpServerAddress
));
1256 DEBUG (( DEBUG_TFTP_PORT
,
1257 "TFTP Port: %d\r\n",
1259 pTftpServer
->TftpServerAddress
.sin_len
= sizeof ( pTftpServer
->TftpServerAddress
);
1260 pTftpServer
->TftpServerAddress
.sin_family
= AF_INET
;
1261 pTftpServer
->TftpServerAddress
.sin_addr
.s_addr
= INADDR_ANY
;
1262 pTftpServer
->TftpServerAddress
.sin_port
= htons ( TftpPort
);
1265 // Bind the socket to the TFTP port
1267 SocketStatus
= bind ( pTftpServer
->TftpPort
.fd
,
1268 (struct sockaddr
*) &pTftpServer
->TftpServerAddress
,
1269 pTftpServer
->TftpServerAddress
.sin_len
);
1270 if ( -1 != SocketStatus
) {
1271 DEBUG (( DEBUG_TFTP_PORT
,
1272 "0x%08x: Socket bound to port %d\r\n",
1273 pTftpServer
->TftpPort
.fd
,
1278 // Release the socket if necessary
1280 if ( -1 == SocketStatus
) {
1281 close ( pTftpServer
->TftpPort
.fd
);
1282 pTftpServer
->TftpPort
.fd
= -1;
1287 // Wait until the socket is open
1289 }while ( -1 == pTftpServer
->TftpPort
.fd
);
1291 DEBUG (( DEBUG_SERVER_TIMER
, "Exiting TftpServerTimer\r\n" ));
1296 Start the TFTP server port creation timer
1298 @param [in] pTftpServer The TFTP server control structure address.
1300 @retval EFI_SUCCESS The timer was successfully started.
1301 @retval EFI_ALREADY_STARTED The timer is already running.
1302 @retval Other The timer failed to start.
1306 TftpServerTimerStart (
1307 IN TSDT_TFTP_SERVER
* pTftpServer
1316 // Assume the timer is already running
1318 Status
= EFI_ALREADY_STARTED
;
1319 if ( !pTftpServer
->bTimerRunning
) {
1321 // Compute the poll interval
1323 TriggerTime
= TFTP_PORT_POLL_DELAY
* ( 1000 * 10 );
1324 Status
= gBS
->SetTimer ( pTftpServer
->TimerEvent
,
1327 if ( !EFI_ERROR ( Status
)) {
1328 DEBUG (( DEBUG_TFTP_PORT
, "TFTP port timer started\r\n" ));
1331 // Mark the timer running
1333 pTftpServer
->bTimerRunning
= TRUE
;
1336 DEBUG (( DEBUG_ERROR
| DEBUG_TFTP_PORT
,
1337 "ERROR - Failed to start TFTP port timer, Status: %r\r\n",
1343 // Return the operation status
1345 DBG_EXIT_STATUS ( Status
);
1351 Stop the TFTP server port creation timer
1353 @param [in] pTftpServer The TFTP server control structure address.
1355 @retval EFI_SUCCESS The TFTP port timer is stopped
1356 @retval Other Failed to stop the TFTP port timer
1360 TftpServerTimerStop (
1361 IN TSDT_TFTP_SERVER
* pTftpServer
1369 // Assume the timer is stopped
1371 Status
= EFI_SUCCESS
;
1372 if ( pTftpServer
->bTimerRunning
) {
1374 // Stop the port creation polling
1376 Status
= gBS
->SetTimer ( pTftpServer
->TimerEvent
,
1379 if ( !EFI_ERROR ( Status
)) {
1380 DEBUG (( DEBUG_TFTP_PORT
, "TFT[ port timer stopped\r\n" ));
1383 // Mark the timer stopped
1385 pTftpServer
->bTimerRunning
= FALSE
;
1388 DEBUG (( DEBUG_ERROR
| DEBUG_TFTP_PORT
,
1389 "ERROR - Failed to stop TFT[ port timer, Status: %r\r\n",
1395 // Return the operation status
1397 DBG_EXIT_STATUS ( Status
);
1402 Send the next TFTP packet
1404 @param [in] pTftpServer The TFTP server control structure address.
1405 @param [in] pContext The context structure address.
1407 @retval EFI_SUCCESS Message processed successfully
1412 IN TSDT_TFTP_SERVER
* pTftpServer
,
1413 IN TSDT_CONNECTION_CONTEXT
* pContext
1416 ssize_t LengthInBytes
;
1424 Status
= EFI_SUCCESS
;
1427 // Send the TFTP packet
1430 "0x%08x: pContext sending 0x%08x bytes\r\n",
1432 pContext
->TxBytes
));
1433 LengthInBytes
= sendto ( pTftpServer
->TftpPort
.fd
,
1434 &pContext
->TxBuffer
[0],
1437 (struct sockaddr
*)&pContext
->RemoteAddress
,
1438 pContext
->RemoteAddress
.sin_len
);
1439 if ( -1 == LengthInBytes
) {
1440 DEBUG (( DEBUG_ERROR
| DEBUG_TX
,
1441 "ERROR - Transmit failure, errno: 0x%08x\r\n",
1443 Status
= EFI_DEVICE_ERROR
;
1447 // Return the operation status
1449 DBG_EXIT_STATUS ( Status
);
1455 Entry point for the TFTP server application.
1457 @param [in] Argc The number of arguments
1458 @param [in] Argv The argument value array
1460 @retval 0 The application exited normally.
1461 @retval Other An error occurred.
1469 TSDT_TFTP_SERVER
* pTftpServer
;
1473 // Create a timer event to start TFTP port
1475 pTftpServer
= &mTftpServer
;
1476 Status
= gBS
->CreateEvent ( EVT_TIMER
,
1480 &pTftpServer
->TimerEvent
);
1481 if ( !EFI_ERROR ( Status
)) {
1482 Status
= TftpServerTimerStart ( pTftpServer
);
1483 if ( !EFI_ERROR ( Status
)) {
1485 // Run the TFTP server forever
1489 // Poll the network layer to create the TFTP port
1490 // for the tftp server. More than one attempt may
1491 // be necessary since it may take some time to get
1492 // the IP address and initialize the upper layers
1493 // of the network stack.
1495 TftpServerTimer ( pTftpServer
);
1498 // Poll the socket for activity
1501 SocketPoll ( pTftpServer
);
1502 } while ( -1 != pTftpServer
->TftpPort
.fd
);
1505 // TODO: Remove the following test code
1506 // Exit when the network connection is broken
1512 // Done with the timer event
1514 TftpServerTimerStop ( pTftpServer
);
1515 Status
= gBS
->CloseEvent ( pTftpServer
->TimerEvent
);
1520 // Return the final status
1522 DBG_EXIT_STATUS ( Status
);