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 ))
851 DEBUG (( DEBUG_ERROR
,
852 "ERROR - Receive data length of %d > %d bytes (maximum block size) for pContext 0x%08x\r\n",
853 pTftpServer
->RxBytes
- 2 - 2,
856 bIgnorePacket
= TRUE
;
862 if ( NULL
== pContext
) {
863 DEBUG (( DEBUG_ERROR
,
864 "ERROR - File not open for %d.%d.%d.%d:%d\r\n",
865 (UINT8
)pTftpServer
->RemoteAddress
.sin_addr
.s_addr
,
866 (UINT8
)( pTftpServer
->RemoteAddress
.sin_addr
.s_addr
>> 8 ),
867 (UINT8
)( pTftpServer
->RemoteAddress
.sin_addr
.s_addr
>> 16 ),
868 (UINT8
)( pTftpServer
->RemoteAddress
.sin_addr
.s_addr
>> 24 ),
869 htons ( pTftpServer
->RemoteAddress
.sin_port
)));
870 bIgnorePacket
= TRUE
;
872 if ( !pContext
->bExpectAck
) {
873 DEBUG (( DEBUG_ERROR
,
874 "ERROR - Expecting data not ACKs for pContext 0x%08x\r\n",
876 bIgnorePacket
= TRUE
;
882 if ( NULL
== pContext
) {
883 DEBUG (( DEBUG_ERROR
,
884 "ERROR - File not open for %d.%d.%d.%d:%d\r\n",
885 (UINT8
)pTftpServer
->RemoteAddress
.sin_addr
.s_addr
,
886 (UINT8
)( pTftpServer
->RemoteAddress
.sin_addr
.s_addr
>> 8 ),
887 (UINT8
)( pTftpServer
->RemoteAddress
.sin_addr
.s_addr
>> 16 ),
888 (UINT8
)( pTftpServer
->RemoteAddress
.sin_addr
.s_addr
>> 24 ),
889 htons ( pTftpServer
->RemoteAddress
.sin_port
)));
890 bIgnorePacket
= TRUE
;
894 if ( !bIgnorePacket
) {
896 // Process the request
900 DEBUG (( DEBUG_TFTP_REQUEST
,
901 "ERROR - Unable to process TFTP opcode: %d\r\n",
905 case TFTP_OP_READ_REQUEST
:
908 // Close the context if necessary
910 if ( NULL
!= pContext
) {
911 ContextRemove ( pTftpServer
, pContext
);
915 // Create the connection context
917 pContext
= ContextAdd ( pTftpServer
);
918 if ( NULL
== pContext
) {
925 pFileName
= &pBuffer
[2];
926 pEnd
= &pBuffer
[pTftpServer
->RxBytes
];
928 while (( pEnd
> pMode
) && ( 0 != *pMode
)) {
931 if ( pEnd
<= pMode
) {
935 DEBUG (( DEBUG_ERROR
| DEBUG_RX
,
936 "ERROR - File mode not found\r\n" ));
938 // Tell the client of the error
940 TftpSendError ( pTftpServer
,
943 (UINT8
*)"File open mode not found" );
947 DEBUG (( DEBUG_TFTP_REQUEST
,
948 "TFTP - FileName: %a\n",
952 // Locate the options
955 while (( pEnd
> pOption
) && ( 0 != *pOption
)) {
958 if ( pEnd
<= pOption
) {
960 // End of mode not found
962 DEBUG (( DEBUG_ERROR
| DEBUG_RX
,
963 "ERROR - File mode not valid\r\n" ));
965 // Tell the client of the error
967 TftpSendError ( pTftpServer
,
970 (UINT8
*)"File open mode not valid" );
974 DEBUG (( DEBUG_TFTP_REQUEST
,
975 "TFTP - Mode: %a\r\n",
979 // Verify the mode is supported
981 if ( 0 != stricmp ((char *)pMode
, "octet" )) {
983 // File access mode not supported
985 DEBUG (( DEBUG_ERROR
| DEBUG_TFTP_REQUEST
,
986 "ERROR - File mode %a not supported\r\n",
990 // Tell the client of the error
992 TftpSendError ( pTftpServer
,
995 (UINT8
*)"File open mode not supported" );
1000 // Open the file, close the context on error
1002 // TODO: Remove the following line
1003 pContext
->File
= (EFI_HANDLE
)1;
1006 // Determine the file length
1011 // Process the options
1013 TftpOptions ( pContext
, pOption
, pEnd
);
1016 // Read in the first portion of the file
1020 // Send the first block
1022 pContext
->bExpectAck
= TRUE
;
1023 if ( 2 < pContext
->TxBytes
) {
1027 Status
= TftpTxPacket ( pTftpServer
, pContext
);
1031 // Send the first block of data
1033 Status
= TftpSendNextBlock ( pTftpServer
, pContext
);
1039 // Get the block number that is being ACKed
1041 BlockNumber
= pTftpServer
->RxBuffer
[2];
1043 BlockNumber
|= pTftpServer
->RxBuffer
[3];
1046 // Determine if this is the correct ACK
1048 DEBUG (( DEBUG_TFTP_ACK
,
1049 "ACK for block 0x%04x received\r\n",
1051 if (( !pContext
->bExpectAck
)
1052 || ( BlockNumber
!= pContext
->AckNext
))
1054 DEBUG (( DEBUG_WARN
| DEBUG_TFTP_ACK
,
1055 "WARNING - Expecting ACK 0x%0x4 not received ACK 0x%08x\r\n",
1061 // Process the expected ACK
1063 if ( pContext
->bEofSent
) {
1064 bCloseContext
= TRUE
;
1068 // Set the next expected ACK
1070 pContext
->AckNext
+= 1;
1073 // Send the next packet of data
1075 Status
= TftpSendNextBlock ( pTftpServer
, pContext
);
1083 // Determine if the context should be closed
1085 if ( bCloseContext
) {
1086 ContextRemove ( pTftpServer
, pContext
);
1094 Build and send an error packet
1096 @param [in] pTftpServer The TFTP server control structure address.
1097 @param [in] pContext The context structure address.
1098 @param [in] Error Error number for the packet
1099 @param [in] pError Zero terminated error string address
1101 @retval EFI_SUCCESS Message processed successfully
1106 IN TSDT_TFTP_SERVER
* pTftpServer
,
1107 IN TSDT_CONNECTION_CONTEXT
* pContext
,
1119 // Build the error packet
1121 pBuffer
= &pContext
->TxBuffer
[0];
1123 pBuffer
[1] = TFTP_OP_ERROR
;
1124 pBuffer
[2] = (UINT8
)( Error
>> 8 );
1125 pBuffer
[3] = (UINT8
)Error
;
1128 // Copy the zero terminated string into the buffer
1132 Character
= *pError
++;
1133 *pBuffer
++ = Character
;
1134 } while ( 0 != Character
);
1137 // Send the error message
1139 pContext
->TxBytes
= pBuffer
- &pContext
->TxBuffer
[0];
1140 Status
= TftpTxPacket ( pTftpServer
, pContext
);
1143 // Return the operation status
1145 DBG_EXIT_STATUS ( Status
);
1151 Send the next block of file system data
1153 @param [in] pTftpServer The TFTP server control structure address.
1154 @param [in] pContext The context structure address.
1156 @retval EFI_SUCCESS Message processed successfully
1161 IN TSDT_TFTP_SERVER
* pTftpServer
,
1162 IN TSDT_CONNECTION_CONTEXT
* pContext
1165 ssize_t LengthInBytes
;
1170 // Determine how much data needs to be sent
1172 LengthInBytes
= pContext
->BlockSize
;
1173 if (( pContext
->LengthInBytes
< TFTP_MAX_BLOCK_SIZE
)
1174 || ( LengthInBytes
> (ssize_t
)pContext
->LengthInBytes
)) {
1175 LengthInBytes
= (ssize_t
)pContext
->LengthInBytes
;
1176 pContext
->bEofSent
= TRUE
;
1180 // Set the TFTP opcode and block number
1182 pBuffer
= &pContext
->TxBuffer
[0];
1184 *pBuffer
++ = TFTP_OP_DATA
;
1185 *pBuffer
++ = (UINT8
)( pContext
->AckNext
>> 8 );
1186 *pBuffer
++ = (UINT8
)pContext
->AckNext
;
1189 // Copy the file data into the transmit buffer
1191 pContext
->TxBytes
= 2 + 2 + LengthInBytes
;
1192 if ( 0 < LengthInBytes
) {
1199 // Send the next block
1201 Status
= TftpTxPacket ( pTftpServer
, pContext
);
1204 // Return the operation status
1211 Create the port for the TFTP server
1213 This routine polls the network layer to create the TFTP port for the
1214 TFTP server. More than one attempt may be necessary since it may take
1215 some time to get the IP address and initialize the upper layers of
1218 @param [in] pTftpServer The TFTP server control structure address.
1223 IN TSDT_TFTP_SERVER
* pTftpServer
1230 DEBUG (( DEBUG_SERVER_TIMER
, "Entering TftpServerTimer\r\n" ));
1233 // Open the TFTP port on the server
1240 Status
= gBS
->CheckEvent ( pTftpServer
->TimerEvent
);
1241 } while ( EFI_SUCCESS
!= Status
);
1244 // Attempt to create the socket for the TFTP server
1246 pTftpServer
->TftpPort
.events
= POLLRDNORM
| POLLHUP
;
1247 pTftpServer
->TftpPort
.revents
= 0;
1248 pTftpServer
->TftpPort
.fd
= socket ( AF_INET
,
1251 if ( -1 != pTftpServer
->TftpPort
.fd
)
1254 // Set the socket address
1256 ZeroMem ( &pTftpServer
->TftpServerAddress
,
1257 sizeof ( pTftpServer
->TftpServerAddress
));
1259 DEBUG (( DEBUG_TFTP_PORT
,
1260 "TFTP Port: %d\r\n",
1262 pTftpServer
->TftpServerAddress
.sin_len
= sizeof ( pTftpServer
->TftpServerAddress
);
1263 pTftpServer
->TftpServerAddress
.sin_family
= AF_INET
;
1264 pTftpServer
->TftpServerAddress
.sin_addr
.s_addr
= INADDR_ANY
;
1265 pTftpServer
->TftpServerAddress
.sin_port
= htons ( TftpPort
);
1268 // Bind the socket to the TFTP port
1270 SocketStatus
= bind ( pTftpServer
->TftpPort
.fd
,
1271 (struct sockaddr
*) &pTftpServer
->TftpServerAddress
,
1272 pTftpServer
->TftpServerAddress
.sin_len
);
1273 if ( -1 != SocketStatus
) {
1274 DEBUG (( DEBUG_TFTP_PORT
,
1275 "0x%08x: Socket bound to port %d\r\n",
1276 pTftpServer
->TftpPort
.fd
,
1281 // Release the socket if necessary
1283 if ( -1 == SocketStatus
) {
1284 close ( pTftpServer
->TftpPort
.fd
);
1285 pTftpServer
->TftpPort
.fd
= -1;
1290 // Wait until the socket is open
1292 }while ( -1 == pTftpServer
->TftpPort
.fd
);
1294 DEBUG (( DEBUG_SERVER_TIMER
, "Exiting TftpServerTimer\r\n" ));
1299 Start the TFTP server port creation timer
1301 @param [in] pTftpServer The TFTP server control structure address.
1303 @retval EFI_SUCCESS The timer was successfully started.
1304 @retval EFI_ALREADY_STARTED The timer is already running.
1305 @retval Other The timer failed to start.
1309 TftpServerTimerStart (
1310 IN TSDT_TFTP_SERVER
* pTftpServer
1319 // Assume the timer is already running
1321 Status
= EFI_ALREADY_STARTED
;
1322 if ( !pTftpServer
->bTimerRunning
) {
1324 // Compute the poll interval
1326 TriggerTime
= TFTP_PORT_POLL_DELAY
* ( 1000 * 10 );
1327 Status
= gBS
->SetTimer ( pTftpServer
->TimerEvent
,
1330 if ( !EFI_ERROR ( Status
)) {
1331 DEBUG (( DEBUG_TFTP_PORT
, "TFTP port timer started\r\n" ));
1334 // Mark the timer running
1336 pTftpServer
->bTimerRunning
= TRUE
;
1339 DEBUG (( DEBUG_ERROR
| DEBUG_TFTP_PORT
,
1340 "ERROR - Failed to start TFTP port timer, Status: %r\r\n",
1346 // Return the operation status
1348 DBG_EXIT_STATUS ( Status
);
1354 Stop the TFTP server port creation timer
1356 @param [in] pTftpServer The TFTP server control structure address.
1358 @retval EFI_SUCCESS The TFTP port timer is stopped
1359 @retval Other Failed to stop the TFTP port timer
1363 TftpServerTimerStop (
1364 IN TSDT_TFTP_SERVER
* pTftpServer
1372 // Assume the timer is stopped
1374 Status
= EFI_SUCCESS
;
1375 if ( pTftpServer
->bTimerRunning
) {
1377 // Stop the port creation polling
1379 Status
= gBS
->SetTimer ( pTftpServer
->TimerEvent
,
1382 if ( !EFI_ERROR ( Status
)) {
1383 DEBUG (( DEBUG_TFTP_PORT
, "TFT[ port timer stopped\r\n" ));
1386 // Mark the timer stopped
1388 pTftpServer
->bTimerRunning
= FALSE
;
1391 DEBUG (( DEBUG_ERROR
| DEBUG_TFTP_PORT
,
1392 "ERROR - Failed to stop TFT[ port timer, Status: %r\r\n",
1398 // Return the operation status
1400 DBG_EXIT_STATUS ( Status
);
1405 Send the next TFTP packet
1407 @param [in] pTftpServer The TFTP server control structure address.
1408 @param [in] pContext The context structure address.
1410 @retval EFI_SUCCESS Message processed successfully
1415 IN TSDT_TFTP_SERVER
* pTftpServer
,
1416 IN TSDT_CONNECTION_CONTEXT
* pContext
1419 ssize_t LengthInBytes
;
1427 Status
= EFI_SUCCESS
;
1430 // Send the TFTP packet
1433 "0x%08x: pContext sending 0x%08x bytes\r\n",
1435 pContext
->TxBytes
));
1436 LengthInBytes
= sendto ( pTftpServer
->TftpPort
.fd
,
1437 &pContext
->TxBuffer
[0],
1440 (struct sockaddr
*)&pContext
->RemoteAddress
,
1441 pContext
->RemoteAddress
.sin_len
);
1442 if ( -1 == LengthInBytes
) {
1443 DEBUG (( DEBUG_ERROR
| DEBUG_TX
,
1444 "ERROR - Transmit failure, errno: 0x%08x\r\n",
1446 Status
= EFI_DEVICE_ERROR
;
1450 // Return the operation status
1452 DBG_EXIT_STATUS ( Status
);
1458 Entry point for the TFTP server application.
1460 @param [in] Argc The number of arguments
1461 @param [in] Argv The argument value array
1463 @retval 0 The application exited normally.
1464 @retval Other An error occurred.
1472 TSDT_TFTP_SERVER
* pTftpServer
;
1476 // Create a timer event to start TFTP port
1478 pTftpServer
= &mTftpServer
;
1479 Status
= gBS
->CreateEvent ( EVT_TIMER
,
1483 &pTftpServer
->TimerEvent
);
1484 if ( !EFI_ERROR ( Status
)) {
1485 Status
= TftpServerTimerStart ( pTftpServer
);
1486 if ( !EFI_ERROR ( Status
)) {
1488 // Run the TFTP server forever
1492 // Poll the network layer to create the TFTP port
1493 // for the tftp server. More than one attempt may
1494 // be necessary since it may take some time to get
1495 // the IP address and initialize the upper layers
1496 // of the network stack.
1498 TftpServerTimer ( pTftpServer
);
1501 // Poll the socket for activity
1504 SocketPoll ( pTftpServer
);
1505 } while ( -1 != pTftpServer
->TftpPort
.fd
);
1508 // TODO: Remove the following test code
1509 // Exit when the network connection is broken
1515 // Done with the timer event
1517 TftpServerTimerStop ( pTftpServer
);
1518 Status
= gBS
->CloseEvent ( pTftpServer
->TimerEvent
);
1523 // Return the final status
1525 DBG_EXIT_STATUS ( Status
);