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