1da3c250d56693672762deda02d8d91fbe3fb705
[mirror_edk2.git] / AppPkg / Applications / Sockets / TftpServer / TftpServer.c
1 /*++
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
6 license agreement
7 --*/
8 /*++
9
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
17 Intel Corporation.
18
19 --*/
20
21 /** @file
22 This is a simple TFTP server application
23
24 **/
25
26 #include <TftpServer.h>
27
28 TSDT_TFTP_SERVER mTftpServer; ///< TFTP server's control structure
29
30
31 /**
32 Add a connection context to the list of connection contexts.
33
34 @param [in] pTftpServer The TFTP server control structure address.
35
36 @retval Context structure address, NULL if allocation fails
37
38 **/
39 TSDT_CONNECTION_CONTEXT *
40 ContextAdd (
41 IN TSDT_TFTP_SERVER * pTftpServer
42 )
43 {
44 size_t LengthInBytes;
45 TSDT_CONNECTION_CONTEXT * pContext;
46 EFI_STATUS Status;
47
48 DBG_ENTER ( );
49
50 //
51 // Use for/break instead of goto
52 //
53 for ( ; ; ) {
54 //
55 // Allocate a new context
56 //
57 LengthInBytes = sizeof ( *pContext );
58 Status = gBS->AllocatePool ( EfiRuntimeServicesData,
59 LengthInBytes,
60 (VOID **)&pContext );
61 if ( EFI_ERROR ( Status )) {
62 DEBUG (( DEBUG_ERROR | DEBUG_POOL,
63 "ERROR - Failed to allocate the context, Status: %r\r\n",
64 Status ));
65 pContext = NULL;
66 break;
67 }
68
69 //
70 // Initialize the context
71 //
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;
81
82 //
83 // Display the new context
84 //
85 DEBUG (( DEBUG_PORT_WORK | DEBUG_INFO,
86 "0x%08x: Context for %d.%d.%d.%d:%d\r\n",
87 pContext,
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 )));
93
94 //
95 // Add the context to the context list
96 //
97 pContext->pNext = pTftpServer->pContextList;
98 pTftpServer->pContextList = pContext;
99
100 //
101 // All done
102 //
103 break;
104 }
105
106 //
107 // Return the connection context
108 //
109 DBG_EXIT_STATUS ( pContext );
110 return pContext;
111 }
112
113
114 /**
115 Locate a remote connection context.
116
117 @param [in] pTftpServer The TFTP server control structure address.
118
119 @param [in] pIpAddress The start of the remote IP address in network order
120
121 @param [in] Port The remote port number
122
123 @retval Context structure address, NULL if not found
124
125 **/
126 TSDT_CONNECTION_CONTEXT *
127 ContextFind (
128 IN TSDT_TFTP_SERVER * pTftpServer
129 )
130 {
131 TSDT_CONNECTION_CONTEXT * pContext;
132
133 DBG_ENTER ( );
134
135 //
136 // Walk the list of connection contexts
137 //
138 pContext = pTftpServer->pContextList;
139 while ( NULL != pContext ) {
140 //
141 // Attempt to locate the remote network connection
142 //
143 if (( pTftpServer->RemoteAddress.sin_addr.s_addr == pContext->RemoteAddress.sin_addr.s_addr )
144 && ( pTftpServer->RemoteAddress.sin_port == pContext->RemoteAddress.sin_port )) {
145 //
146 // The connection was found
147 //
148 DEBUG (( DEBUG_TFTP_REQUEST,
149 "0x%08x: pContext found\r\n",
150 pContext ));
151 break;
152 }
153
154 //
155 // Set the next context
156 //
157 pContext = pContext->pNext;
158 }
159
160 //
161 // Return the connection context structure address
162 //
163 DBG_EXIT_HEX ( pContext );
164 return pContext;
165 }
166
167
168 /**
169 Remove a context from the list.
170
171 @param [in] pTftpServer The TFTP server control structure address.
172
173 @param [in] pContext The context structure address.
174
175 **/
176 VOID
177 ContextRemove (
178 IN TSDT_TFTP_SERVER * pTftpServer,
179 IN TSDT_CONNECTION_CONTEXT * pContext
180 )
181 {
182 TSDT_CONNECTION_CONTEXT * pNextContext;
183 TSDT_CONNECTION_CONTEXT * pPreviousContext;
184
185 DBG_ENTER ( );
186
187 //
188 // Attempt to locate the context in the list
189 //
190 pPreviousContext = NULL;
191 pNextContext = pTftpServer->pContextList;
192 while ( NULL != pNextContext ) {
193 //
194 // Determine if the context was found
195 //
196 if ( pNextContext == pContext ) {
197 //
198 // Remove the context from the list
199 //
200 if ( NULL == pPreviousContext ) {
201 pTftpServer->pContextList = pContext->pNext;
202 }
203 else {
204 pPreviousContext->pNext = pContext->pNext;
205 }
206 break;
207 }
208
209 //
210 // Set the next context
211 //
212 pPreviousContext = pNextContext;
213 pNextContext = pNextContext->pNext;
214 }
215
216 //
217 // Determine if the context was found
218 //
219 if ( NULL != pContext ) {
220 //
221 // Return the resources
222 //
223 gBS->FreePool ( pContext );
224 }
225
226 DBG_EXIT ( );
227 }
228
229
230 /**
231 Process the work for the sockets.
232
233 @param [in] pTftpServer The TFTP server control structure address.
234
235 **/
236 VOID
237 PortWork (
238 IN TSDT_TFTP_SERVER * pTftpServer
239 )
240 {
241 TSDT_CONNECTION_CONTEXT * pContext;
242 socklen_t RemoteAddressLength;
243
244 DBG_ENTER ( );
245
246 //
247 // Handle input events
248 //
249 if ( 0 != ( pTftpServer->TftpPort.revents & POLLRDNORM )) {
250 //
251 // Receive the message from the remote system
252 //
253 RemoteAddressLength = sizeof ( pTftpServer->RemoteAddress );
254 pTftpServer->RxBytes = recvfrom ( pTftpServer->TftpPort.fd,
255 &pTftpServer->RxBuffer[0],
256 sizeof ( pTftpServer->RxBuffer ),
257 0,
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 )));
270
271 //
272 // Lookup connection context using the remote system address and port
273 // to determine if an existing connection to this remote
274 // system exists
275 //
276 pContext = ContextFind ( pTftpServer );
277
278 //
279 // Process the received message
280 //
281 TftpProcessRequest ( pTftpServer, pContext );
282 }
283 else {
284 //
285 // Receive error on the TFTP server port
286 // Close the server socket
287 //
288 DEBUG (( DEBUG_ERROR,
289 "ERROR - Failed receive on TFTP server port, errno: 0x%08x\r\n",
290 errno ));
291 pTftpServer->TftpPort.revents |= POLLHUP;
292 }
293 }
294
295 //
296 // Handle the close event
297 //
298 if ( 0 != ( pTftpServer->TftpPort.revents & POLLHUP )) {
299 //
300 // Close the port
301 //
302 close ( pTftpServer->TftpPort.fd );
303 pTftpServer->TftpPort.fd = -1;
304 }
305
306 DBG_EXIT ( );
307 }
308
309
310 /**
311 Scan the list of sockets and process any pending work
312
313 @param [in] pTftpServer The TFTP server control structure address.
314
315 **/
316 VOID
317 SocketPoll (
318 IN TSDT_TFTP_SERVER * pTftpServer
319 )
320 {
321 int FDCount;
322
323 DEBUG (( DEBUG_SOCKET_POLL, "Entering SocketPoll\r\n" ));
324
325 //
326 // Determine if any ports are active
327 //
328 FDCount = poll ( &pTftpServer->TftpPort,
329 1,
330 CLIENT_POLL_DELAY );
331 if ( -1 == FDCount ) {
332 DEBUG (( DEBUG_ERROR | DEBUG_SOCKET_POLL,
333 "ERROR - errno: %d\r\n",
334 errno ));
335 }
336
337 if ( 0 < FDCount ) {
338 //
339 // Process this port
340 //
341 PortWork ( pTftpServer );
342 pTftpServer->TftpPort.revents = 0;
343 }
344
345 DEBUG (( DEBUG_SOCKET_POLL, "Exiting SocketPoll\r\n" ));
346 }
347
348
349 /**
350 Convert a character to lower case
351
352 @param [in] Character The character to convert
353
354 @return The lower case equivalent of the character
355
356 **/
357 int
358 tolower (
359 int Character
360 )
361 {
362 //
363 // Determine if the character is upper case
364 //
365 if (( 'A' <= Character ) && ( 'Z' >= Character )) {
366 //
367 // Convert the character to lower caes
368 //
369 Character += 'a' - 'A';
370 }
371
372 //
373 // Return the converted character
374 //
375 return Character;
376 }
377
378
379 /**
380 Case independent string comparison
381
382 @param [in] pString1 Zero terminated string address
383 @param [in] pString2 Zero terminated string address
384
385 @return Returns the first character difference between string 1
386 and string 2.
387
388 **/
389 int
390 stricmp (
391 char * pString1,
392 char * pString2
393 )
394 {
395 int Char1;
396 int Char2;
397 int Difference;
398
399 //
400 // Walk the length of the strings
401 //
402 do {
403 //
404 // Get the next characters
405 //
406 Char1 = (UINT8)*pString1++;
407 Char2 = (UINT8)*pString2++;
408
409 //
410 // Convert them to lower case
411 //
412 Char1 = tolower ( Char1 );
413 Char2 = tolower ( Char2 );
414
415 //
416 // Done when the characters differ
417 //
418 Difference = Char1 - Char2;
419 if ( 0 != Difference ) {
420 break;
421 }
422
423 //
424 // Done at the end of the string
425 //
426 } while ( 0 != Char1 );
427
428 //
429 // Return the difference
430 //
431 return Difference;
432 }
433
434
435 /**
436 Get the next TFTP option
437
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
442
443 @retval EFI_SUCCESS Message processed successfully
444
445 **/
446 EFI_STATUS
447 TftpOptionGet (
448 IN UINT8 * pOption,
449 IN UINT8 * pEnd,
450 IN UINT8 ** ppNextOption
451 )
452 {
453 UINT8 * pNextOption;
454 EFI_STATUS Status;
455
456 //
457 // Locate the end of the option
458 //
459 pNextOption = pOption;
460 while (( pEnd > pNextOption ) && ( 0 != *pNextOption )) {
461 pNextOption += 1;
462 }
463 if ( pEnd <= pNextOption ) {
464 //
465 // Error - end of buffer reached
466 //
467 DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST,
468 "ERROR - Option without zero termination received!\r\n" ));
469 Status = EFI_INVALID_PARAMETER;
470 }
471 else {
472 //
473 // Zero terminated option found
474 //
475 pNextOption += 1;
476
477 //
478 // Display the zero terminated ASCII option string
479 //
480 DEBUG (( DEBUG_TFTP_REQUEST,
481 "Option: %a\r\n",
482 pOption ));
483 Status = EFI_SUCCESS;
484 }
485
486 //
487 // Return the next option address
488 //
489 *ppNextOption = pNextOption;
490
491 //
492 // Return the operation status
493 //
494 return Status;
495 }
496
497
498 /**
499 Place an option value into the option acknowledgement
500
501 @param [in] pOack Option acknowledgement address
502 @param [in] Value Value to translate into ASCII decimal
503
504 @return Option acknowledgement address
505
506 **/
507 UINT8 *
508 TftpOptionSet (
509 IN UINT8 * pOack,
510 IN UINT64 Value
511 )
512 {
513 UINT64 NextValue;
514
515 //
516 // Determine the next value
517 //
518 NextValue = Value / 10;
519
520 //
521 // Supress leading zeros
522 //
523 if ( 0 != NextValue ) {
524 pOack = TftpOptionSet ( pOack, NextValue );
525 }
526
527 //
528 // Output this digit
529 //
530 *pOack++ = (UINT8)( Value - ( NextValue * 10 ) + '0' );
531
532 //
533 // Return the next option acknowledgement location
534 //
535 return pOack;
536 }
537
538
539 /**
540 Process the TFTP request
541
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
545
546 **/
547 VOID
548 TftpOptions (
549 IN TSDT_CONNECTION_CONTEXT * pContext,
550 IN UINT8 * pOption,
551 IN UINT8 * pEnd
552 )
553 {
554 UINT8 * pNextOption;
555 UINT8 * pOack;
556 UINT8 * pTemp;
557 UINT8 * pValue;
558 EFI_STATUS Status;
559 INT32 Value;
560
561 //
562 // Start the OACK packet
563 // Let the OACK handle the parsing errors
564 // See http://tools.ietf.org/html/rfc2347
565 //
566 pOack = &pContext->TxBuffer[0];
567 *pOack++ = 0;
568 *pOack++ = TFTP_OP_OACK;
569 pContext->TxBytes = 2;
570
571 //
572 // Walk the list of options
573 //
574 do {
575 //
576 // Get the next option, skip junk at end of message
577 //
578 Status = TftpOptionGet ( pOption, pEnd, &pNextOption );
579 if ( !EFI_ERROR ( Status )) {
580 //
581 // Process the option
582 //
583
584 //
585 // blksize - See http://tools.ietf.org/html/rfc2348
586 //
587 pValue = pNextOption;
588 if ( 0 == stricmp ((char *)pOption, "blksize" )) {
589 //
590 // Get the value
591 //
592 Status = TftpOptionGet ( pValue, pEnd, &pNextOption );
593 if ( !EFI_ERROR ( Status )) {
594 //
595 // Validate the block size, skip non-numeric block sizes
596 //
597 Status = TftpOptionValue ( pValue, &Value );
598 if ( !EFI_ERROR ( Status )) {
599 //
600 // Propose a smaller block size if necessary
601 //
602 if ( Value > TFTP_MAX_BLOCK_SIZE ) {
603 Value = TFTP_MAX_BLOCK_SIZE;
604 }
605
606 //
607 // Set the new block size
608 //
609 pContext->BlockSize = Value;
610 DEBUG (( DEBUG_TFTP_REQUEST,
611 "Using block size of %d bytes\r\n",
612 pContext->BlockSize ));
613
614 //
615 // Update the OACK
616 //
617 pTemp = pOack;
618 *pOack++ = 'b';
619 *pOack++ = 'l';
620 *pOack++ = 'k';
621 *pOack++ = 's';
622 *pOack++ = 'i';
623 *pOack++ = 'z';
624 *pOack++ = 'e';
625 *pOack++ = 0;
626 pOack = TftpOptionSet ( pOack, pContext->BlockSize );
627 *pOack++ = 0;
628 pContext->TxBytes += pOack - pTemp;
629 }
630 }
631 }
632
633 //
634 // timeout - See http://tools.ietf.org/html/rfc2349
635 //
636 else if ( 0 == stricmp ((char *)pOption, "timeout" )) {
637 //
638 // Get the value
639 //
640 Status = TftpOptionGet ( pValue, pEnd, &pNextOption );
641 if ( !EFI_ERROR ( Status )) {
642 Status = TftpOptionValue ( pValue, &Value );
643 if ( !EFI_ERROR ( Status )) {
644 //
645 // Set the timeout value
646 //
647 pContext->Timeout = Value;
648 DEBUG (( DEBUG_TFTP_REQUEST,
649 "Using timeout of %d seconds\r\n",
650 pContext->Timeout ));
651
652 //
653 // Update the OACK
654 //
655 pTemp = pOack;
656 *pOack++ = 't';
657 *pOack++ = 'i';
658 *pOack++ = 'm';
659 *pOack++ = 'e';
660 *pOack++ = 'o';
661 *pOack++ = 'u';
662 *pOack++ = 't';
663 *pOack++ = 0;
664 pOack = TftpOptionSet ( pOack, pContext->Timeout );
665 *pOack++ = 0;
666 pContext->TxBytes += pOack - pTemp;
667 }
668 }
669 }
670
671 //
672 // tsize - See http://tools.ietf.org/html/rfc2349
673 //
674 else if ( 0 == stricmp ((char *)pOption, "tsize" )) {
675 //
676 // Get the value
677 //
678 Status = TftpOptionGet ( pValue, pEnd, &pNextOption );
679 if ( !EFI_ERROR ( Status )) {
680 Status = TftpOptionValue ( pValue, &Value );
681 if ( !EFI_ERROR ( Status )) {
682 //
683 // Return the file size
684 //
685 DEBUG (( DEBUG_TFTP_REQUEST,
686 "Returning file size of %Ld bytes\r\n",
687 pContext->LengthInBytes ));
688
689 //
690 // Update the OACK
691 //
692 pTemp = pOack;
693 *pOack++ = 't';
694 *pOack++ = 's';
695 *pOack++ = 'i';
696 *pOack++ = 'z';
697 *pOack++ = 'e';
698 *pOack++ = 0;
699 pOack = TftpOptionSet ( pOack, pContext->LengthInBytes );
700 *pOack++ = 0;
701 pContext->TxBytes += pOack - pTemp;
702 }
703 }
704 }
705 else {
706 //
707 // Unknown option - Ignore it
708 //
709 DEBUG (( DEBUG_WARN | DEBUG_TFTP_REQUEST,
710 "WARNING - Skipping unknown option: %a\r\n",
711 pOption ));
712 }
713 }
714
715 //
716 // Set the next option
717 //
718 pOption = pNextOption;
719 } while ( pEnd > pOption );
720 }
721
722
723 /**
724 Process the TFTP request
725
726 @param [in] pOption Address of the first zero terminated option string
727 @param [in] pValue Address to receive the value
728
729 @retval EFI_SUCCESS Option translated into a value
730
731 **/
732 EFI_STATUS
733 TftpOptionValue (
734 IN UINT8 * pOption,
735 IN INT32 * pValue
736 )
737 {
738 UINT8 Digit;
739 EFI_STATUS Status;
740 INT32 Value;
741
742 //
743 // Assume success
744 //
745 Status = EFI_SUCCESS;
746
747 //
748 // Walk the characters in the option
749 //
750 Value = 0;
751 while ( 0 != *pOption ) {
752 //
753 // Convert the next digit to binary
754 //
755 Digit = *pOption++;
756 if (( '0' <= Digit ) && ( '9' >= Digit )) {
757 Value *= 10;
758 Value += Digit - '0';
759 }
760 else {
761 DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST,
762 "ERROR - Invalid character '0x%02x' in the value\r\n",
763 Digit ));
764 Status = EFI_INVALID_PARAMETER;
765 break;
766 }
767 }
768
769 //
770 // Return the value
771 //
772 *pValue = Value;
773
774 //
775 // Return the conversion status
776 //
777 return Status;
778 }
779
780
781 /**
782 Process the TFTP request
783
784 @param [in] pTftpServer The TFTP server control structure address.
785 @param [in] pContext Connection context structure address
786
787 **/
788 VOID
789 TftpProcessRequest (
790 IN TSDT_TFTP_SERVER * pTftpServer,
791 IN TSDT_CONNECTION_CONTEXT * pContext
792 )
793 {
794 BOOLEAN bCloseContext;
795 BOOLEAN bIgnorePacket;
796 UINT16 BlockNumber;
797 UINT16 Opcode;
798 UINT8 * pBuffer;
799 UINT8 * pEnd;
800 UINT8 * pFileName;
801 UINT8 * pMode;
802 UINT8 * pOption;
803 EFI_STATUS Status;
804
805 DBG_ENTER ( );
806
807 //
808 // Get the opcode
809 //
810 pBuffer = &pTftpServer->RxBuffer[0];
811 Opcode = HTONS ( *(UINT16 *)&pBuffer[0]);
812 Print ( L"TFTP Opcode: 0x%08x\r\n", Opcode );
813
814 //
815 // Validate the parameters
816 //
817 bCloseContext = FALSE;
818 bIgnorePacket = FALSE;
819 switch ( Opcode ) {
820 default:
821 DEBUG (( DEBUG_TFTP_REQUEST,
822 "ERROR - Unknown TFTP opcode: %d\r\n",
823 Opcode ));
824 bIgnorePacket = TRUE;
825 break;
826
827 case TFTP_OP_READ_REQUEST:
828 break;
829
830 case TFTP_OP_DATA:
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;
840 break;
841 }
842 if ( pContext->bExpectAck ) {
843 DEBUG (( DEBUG_ERROR,
844 "ERROR - Expecting ACKs not data for pContext 0x%08x\r\n",
845 pContext ));
846 bIgnorePacket = TRUE;
847 break;
848 }
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,
853 pContext->BlockSize,
854 pContext ));
855 bIgnorePacket = TRUE;
856 break;
857 }
858 break;
859
860 case TFTP_OP_ACK:
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;
870 }
871 if ( !pContext->bExpectAck ) {
872 DEBUG (( DEBUG_ERROR,
873 "ERROR - Expecting data not ACKs for pContext 0x%08x\r\n",
874 pContext ));
875 bIgnorePacket = TRUE;
876 break;
877 }
878 break;
879
880 case TFTP_OP_ERROR:
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;
890 }
891 break;
892 }
893 if ( !bIgnorePacket ) {
894 //
895 // Process the request
896 //
897 switch ( Opcode ) {
898 default:
899 DEBUG (( DEBUG_TFTP_REQUEST,
900 "ERROR - Unable to process TFTP opcode: %d\r\n",
901 Opcode ));
902 break;
903
904 case TFTP_OP_READ_REQUEST:
905
906 //
907 // Close the context if necessary
908 //
909 if ( NULL != pContext ) {
910 ContextRemove ( pTftpServer, pContext );
911 }
912
913 //
914 // Create the connection context
915 //
916 pContext = ContextAdd ( pTftpServer );
917 if ( NULL == pContext ) {
918 break;
919 }
920
921 //
922 // Locate the mode
923 //
924 pFileName = &pBuffer[2];
925 pEnd = &pBuffer[pTftpServer->RxBytes];
926 pMode = pFileName;
927 while (( pEnd > pMode ) && ( 0 != *pMode )) {
928 pMode += 1;
929 }
930 if ( pEnd <= pMode ) {
931 //
932 // Mode not found
933 //
934 DEBUG (( DEBUG_ERROR | DEBUG_RX,
935 "ERROR - File mode not found\r\n" ));
936 //
937 // Tell the client of the error
938 //
939 TftpSendError ( pTftpServer,
940 pContext,
941 0,
942 (UINT8 *)"File open mode not found" );
943 break;
944 }
945 pMode += 1;
946 DEBUG (( DEBUG_TFTP_REQUEST,
947 "TFTP - FileName: %a\n",
948 pFileName ));
949
950 //
951 // Locate the options
952 //
953 pOption = pMode;
954 while (( pEnd > pOption ) && ( 0 != *pOption )) {
955 pOption += 1;
956 }
957 if ( pEnd <= pOption ) {
958 //
959 // End of mode not found
960 //
961 DEBUG (( DEBUG_ERROR | DEBUG_RX,
962 "ERROR - File mode not valid\r\n" ));
963 //
964 // Tell the client of the error
965 //
966 TftpSendError ( pTftpServer,
967 pContext,
968 0,
969 (UINT8 *)"File open mode not valid" );
970 break;
971 }
972 pOption += 1;
973 DEBUG (( DEBUG_TFTP_REQUEST,
974 "TFTP - Mode: %a\r\n",
975 pMode ));
976
977 //
978 // Verify the mode is supported
979 //
980 if ( 0 != stricmp ((char *)pMode, "octet" )) {
981 //
982 // File access mode not supported
983 //
984 DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST,
985 "ERROR - File mode %a not supported\r\n",
986 pMode ));
987
988 //
989 // Tell the client of the error
990 //
991 TftpSendError ( pTftpServer,
992 pContext,
993 0,
994 (UINT8 *)"File open mode not supported" );
995 break;
996 }
997
998 //
999 // Open the file, close the context on error
1000 //
1001 // TODO: Remove the following line
1002 pContext->File = (EFI_HANDLE)1;
1003
1004 //
1005 // Determine the file length
1006 //
1007 //fstat
1008
1009 //
1010 // Process the options
1011 //
1012 TftpOptions ( pContext, pOption, pEnd );
1013
1014 //
1015 // Read in the first portion of the file
1016 //
1017
1018 //
1019 // Send the first block
1020 //
1021 pContext->bExpectAck = TRUE;
1022 if ( 2 < pContext->TxBytes ) {
1023 //
1024 // Send the OACK
1025 //
1026 Status = TftpTxPacket ( pTftpServer, pContext );
1027 }
1028 else {
1029 //
1030 // Send the first block of data
1031 //
1032 Status = TftpSendNextBlock ( pTftpServer, pContext );
1033 }
1034 break;
1035
1036 case TFTP_OP_ACK:
1037 //
1038 // Get the block number that is being ACKed
1039 //
1040 BlockNumber = pTftpServer->RxBuffer[2];
1041 BlockNumber <<= 8;
1042 BlockNumber |= pTftpServer->RxBuffer[3];
1043
1044 //
1045 // Determine if this is the correct ACK
1046 //
1047 DEBUG (( DEBUG_TFTP_ACK,
1048 "ACK for block 0x%04x received\r\n",
1049 BlockNumber ));
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",
1054 pContext->AckNext,
1055 BlockNumber ));
1056 }
1057 else {
1058 //
1059 // Process the expected ACK
1060 //
1061 if ( pContext->bEofSent ) {
1062 bCloseContext = TRUE;
1063 }
1064 else {
1065 //
1066 // Set the next expected ACK
1067 //
1068 pContext->AckNext += 1;
1069
1070 //
1071 // Send the next packet of data
1072 //
1073 Status = TftpSendNextBlock ( pTftpServer, pContext );
1074 }
1075 }
1076 break;
1077 }
1078 }
1079
1080 //
1081 // Determine if the context should be closed
1082 //
1083 if ( bCloseContext ) {
1084 ContextRemove ( pTftpServer, pContext );
1085 }
1086
1087 DBG_EXIT ( );
1088 }
1089
1090
1091 /**
1092 Build and send an error packet
1093
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
1098
1099 @retval EFI_SUCCESS Message processed successfully
1100
1101 **/
1102 EFI_STATUS
1103 TftpSendError (
1104 IN TSDT_TFTP_SERVER * pTftpServer,
1105 IN TSDT_CONNECTION_CONTEXT * pContext,
1106 IN UINT16 Error,
1107 IN UINT8 * pError
1108 )
1109 {
1110 UINT8 Character;
1111 UINT8 * pBuffer;
1112 EFI_STATUS Status;
1113
1114 DBG_ENTER ( );
1115
1116 //
1117 // Build the error packet
1118 //
1119 pBuffer = &pContext->TxBuffer[0];
1120 pBuffer[0] = 0;
1121 pBuffer[1] = TFTP_OP_ERROR;
1122 pBuffer[2] = (UINT8)( Error >> 8 );
1123 pBuffer[3] = (UINT8)Error;
1124
1125 //
1126 // Copy the zero terminated string into the buffer
1127 //
1128 pBuffer += 4;
1129 do {
1130 Character = *pError++;
1131 *pBuffer++ = Character;
1132 } while ( 0 != Character );
1133
1134 //
1135 // Send the error message
1136 //
1137 pContext->TxBytes = pBuffer - &pContext->TxBuffer[0];
1138 Status = TftpTxPacket ( pTftpServer, pContext );
1139
1140 //
1141 // Return the operation status
1142 //
1143 DBG_EXIT_STATUS ( Status );
1144 return Status;
1145 }
1146
1147
1148 /**
1149 Send the next block of file system data
1150
1151 @param [in] pTftpServer The TFTP server control structure address.
1152 @param [in] pContext The context structure address.
1153
1154 @retval EFI_SUCCESS Message processed successfully
1155
1156 **/
1157 EFI_STATUS
1158 TftpSendNextBlock (
1159 IN TSDT_TFTP_SERVER * pTftpServer,
1160 IN TSDT_CONNECTION_CONTEXT * pContext
1161 )
1162 {
1163 ssize_t LengthInBytes;
1164 UINT8 * pBuffer;
1165 EFI_STATUS Status;
1166
1167 //
1168 // Determine how much data needs to be sent
1169 //
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;
1175 }
1176
1177 //
1178 // Set the TFTP opcode and block number
1179 //
1180 pBuffer = &pContext->TxBuffer[0];
1181 *pBuffer++ = 0;
1182 *pBuffer++ = TFTP_OP_DATA;
1183 *pBuffer++ = (UINT8)( pContext->AckNext >> 8 );
1184 *pBuffer++ = (UINT8)pContext->AckNext;
1185
1186 //
1187 // Copy the file data into the transmit buffer
1188 //
1189 pContext->TxBytes = 2 + 2 + LengthInBytes;
1190 if ( 0 < LengthInBytes ) {
1191 CopyMem ( &pBuffer,
1192 pContext->pBuffer,
1193 LengthInBytes );
1194 }
1195
1196 //
1197 // Send the next block
1198 //
1199 Status = TftpTxPacket ( pTftpServer, pContext );
1200
1201 //
1202 // Return the operation status
1203 //
1204 return Status;
1205 }
1206
1207
1208 /**
1209 Create the port for the TFTP server
1210
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
1214 the network stack.
1215
1216 @param [in] pTftpServer The TFTP server control structure address.
1217
1218 **/
1219 VOID
1220 TftpServerTimer (
1221 IN TSDT_TFTP_SERVER * pTftpServer
1222 )
1223 {
1224 UINT16 TftpPort;
1225 int SocketStatus;
1226 EFI_STATUS Status;
1227
1228 DEBUG (( DEBUG_SERVER_TIMER, "Entering TftpServerTimer\r\n" ));
1229
1230 //
1231 // Open the TFTP port on the server
1232 //
1233 do {
1234 do {
1235 //
1236 // Wait for a while
1237 //
1238 Status = gBS->CheckEvent ( pTftpServer->TimerEvent );
1239 } while ( EFI_SUCCESS != Status );
1240
1241 //
1242 // Attempt to create the socket for the TFTP server
1243 //
1244 pTftpServer->TftpPort.events = POLLRDNORM | POLLHUP;
1245 pTftpServer->TftpPort.revents = 0;
1246 pTftpServer->TftpPort.fd = socket ( AF_INET,
1247 SOCK_DGRAM,
1248 IPPROTO_UDP );
1249 if ( -1 != pTftpServer->TftpPort.fd ) {
1250 //
1251 // Set the socket address
1252 //
1253 ZeroMem ( &pTftpServer->TftpServerAddress,
1254 sizeof ( pTftpServer->TftpServerAddress ));
1255 TftpPort = 69;
1256 DEBUG (( DEBUG_TFTP_PORT,
1257 "TFTP Port: %d\r\n",
1258 TftpPort ));
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 );
1263
1264 //
1265 // Bind the socket to the TFTP port
1266 //
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,
1274 TftpPort ));
1275 }
1276
1277 //
1278 // Release the socket if necessary
1279 //
1280 if ( -1 == SocketStatus ) {
1281 close ( pTftpServer->TftpPort.fd );
1282 pTftpServer->TftpPort.fd = -1;
1283 }
1284 }
1285
1286 //
1287 // Wait until the socket is open
1288 //
1289 }while ( -1 == pTftpServer->TftpPort.fd );
1290
1291 DEBUG (( DEBUG_SERVER_TIMER, "Exiting TftpServerTimer\r\n" ));
1292 }
1293
1294
1295 /**
1296 Start the TFTP server port creation timer
1297
1298 @param [in] pTftpServer The TFTP server control structure address.
1299
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.
1303
1304 **/
1305 EFI_STATUS
1306 TftpServerTimerStart (
1307 IN TSDT_TFTP_SERVER * pTftpServer
1308 )
1309 {
1310 EFI_STATUS Status;
1311 UINT64 TriggerTime;
1312
1313 DBG_ENTER ( );
1314
1315 //
1316 // Assume the timer is already running
1317 //
1318 Status = EFI_ALREADY_STARTED;
1319 if ( !pTftpServer->bTimerRunning ) {
1320 //
1321 // Compute the poll interval
1322 //
1323 TriggerTime = TFTP_PORT_POLL_DELAY * ( 1000 * 10 );
1324 Status = gBS->SetTimer ( pTftpServer->TimerEvent,
1325 TimerPeriodic,
1326 TriggerTime );
1327 if ( !EFI_ERROR ( Status )) {
1328 DEBUG (( DEBUG_TFTP_PORT, "TFTP port timer started\r\n" ));
1329
1330 //
1331 // Mark the timer running
1332 //
1333 pTftpServer->bTimerRunning = TRUE;
1334 }
1335 else {
1336 DEBUG (( DEBUG_ERROR | DEBUG_TFTP_PORT,
1337 "ERROR - Failed to start TFTP port timer, Status: %r\r\n",
1338 Status ));
1339 }
1340 }
1341
1342 //
1343 // Return the operation status
1344 //
1345 DBG_EXIT_STATUS ( Status );
1346 return Status;
1347 }
1348
1349
1350 /**
1351 Stop the TFTP server port creation timer
1352
1353 @param [in] pTftpServer The TFTP server control structure address.
1354
1355 @retval EFI_SUCCESS The TFTP port timer is stopped
1356 @retval Other Failed to stop the TFTP port timer
1357
1358 **/
1359 EFI_STATUS
1360 TftpServerTimerStop (
1361 IN TSDT_TFTP_SERVER * pTftpServer
1362 )
1363 {
1364 EFI_STATUS Status;
1365
1366 DBG_ENTER ( );
1367
1368 //
1369 // Assume the timer is stopped
1370 //
1371 Status = EFI_SUCCESS;
1372 if ( pTftpServer->bTimerRunning ) {
1373 //
1374 // Stop the port creation polling
1375 //
1376 Status = gBS->SetTimer ( pTftpServer->TimerEvent,
1377 TimerCancel,
1378 0 );
1379 if ( !EFI_ERROR ( Status )) {
1380 DEBUG (( DEBUG_TFTP_PORT, "TFT[ port timer stopped\r\n" ));
1381
1382 //
1383 // Mark the timer stopped
1384 //
1385 pTftpServer->bTimerRunning = FALSE;
1386 }
1387 else {
1388 DEBUG (( DEBUG_ERROR | DEBUG_TFTP_PORT,
1389 "ERROR - Failed to stop TFT[ port timer, Status: %r\r\n",
1390 Status ));
1391 }
1392 }
1393
1394 //
1395 // Return the operation status
1396 //
1397 DBG_EXIT_STATUS ( Status );
1398 return Status;
1399 }
1400
1401 /**
1402 Send the next TFTP packet
1403
1404 @param [in] pTftpServer The TFTP server control structure address.
1405 @param [in] pContext The context structure address.
1406
1407 @retval EFI_SUCCESS Message processed successfully
1408
1409 **/
1410 EFI_STATUS
1411 TftpTxPacket (
1412 IN TSDT_TFTP_SERVER * pTftpServer,
1413 IN TSDT_CONNECTION_CONTEXT * pContext
1414 )
1415 {
1416 ssize_t LengthInBytes;
1417 EFI_STATUS Status;
1418
1419 DBG_ENTER ( );
1420
1421 //
1422 // Assume success
1423 //
1424 Status = EFI_SUCCESS;
1425
1426 //
1427 // Send the TFTP packet
1428 //
1429 DEBUG (( DEBUG_TX,
1430 "0x%08x: pContext sending 0x%08x bytes\r\n",
1431 pContext,
1432 pContext->TxBytes ));
1433 LengthInBytes = sendto ( pTftpServer->TftpPort.fd,
1434 &pContext->TxBuffer[0],
1435 pContext->TxBytes,
1436 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",
1442 errno ));
1443 Status = EFI_DEVICE_ERROR;
1444 }
1445
1446 //
1447 // Return the operation status
1448 //
1449 DBG_EXIT_STATUS ( Status );
1450 return Status;
1451 }
1452
1453
1454 /**
1455 Entry point for the TFTP server application.
1456
1457 @param [in] Argc The number of arguments
1458 @param [in] Argv The argument value array
1459
1460 @retval 0 The application exited normally.
1461 @retval Other An error occurred.
1462 **/
1463 int
1464 main (
1465 IN int Argc,
1466 IN char **Argv
1467 )
1468 {
1469 TSDT_TFTP_SERVER * pTftpServer;
1470 EFI_STATUS Status;
1471
1472 //
1473 // Create a timer event to start TFTP port
1474 //
1475 pTftpServer = &mTftpServer;
1476 Status = gBS->CreateEvent ( EVT_TIMER,
1477 TPL_TFTP_SERVER,
1478 NULL,
1479 NULL,
1480 &pTftpServer->TimerEvent );
1481 if ( !EFI_ERROR ( Status )) {
1482 Status = TftpServerTimerStart ( pTftpServer );
1483 if ( !EFI_ERROR ( Status )) {
1484 //
1485 // Run the TFTP server forever
1486 //
1487 for ( ; ; ) {
1488 //
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.
1494 //
1495 TftpServerTimer ( pTftpServer );
1496
1497 //
1498 // Poll the socket for activity
1499 //
1500 do {
1501 SocketPoll ( pTftpServer );
1502 } while ( -1 != pTftpServer->TftpPort.fd );
1503
1504 //
1505 // TODO: Remove the following test code
1506 // Exit when the network connection is broken
1507 //
1508 break;
1509 }
1510
1511 //
1512 // Done with the timer event
1513 //
1514 TftpServerTimerStop ( pTftpServer );
1515 Status = gBS->CloseEvent ( pTftpServer->TimerEvent );
1516 }
1517 }
1518
1519 //
1520 // Return the final status
1521 //
1522 DBG_EXIT_STATUS ( Status );
1523 return Status;
1524 }