Add Socket Library applications.
[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 @returns 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 @returns 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 @returns 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 {
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,
854 pContext->BlockSize,
855 pContext ));
856 bIgnorePacket = TRUE;
857 break;
858 }
859 break;
860
861 case TFTP_OP_ACK:
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;
871 }
872 if ( !pContext->bExpectAck ) {
873 DEBUG (( DEBUG_ERROR,
874 "ERROR - Expecting data not ACKs for pContext 0x%08x\r\n",
875 pContext ));
876 bIgnorePacket = TRUE;
877 break;
878 }
879 break;
880
881 case TFTP_OP_ERROR:
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;
891 }
892 break;
893 }
894 if ( !bIgnorePacket ) {
895 //
896 // Process the request
897 //
898 switch ( Opcode ) {
899 default:
900 DEBUG (( DEBUG_TFTP_REQUEST,
901 "ERROR - Unable to process TFTP opcode: %d\r\n",
902 Opcode ));
903 break;
904
905 case TFTP_OP_READ_REQUEST:
906
907 //
908 // Close the context if necessary
909 //
910 if ( NULL != pContext ) {
911 ContextRemove ( pTftpServer, pContext );
912 }
913
914 //
915 // Create the connection context
916 //
917 pContext = ContextAdd ( pTftpServer );
918 if ( NULL == pContext ) {
919 break;
920 }
921
922 //
923 // Locate the mode
924 //
925 pFileName = &pBuffer[2];
926 pEnd = &pBuffer[pTftpServer->RxBytes];
927 pMode = pFileName;
928 while (( pEnd > pMode ) && ( 0 != *pMode )) {
929 pMode += 1;
930 }
931 if ( pEnd <= pMode ) {
932 //
933 // Mode not found
934 //
935 DEBUG (( DEBUG_ERROR | DEBUG_RX,
936 "ERROR - File mode not found\r\n" ));
937 //
938 // Tell the client of the error
939 //
940 TftpSendError ( pTftpServer,
941 pContext,
942 0,
943 (UINT8 *)"File open mode not found" );
944 break;
945 }
946 pMode += 1;
947 DEBUG (( DEBUG_TFTP_REQUEST,
948 "TFTP - FileName: %a\n",
949 pFileName ));
950
951 //
952 // Locate the options
953 //
954 pOption = pMode;
955 while (( pEnd > pOption ) && ( 0 != *pOption )) {
956 pOption += 1;
957 }
958 if ( pEnd <= pOption ) {
959 //
960 // End of mode not found
961 //
962 DEBUG (( DEBUG_ERROR | DEBUG_RX,
963 "ERROR - File mode not valid\r\n" ));
964 //
965 // Tell the client of the error
966 //
967 TftpSendError ( pTftpServer,
968 pContext,
969 0,
970 (UINT8 *)"File open mode not valid" );
971 break;
972 }
973 pOption += 1;
974 DEBUG (( DEBUG_TFTP_REQUEST,
975 "TFTP - Mode: %a\r\n",
976 pMode ));
977
978 //
979 // Verify the mode is supported
980 //
981 if ( 0 != stricmp ((char *)pMode, "octet" )) {
982 //
983 // File access mode not supported
984 //
985 DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST,
986 "ERROR - File mode %a not supported\r\n",
987 pMode ));
988
989 //
990 // Tell the client of the error
991 //
992 TftpSendError ( pTftpServer,
993 pContext,
994 0,
995 (UINT8 *)"File open mode not supported" );
996 break;
997 }
998
999 //
1000 // Open the file, close the context on error
1001 //
1002 // TODO: Remove the following line
1003 pContext->File = (EFI_HANDLE)1;
1004
1005 //
1006 // Determine the file length
1007 //
1008 //fstat
1009
1010 //
1011 // Process the options
1012 //
1013 TftpOptions ( pContext, pOption, pEnd );
1014
1015 //
1016 // Read in the first portion of the file
1017 //
1018
1019 //
1020 // Send the first block
1021 //
1022 pContext->bExpectAck = TRUE;
1023 if ( 2 < pContext->TxBytes ) {
1024 //
1025 // Send the OACK
1026 //
1027 Status = TftpTxPacket ( pTftpServer, pContext );
1028 }
1029 else {
1030 //
1031 // Send the first block of data
1032 //
1033 Status = TftpSendNextBlock ( pTftpServer, pContext );
1034 }
1035 break;
1036
1037 case TFTP_OP_ACK:
1038 //
1039 // Get the block number that is being ACKed
1040 //
1041 BlockNumber = pTftpServer->RxBuffer[2];
1042 BlockNumber <<= 8;
1043 BlockNumber |= pTftpServer->RxBuffer[3];
1044
1045 //
1046 // Determine if this is the correct ACK
1047 //
1048 DEBUG (( DEBUG_TFTP_ACK,
1049 "ACK for block 0x%04x received\r\n",
1050 BlockNumber ));
1051 if (( !pContext->bExpectAck )
1052 || ( BlockNumber != pContext->AckNext ))
1053 {
1054 DEBUG (( DEBUG_WARN | DEBUG_TFTP_ACK,
1055 "WARNING - Expecting ACK 0x%0x4 not received ACK 0x%08x\r\n",
1056 pContext->AckNext,
1057 BlockNumber ));
1058 }
1059 else {
1060 //
1061 // Process the expected ACK
1062 //
1063 if ( pContext->bEofSent ) {
1064 bCloseContext = TRUE;
1065 }
1066 else {
1067 //
1068 // Set the next expected ACK
1069 //
1070 pContext->AckNext += 1;
1071
1072 //
1073 // Send the next packet of data
1074 //
1075 Status = TftpSendNextBlock ( pTftpServer, pContext );
1076 }
1077 }
1078 break;
1079 }
1080 }
1081
1082 //
1083 // Determine if the context should be closed
1084 //
1085 if ( bCloseContext ) {
1086 ContextRemove ( pTftpServer, pContext );
1087 }
1088
1089 DBG_EXIT ( );
1090 }
1091
1092
1093 /**
1094 Build and send an error packet
1095
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
1100
1101 @retval EFI_SUCCESS Message processed successfully
1102
1103 **/
1104 EFI_STATUS
1105 TftpSendError (
1106 IN TSDT_TFTP_SERVER * pTftpServer,
1107 IN TSDT_CONNECTION_CONTEXT * pContext,
1108 IN UINT16 Error,
1109 IN UINT8 * pError
1110 )
1111 {
1112 UINT8 Character;
1113 UINT8 * pBuffer;
1114 EFI_STATUS Status;
1115
1116 DBG_ENTER ( );
1117
1118 //
1119 // Build the error packet
1120 //
1121 pBuffer = &pContext->TxBuffer[0];
1122 pBuffer[0] = 0;
1123 pBuffer[1] = TFTP_OP_ERROR;
1124 pBuffer[2] = (UINT8)( Error >> 8 );
1125 pBuffer[3] = (UINT8)Error;
1126
1127 //
1128 // Copy the zero terminated string into the buffer
1129 //
1130 pBuffer += 4;
1131 do {
1132 Character = *pError++;
1133 *pBuffer++ = Character;
1134 } while ( 0 != Character );
1135
1136 //
1137 // Send the error message
1138 //
1139 pContext->TxBytes = pBuffer - &pContext->TxBuffer[0];
1140 Status = TftpTxPacket ( pTftpServer, pContext );
1141
1142 //
1143 // Return the operation status
1144 //
1145 DBG_EXIT_STATUS ( Status );
1146 return Status;
1147 }
1148
1149
1150 /**
1151 Send the next block of file system data
1152
1153 @param [in] pTftpServer The TFTP server control structure address.
1154 @param [in] pContext The context structure address.
1155
1156 @retval EFI_SUCCESS Message processed successfully
1157
1158 **/
1159 EFI_STATUS
1160 TftpSendNextBlock (
1161 IN TSDT_TFTP_SERVER * pTftpServer,
1162 IN TSDT_CONNECTION_CONTEXT * pContext
1163 )
1164 {
1165 ssize_t LengthInBytes;
1166 UINT8 * pBuffer;
1167 EFI_STATUS Status;
1168
1169 //
1170 // Determine how much data needs to be sent
1171 //
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;
1177 }
1178
1179 //
1180 // Set the TFTP opcode and block number
1181 //
1182 pBuffer = &pContext->TxBuffer[0];
1183 *pBuffer++ = 0;
1184 *pBuffer++ = TFTP_OP_DATA;
1185 *pBuffer++ = (UINT8)( pContext->AckNext >> 8 );
1186 *pBuffer++ = (UINT8)pContext->AckNext;
1187
1188 //
1189 // Copy the file data into the transmit buffer
1190 //
1191 pContext->TxBytes = 2 + 2 + LengthInBytes;
1192 if ( 0 < LengthInBytes ) {
1193 CopyMem ( &pBuffer,
1194 pContext->pBuffer,
1195 LengthInBytes );
1196 }
1197
1198 //
1199 // Send the next block
1200 //
1201 Status = TftpTxPacket ( pTftpServer, pContext );
1202
1203 //
1204 // Return the operation status
1205 //
1206 return Status;
1207 }
1208
1209
1210 /**
1211 Create the port for the TFTP server
1212
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
1216 the network stack.
1217
1218 @param [in] pTftpServer The TFTP server control structure address.
1219
1220 **/
1221 VOID
1222 TftpServerTimer (
1223 IN TSDT_TFTP_SERVER * pTftpServer
1224 )
1225 {
1226 UINT16 TftpPort;
1227 int SocketStatus;
1228 EFI_STATUS Status;
1229
1230 DEBUG (( DEBUG_SERVER_TIMER, "Entering TftpServerTimer\r\n" ));
1231
1232 //
1233 // Open the TFTP port on the server
1234 //
1235 do {
1236 do {
1237 //
1238 // Wait for a while
1239 //
1240 Status = gBS->CheckEvent ( pTftpServer->TimerEvent );
1241 } while ( EFI_SUCCESS != Status );
1242
1243 //
1244 // Attempt to create the socket for the TFTP server
1245 //
1246 pTftpServer->TftpPort.events = POLLRDNORM | POLLHUP;
1247 pTftpServer->TftpPort.revents = 0;
1248 pTftpServer->TftpPort.fd = socket ( AF_INET,
1249 SOCK_DGRAM,
1250 IPPROTO_UDP );
1251 if ( -1 != pTftpServer->TftpPort.fd )
1252 {
1253 //
1254 // Set the socket address
1255 //
1256 ZeroMem ( &pTftpServer->TftpServerAddress,
1257 sizeof ( pTftpServer->TftpServerAddress ));
1258 TftpPort = 69;
1259 DEBUG (( DEBUG_TFTP_PORT,
1260 "TFTP Port: %d\r\n",
1261 TftpPort ));
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 );
1266
1267 //
1268 // Bind the socket to the TFTP port
1269 //
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,
1277 TftpPort ));
1278 }
1279
1280 //
1281 // Release the socket if necessary
1282 //
1283 if ( -1 == SocketStatus ) {
1284 close ( pTftpServer->TftpPort.fd );
1285 pTftpServer->TftpPort.fd = -1;
1286 }
1287 }
1288
1289 //
1290 // Wait until the socket is open
1291 //
1292 }while ( -1 == pTftpServer->TftpPort.fd );
1293
1294 DEBUG (( DEBUG_SERVER_TIMER, "Exiting TftpServerTimer\r\n" ));
1295 }
1296
1297
1298 /**
1299 Start the TFTP server port creation timer
1300
1301 @param [in] pTftpServer The TFTP server control structure address.
1302
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.
1306
1307 **/
1308 EFI_STATUS
1309 TftpServerTimerStart (
1310 IN TSDT_TFTP_SERVER * pTftpServer
1311 )
1312 {
1313 EFI_STATUS Status;
1314 UINT64 TriggerTime;
1315
1316 DBG_ENTER ( );
1317
1318 //
1319 // Assume the timer is already running
1320 //
1321 Status = EFI_ALREADY_STARTED;
1322 if ( !pTftpServer->bTimerRunning ) {
1323 //
1324 // Compute the poll interval
1325 //
1326 TriggerTime = TFTP_PORT_POLL_DELAY * ( 1000 * 10 );
1327 Status = gBS->SetTimer ( pTftpServer->TimerEvent,
1328 TimerPeriodic,
1329 TriggerTime );
1330 if ( !EFI_ERROR ( Status )) {
1331 DEBUG (( DEBUG_TFTP_PORT, "TFTP port timer started\r\n" ));
1332
1333 //
1334 // Mark the timer running
1335 //
1336 pTftpServer->bTimerRunning = TRUE;
1337 }
1338 else {
1339 DEBUG (( DEBUG_ERROR | DEBUG_TFTP_PORT,
1340 "ERROR - Failed to start TFTP port timer, Status: %r\r\n",
1341 Status ));
1342 }
1343 }
1344
1345 //
1346 // Return the operation status
1347 //
1348 DBG_EXIT_STATUS ( Status );
1349 return Status;
1350 }
1351
1352
1353 /**
1354 Stop the TFTP server port creation timer
1355
1356 @param [in] pTftpServer The TFTP server control structure address.
1357
1358 @retval EFI_SUCCESS The TFTP port timer is stopped
1359 @retval Other Failed to stop the TFTP port timer
1360
1361 **/
1362 EFI_STATUS
1363 TftpServerTimerStop (
1364 IN TSDT_TFTP_SERVER * pTftpServer
1365 )
1366 {
1367 EFI_STATUS Status;
1368
1369 DBG_ENTER ( );
1370
1371 //
1372 // Assume the timer is stopped
1373 //
1374 Status = EFI_SUCCESS;
1375 if ( pTftpServer->bTimerRunning ) {
1376 //
1377 // Stop the port creation polling
1378 //
1379 Status = gBS->SetTimer ( pTftpServer->TimerEvent,
1380 TimerCancel,
1381 0 );
1382 if ( !EFI_ERROR ( Status )) {
1383 DEBUG (( DEBUG_TFTP_PORT, "TFT[ port timer stopped\r\n" ));
1384
1385 //
1386 // Mark the timer stopped
1387 //
1388 pTftpServer->bTimerRunning = FALSE;
1389 }
1390 else {
1391 DEBUG (( DEBUG_ERROR | DEBUG_TFTP_PORT,
1392 "ERROR - Failed to stop TFT[ port timer, Status: %r\r\n",
1393 Status ));
1394 }
1395 }
1396
1397 //
1398 // Return the operation status
1399 //
1400 DBG_EXIT_STATUS ( Status );
1401 return Status;
1402 }
1403
1404 /**
1405 Send the next TFTP packet
1406
1407 @param [in] pTftpServer The TFTP server control structure address.
1408 @param [in] pContext The context structure address.
1409
1410 @retval EFI_SUCCESS Message processed successfully
1411
1412 **/
1413 EFI_STATUS
1414 TftpTxPacket (
1415 IN TSDT_TFTP_SERVER * pTftpServer,
1416 IN TSDT_CONNECTION_CONTEXT * pContext
1417 )
1418 {
1419 ssize_t LengthInBytes;
1420 EFI_STATUS Status;
1421
1422 DBG_ENTER ( );
1423
1424 //
1425 // Assume success
1426 //
1427 Status = EFI_SUCCESS;
1428
1429 //
1430 // Send the TFTP packet
1431 //
1432 DEBUG (( DEBUG_TX,
1433 "0x%08x: pContext sending 0x%08x bytes\r\n",
1434 pContext,
1435 pContext->TxBytes ));
1436 LengthInBytes = sendto ( pTftpServer->TftpPort.fd,
1437 &pContext->TxBuffer[0],
1438 pContext->TxBytes,
1439 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",
1445 errno ));
1446 Status = EFI_DEVICE_ERROR;
1447 }
1448
1449 //
1450 // Return the operation status
1451 //
1452 DBG_EXIT_STATUS ( Status );
1453 return Status;
1454 }
1455
1456
1457 /**
1458 Entry point for the TFTP server application.
1459
1460 @param [in] Argc The number of arguments
1461 @param [in] Argv The argument value array
1462
1463 @retval 0 The application exited normally.
1464 @retval Other An error occurred.
1465 **/
1466 int
1467 main (
1468 IN int Argc,
1469 IN char **Argv
1470 )
1471 {
1472 TSDT_TFTP_SERVER * pTftpServer;
1473 EFI_STATUS Status;
1474
1475 //
1476 // Create a timer event to start TFTP port
1477 //
1478 pTftpServer = &mTftpServer;
1479 Status = gBS->CreateEvent ( EVT_TIMER,
1480 TPL_TFTP_SERVER,
1481 NULL,
1482 NULL,
1483 &pTftpServer->TimerEvent );
1484 if ( !EFI_ERROR ( Status )) {
1485 Status = TftpServerTimerStart ( pTftpServer );
1486 if ( !EFI_ERROR ( Status )) {
1487 //
1488 // Run the TFTP server forever
1489 //
1490 for ( ; ; ) {
1491 //
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.
1497 //
1498 TftpServerTimer ( pTftpServer );
1499
1500 //
1501 // Poll the socket for activity
1502 //
1503 do {
1504 SocketPoll ( pTftpServer );
1505 } while ( -1 != pTftpServer->TftpPort.fd );
1506
1507 //
1508 // TODO: Remove the following test code
1509 // Exit when the network connection is broken
1510 //
1511 break;
1512 }
1513
1514 //
1515 // Done with the timer event
1516 //
1517 TftpServerTimerStop ( pTftpServer );
1518 Status = gBS->CloseEvent ( pTftpServer->TimerEvent );
1519 }
1520 }
1521
1522 //
1523 // Return the final status
1524 //
1525 DBG_EXIT_STATUS ( Status );
1526 return Status;
1527 }