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