2 The implementation for the 'tftp' Shell command.
4 Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
5 Copyright (c) 2015, Intel Corporation. All rights reserved. <BR>
6 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php.
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "UefiShellTftpCommandLib.h"
19 #define IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH 32
22 Constant strings and definitions related to the message indicating the amount of
23 progress in the dowloading of a TFTP file.
26 // Frame for the progression slider
27 STATIC CONST CHAR16 mTftpProgressFrame
[] = L
"[ ]";
29 // Number of steps in the progression slider
30 #define TFTP_PROGRESS_SLIDER_STEPS ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 3)
32 // Size in number of characters plus one (final zero) of the message to
33 // indicate the progress of a TFTP download. The format is "[(progress slider:
34 // 40 characters)] (nb of KBytes downloaded so far: 7 characters) Kb". There
35 // are thus the number of characters in mTftpProgressFrame[] plus 11 characters
36 // (2 // spaces, "Kb" and seven characters for the number of KBytes).
37 #define TFTP_PROGRESS_MESSAGE_SIZE ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) + 12)
39 // String to delete the TFTP progress message to be able to update it :
40 // (TFTP_PROGRESS_MESSAGE_SIZE-1) '\b'
41 STATIC CONST CHAR16 mTftpProgressDelete
[] = L
"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
44 Check and convert the UINT16 option values of the 'tftp' command
46 @param[in] ValueStr Value as an Unicode encoded string
47 @param[out] Value UINT16 value
49 @return TRUE The value was returned.
50 @return FALSE A parsing error occured.
55 IN CONST CHAR16
*ValueStr
,
60 Get the name of the NIC.
62 @param[in] ControllerHandle The network physical device handle.
63 @param[in] NicNumber The network physical device number.
64 @param[out] NicName Address where to store the NIC name.
65 The memory area has to be at least
66 IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH
69 @return EFI_SUCCESS The name of the NIC was returned.
70 @return Others The creation of the child for the Managed
71 Network Service failed or the opening of
72 the Managed Network Protocol failed or
73 the operational parameters for the
74 Managed Network Protocol could not be
80 IN EFI_HANDLE ControllerHandle
,
86 Create a child for the service identified by its service binding protocol GUID
87 and get from the child the interface of the protocol identified by its GUID.
89 @param[in] ControllerHandle Controller handle.
90 @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the
91 service to be created.
92 @param[in] ProtocolGuid GUID of the protocol to be open.
93 @param[out] ChildHandle Address where the handler of the
94 created child is returned. NULL is
95 returned in case of error.
96 @param[out] Interface Address where a pointer to the
97 protocol interface is returned in
100 @return EFI_SUCCESS The child was created and the protocol opened.
101 @return Others Either the creation of the child or the opening
102 of the protocol failed.
106 CreateServiceChildAndOpenProtocol (
107 IN EFI_HANDLE ControllerHandle
,
108 IN EFI_GUID
*ServiceBindingProtocolGuid
,
109 IN EFI_GUID
*ProtocolGuid
,
110 OUT EFI_HANDLE
*ChildHandle
,
115 Close the protocol identified by its GUID on the child handle of the service
116 identified by its service binding protocol GUID, then destroy the child
119 @param[in] ControllerHandle Controller handle.
120 @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the
121 service to be destroyed.
122 @param[in] ProtocolGuid GUID of the protocol to be closed.
123 @param[in] ChildHandle Handle of the child to be destroyed.
128 CloseProtocolAndDestroyServiceChild (
129 IN EFI_HANDLE ControllerHandle
,
130 IN EFI_GUID
*ServiceBindingProtocolGuid
,
131 IN EFI_GUID
*ProtocolGuid
,
132 IN EFI_HANDLE ChildHandle
136 Worker function that gets the size in numbers of bytes of a file from a TFTP
137 server before to download the file.
139 @param[in] Mtftp4 MTFTP4 protocol interface
140 @param[in] FilePath Path of the file, ASCII encoded
141 @param[out] FileSize Address where to store the file size in number of
144 @retval EFI_SUCCESS The size of the file was returned.
145 @retval EFI_UNSUPPORTED The server does not support the "tsize" option.
146 @retval Others Error when retrieving the information from the server
147 (see EFI_MTFTP4_PROTOCOL.GetInfo() status codes)
148 or error when parsing the response of the server.
153 IN EFI_MTFTP4_PROTOCOL
*Mtftp4
,
154 IN CONST CHAR8
*FilePath
,
159 Worker function that download the data of a file from a TFTP server given
160 the path of the file and its size.
162 @param[in] Mtftp4 MTFTP4 protocol interface
163 @param[in] FilePath Path of the file, Unicode encoded
164 @param[in] AsciiFilePath Path of the file, ASCII encoded
165 @param[in] FileSize Size of the file in number of bytes
166 @param[out] Data Address where to store the address of the buffer
167 where the data of the file were downloaded in
170 @retval EFI_SUCCESS The file was downloaded.
171 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
172 @retval Others The downloading of the file from the server failed
173 (see EFI_MTFTP4_PROTOCOL.ReadFile() status codes).
179 IN EFI_MTFTP4_PROTOCOL
*Mtftp4
,
180 IN CONST CHAR16
*FilePath
,
181 IN CONST CHAR8
*AsciiFilePath
,
187 Update the progress of a file download
188 This procedure is called each time a new TFTP packet is received.
190 @param[in] This MTFTP4 protocol interface
191 @param[in] Token Parameters for the download of the file
192 @param[in] PacketLen Length of the packet
193 @param[in] Packet Address of the packet
195 @retval EFI_SUCCESS All packets are accepted.
202 IN EFI_MTFTP4_PROTOCOL
*This
,
203 IN EFI_MTFTP4_TOKEN
*Token
,
205 IN EFI_MTFTP4_PACKET
*Packet
208 EFI_MTFTP4_CONFIG_DATA DefaultMtftp4ConfigData
= {
209 TRUE
, // Use default setting
210 { { 0, 0, 0, 0 } }, // StationIp - Not relevant as UseDefaultSetting=TRUE
211 { { 0, 0, 0, 0 } }, // SubnetMask - Not relevant as UseDefaultSetting=TRUE
212 0, // LocalPort - Automatically assigned port number.
213 { { 0, 0, 0, 0 } }, // GatewayIp - Not relevant as UseDefaultSetting=TRUE
214 { { 0, 0, 0, 0 } }, // ServerIp - Not known yet
215 69, // InitialServerPort - Standard TFTP server port
216 6, // TryCount - Max number of retransmissions.
217 4 // TimeoutValue - Retransmission timeout in seconds.
220 STATIC CONST SHELL_PARAM_ITEM ParamList
[] = {
230 Function for 'tftp' command.
232 @param[in] ImageHandle Handle to the Image (NULL if Internal).
233 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
235 @return SHELL_SUCCESS The 'tftp' command completed successfully.
236 @return SHELL_ABORTED The Shell Library initialization failed.
237 @return SHELL_INVALID_PARAMETER At least one of the command's arguments is
239 @return SHELL_OUT_OF_RESOURCES A memory allocation failed.
240 @return SHELL_NOT_FOUND Network Interface Card not found or server
246 ShellCommandRunTftp (
247 IN EFI_HANDLE ImageHandle
,
248 IN EFI_SYSTEM_TABLE
*SystemTable
251 SHELL_STATUS ShellStatus
;
253 LIST_ENTRY
*CheckPackage
;
254 CHAR16
*ProblemParam
;
256 CONST CHAR16
*UserNicName
;
258 CONST CHAR16
*ValueStr
;
259 CONST CHAR16
*RemoteFilePath
;
260 CHAR8
*AsciiRemoteFilePath
;
261 CONST CHAR16
*Walker
;
262 CONST CHAR16
*LocalFilePath
;
263 EFI_MTFTP4_CONFIG_DATA Mtftp4ConfigData
;
267 CHAR16 NicName
[IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH
];
268 EFI_HANDLE ControllerHandle
;
269 EFI_HANDLE Mtftp4ChildHandle
;
270 EFI_MTFTP4_PROTOCOL
*Mtftp4
;
273 SHELL_FILE_HANDLE FileHandle
;
275 ShellStatus
= SHELL_INVALID_PARAMETER
;
278 AsciiRemoteFilePath
= NULL
;
283 // Initialize the Shell library (we must be in non-auto-init...)
285 Status
= ShellInitialize ();
286 if (EFI_ERROR (Status
)) {
287 ASSERT_EFI_ERROR (Status
);
288 return SHELL_ABORTED
;
292 // Parse the command line.
294 Status
= ShellCommandLineParse (ParamList
, &CheckPackage
, &ProblemParam
, TRUE
);
295 if (EFI_ERROR (Status
)) {
296 if ((Status
== EFI_VOLUME_CORRUPTED
) &&
297 (ProblemParam
!= NULL
) ) {
299 -1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellTftpHiiHandle
,
300 L
"tftp", ProblemParam
302 FreePool (ProblemParam
);
310 // Check the number of parameters
312 ParamCount
= ShellCommandLineGetCount (CheckPackage
);
313 if (ParamCount
> 4) {
315 -1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
),
316 gShellTftpHiiHandle
, L
"tftp"
320 if (ParamCount
< 3) {
322 -1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
),
323 gShellTftpHiiHandle
, L
"tftp"
328 Mtftp4ConfigData
= DefaultMtftp4ConfigData
;
331 // Check the host IPv4 address
333 ValueStr
= ShellCommandLineGetRawValue (CheckPackage
, 1);
334 Status
= NetLibStrToIp4 (ValueStr
, &Mtftp4ConfigData
.ServerIp
);
335 if (EFI_ERROR (Status
)) {
337 -1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
),
338 gShellTftpHiiHandle
, L
"tftp", ValueStr
343 RemoteFilePath
= ShellCommandLineGetRawValue (CheckPackage
, 2);
344 ASSERT(RemoteFilePath
!= NULL
);
345 AsciiRemoteFilePath
= AllocatePool (
346 (StrLen (RemoteFilePath
) + 1) * sizeof (CHAR8
)
348 if (AsciiRemoteFilePath
== NULL
) {
349 ShellStatus
= SHELL_OUT_OF_RESOURCES
;
352 UnicodeStrToAsciiStr (RemoteFilePath
, AsciiRemoteFilePath
);
354 if (ParamCount
== 4) {
355 LocalFilePath
= ShellCommandLineGetRawValue (CheckPackage
, 3);
357 Walker
= RemoteFilePath
+ StrLen (RemoteFilePath
);
358 while ((--Walker
) >= RemoteFilePath
) {
359 if ((*Walker
== L
'\\') ||
360 (*Walker
== L
'/' ) ) {
364 LocalFilePath
= Walker
+ 1;
368 // Get the name of the Network Interface Card to be used if any.
370 UserNicName
= ShellCommandLineGetValue (CheckPackage
, L
"-i");
372 ValueStr
= ShellCommandLineGetValue (CheckPackage
, L
"-l");
373 if (ValueStr
!= NULL
) {
374 if (!StringToUint16 (ValueStr
, &Mtftp4ConfigData
.LocalPort
)) {
379 ValueStr
= ShellCommandLineGetValue (CheckPackage
, L
"-r");
380 if (ValueStr
!= NULL
) {
381 if (!StringToUint16 (ValueStr
, &Mtftp4ConfigData
.InitialServerPort
)) {
386 ValueStr
= ShellCommandLineGetValue (CheckPackage
, L
"-c");
387 if (ValueStr
!= NULL
) {
388 if (!StringToUint16 (ValueStr
, &Mtftp4ConfigData
.TryCount
)) {
393 ValueStr
= ShellCommandLineGetValue (CheckPackage
, L
"-t");
394 if (ValueStr
!= NULL
) {
395 if (!StringToUint16 (ValueStr
, &Mtftp4ConfigData
.TimeoutValue
)) {
398 if (Mtftp4ConfigData
.TimeoutValue
== 0) {
400 -1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
),
401 gShellTftpHiiHandle
, L
"tftp", ValueStr
408 // Locate all MTFTP4 Service Binding protocols
410 ShellStatus
= SHELL_NOT_FOUND
;
411 Status
= gBS
->LocateHandleBuffer (
413 &gEfiManagedNetworkServiceBindingProtocolGuid
,
418 if (EFI_ERROR (Status
) || (HandleCount
== 0)) {
420 -1, -1, NULL
, STRING_TOKEN (STR_TFTP_ERR_NO_NIC
),
427 (NicNumber
< HandleCount
) && (ShellStatus
!= SHELL_SUCCESS
);
429 ControllerHandle
= Handles
[NicNumber
];
432 Status
= GetNicName (ControllerHandle
, NicNumber
, NicName
);
433 if (EFI_ERROR (Status
)) {
435 -1, -1, NULL
, STRING_TOKEN (STR_TFTP_ERR_NIC_NAME
),
436 gShellTftpHiiHandle
, NicNumber
, Status
441 if (UserNicName
!= NULL
) {
442 if (StrCmp (NicName
, UserNicName
) != 0) {
448 Status
= CreateServiceChildAndOpenProtocol (
450 &gEfiMtftp4ServiceBindingProtocolGuid
,
451 &gEfiMtftp4ProtocolGuid
,
455 if (EFI_ERROR (Status
)) {
457 -1, -1, NULL
, STRING_TOKEN (STR_TFTP_ERR_OPEN_PROTOCOL
),
458 gShellTftpHiiHandle
, NicName
, Status
463 Status
= Mtftp4
->Configure (Mtftp4
, &Mtftp4ConfigData
);
464 if (EFI_ERROR (Status
)) {
466 -1, -1, NULL
, STRING_TOKEN (STR_TFTP_ERR_CONFIGURE
),
467 gShellTftpHiiHandle
, NicName
, Status
472 Status
= GetFileSize (Mtftp4
, AsciiRemoteFilePath
, &FileSize
);
473 if (EFI_ERROR (Status
)) {
475 -1, -1, NULL
, STRING_TOKEN (STR_TFTP_ERR_FILE_SIZE
),
476 gShellTftpHiiHandle
, RemoteFilePath
, NicName
, Status
481 Status
= DownloadFile (Mtftp4
, RemoteFilePath
, AsciiRemoteFilePath
, FileSize
, &Data
);
482 if (EFI_ERROR (Status
)) {
484 -1, -1, NULL
, STRING_TOKEN (STR_TFTP_ERR_DOWNLOAD
),
485 gShellTftpHiiHandle
, RemoteFilePath
, NicName
, Status
490 if (!EFI_ERROR (ShellFileExists (LocalFilePath
))) {
491 ShellDeleteFileByName (LocalFilePath
);
494 Status
= ShellOpenFileByName (
497 EFI_FILE_MODE_CREATE
|
498 EFI_FILE_MODE_WRITE
|
502 if (EFI_ERROR (Status
)) {
504 -1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL
),
505 gShellTftpHiiHandle
, L
"tftp", LocalFilePath
510 Status
= ShellWriteFile (FileHandle
, &FileSize
, Data
);
511 if (!EFI_ERROR (Status
)) {
512 ShellStatus
= SHELL_SUCCESS
;
515 -1, -1, NULL
, STRING_TOKEN (STR_TFTP_ERR_WRITE
),
516 gShellTftpHiiHandle
, LocalFilePath
, Status
519 ShellCloseFile (&FileHandle
);
524 gBS
->FreePages ((EFI_PHYSICAL_ADDRESS
)(UINTN
)Data
, EFI_SIZE_TO_PAGES (FileSize
));
527 CloseProtocolAndDestroyServiceChild (
529 &gEfiMtftp4ServiceBindingProtocolGuid
,
530 &gEfiMtftp4ProtocolGuid
,
535 if ((UserNicName
!= NULL
) && (!NicFound
)) {
537 -1, -1, NULL
, STRING_TOKEN (STR_TFTP_ERR_NIC_NOT_FOUND
),
538 gShellTftpHiiHandle
, UserNicName
544 ShellCommandLineFreeVarList (CheckPackage
);
545 if (AsciiRemoteFilePath
!= NULL
) {
546 FreePool (AsciiRemoteFilePath
);
548 if (Handles
!= NULL
) {
556 Check and convert the UINT16 option values of the 'tftp' command
558 @param[in] ValueStr Value as an Unicode encoded string
559 @param[out] Value UINT16 value
561 @return TRUE The value was returned.
562 @return FALSE A parsing error occured.
567 IN CONST CHAR16
*ValueStr
,
573 Val
= ShellStrToUintn (ValueStr
);
574 if (Val
> MAX_UINT16
) {
576 -1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
),
577 gShellTftpHiiHandle
, L
"tftp", ValueStr
582 *Value
= (UINT16
)Val
;
587 Get the name of the NIC.
589 @param[in] ControllerHandle The network physical device handle.
590 @param[in] NicNumber The network physical device number.
591 @param[out] NicName Address where to store the NIC name.
592 The memory area has to be at least
593 IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH
596 @return EFI_SUCCESS The name of the NIC was returned.
597 @return Others The creation of the child for the Managed
598 Network Service failed or the opening of
599 the Managed Network Protocol failed or
600 the operational parameters for the
601 Managed Network Protocol could not be
607 IN EFI_HANDLE ControllerHandle
,
613 EFI_HANDLE MnpHandle
;
614 EFI_MANAGED_NETWORK_PROTOCOL
*Mnp
;
615 EFI_SIMPLE_NETWORK_MODE SnpMode
;
617 Status
= CreateServiceChildAndOpenProtocol (
619 &gEfiManagedNetworkServiceBindingProtocolGuid
,
620 &gEfiManagedNetworkProtocolGuid
,
624 if (EFI_ERROR (Status
)) {
628 Status
= Mnp
->GetModeData (Mnp
, NULL
, &SnpMode
);
629 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_STARTED
)) {
635 IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH
,
636 SnpMode
.IfType
== NET_IFTYPE_ETHERNET
?
642 Status
= EFI_SUCCESS
;
646 if (MnpHandle
!= NULL
) {
647 CloseProtocolAndDestroyServiceChild (
649 &gEfiManagedNetworkServiceBindingProtocolGuid
,
650 &gEfiManagedNetworkProtocolGuid
,
659 Create a child for the service identified by its service binding protocol GUID
660 and get from the child the interface of the protocol identified by its GUID.
662 @param[in] ControllerHandle Controller handle.
663 @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the
664 service to be created.
665 @param[in] ProtocolGuid GUID of the protocol to be open.
666 @param[out] ChildHandle Address where the handler of the
667 created child is returned. NULL is
668 returned in case of error.
669 @param[out] Interface Address where a pointer to the
670 protocol interface is returned in
673 @return EFI_SUCCESS The child was created and the protocol opened.
674 @return Others Either the creation of the child or the opening
675 of the protocol failed.
679 CreateServiceChildAndOpenProtocol (
680 IN EFI_HANDLE ControllerHandle
,
681 IN EFI_GUID
*ServiceBindingProtocolGuid
,
682 IN EFI_GUID
*ProtocolGuid
,
683 OUT EFI_HANDLE
*ChildHandle
,
690 Status
= NetLibCreateServiceChild (
693 ServiceBindingProtocolGuid
,
696 if (!EFI_ERROR (Status
)) {
697 Status
= gBS
->OpenProtocol (
703 EFI_OPEN_PROTOCOL_GET_PROTOCOL
705 if (EFI_ERROR (Status
)) {
706 NetLibDestroyServiceChild (
709 ServiceBindingProtocolGuid
,
720 Close the protocol identified by its GUID on the child handle of the service
721 identified by its service binding protocol GUID, then destroy the child
724 @param[in] ControllerHandle Controller handle.
725 @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the
726 service to be destroyed.
727 @param[in] ProtocolGuid GUID of the protocol to be closed.
728 @param[in] ChildHandle Handle of the child to be destroyed.
733 CloseProtocolAndDestroyServiceChild (
734 IN EFI_HANDLE ControllerHandle
,
735 IN EFI_GUID
*ServiceBindingProtocolGuid
,
736 IN EFI_GUID
*ProtocolGuid
,
737 IN EFI_HANDLE ChildHandle
747 NetLibDestroyServiceChild (
750 ServiceBindingProtocolGuid
,
756 Worker function that gets the size in numbers of bytes of a file from a TFTP
757 server before to download the file.
759 @param[in] Mtftp4 MTFTP4 protocol interface
760 @param[in] FilePath Path of the file, ASCII encoded
761 @param[out] FileSize Address where to store the file size in number of
764 @retval EFI_SUCCESS The size of the file was returned.
765 @retval EFI_UNSUPPORTED The server does not support the "tsize" option.
766 @retval Others Error when retrieving the information from the server
767 (see EFI_MTFTP4_PROTOCOL.GetInfo() status codes)
768 or error when parsing the response of the server.
773 IN EFI_MTFTP4_PROTOCOL
*Mtftp4
,
774 IN CONST CHAR8
*FilePath
,
779 EFI_MTFTP4_OPTION ReqOpt
[1];
780 EFI_MTFTP4_PACKET
*Packet
;
782 EFI_MTFTP4_OPTION
*TableOfOptions
;
783 EFI_MTFTP4_OPTION
*Option
;
787 ReqOpt
[0].OptionStr
= (UINT8
*)"tsize";
790 ReqOpt
[0].ValueStr
= OptBuf
;
792 Status
= Mtftp4
->GetInfo (
803 if (EFI_ERROR (Status
)) {
807 Status
= Mtftp4
->ParseOptions (
814 if (EFI_ERROR (Status
)) {
818 Option
= TableOfOptions
;
819 while (OptCnt
!= 0) {
820 if (AsciiStrnCmp ((CHAR8
*)Option
->OptionStr
, "tsize", 5) == 0) {
821 *FileSize
= AsciiStrDecimalToUintn ((CHAR8
*)Option
->ValueStr
);
827 FreePool (TableOfOptions
);
830 Status
= EFI_UNSUPPORTED
;
839 Worker function that download the data of a file from a TFTP server given
840 the path of the file and its size.
842 @param[in] Mtftp4 MTFTP4 protocol interface
843 @param[in] FilePath Path of the file, Unicode encoded
844 @param[in] AsciiFilePath Path of the file, ASCII encoded
845 @param[in] FileSize Size of the file in number of bytes
846 @param[out] Data Address where to store the address of the buffer
847 where the data of the file were downloaded in
850 @retval EFI_SUCCESS The file was downloaded.
851 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
852 @retval Others The downloading of the file from the server failed
853 (see EFI_MTFTP4_PROTOCOL.ReadFile() status codes).
859 IN EFI_MTFTP4_PROTOCOL
*Mtftp4
,
860 IN CONST CHAR16
*FilePath
,
861 IN CONST CHAR8
*AsciiFilePath
,
867 EFI_PHYSICAL_ADDRESS PagesAddress
;
869 DOWNLOAD_CONTEXT
*TftpContext
;
870 EFI_MTFTP4_TOKEN Mtftp4Token
;
872 // Downloaded file can be large. BS.AllocatePages() is more faster
873 // than AllocatePool() and avoid fragmentation.
874 // The downloaded file could be an EFI application. Marking the
875 // allocated page as EfiBootServicesCode would allow to execute a
876 // potential downloaded EFI application.
877 Status
= gBS
->AllocatePages (
880 EFI_SIZE_TO_PAGES (FileSize
),
883 if (EFI_ERROR (Status
)) {
887 Buffer
= (VOID
*)(UINTN
)PagesAddress
;
888 TftpContext
= AllocatePool (sizeof (DOWNLOAD_CONTEXT
));
889 if (TftpContext
== NULL
) {
890 Status
= EFI_OUT_OF_RESOURCES
;
893 TftpContext
->FileSize
= FileSize
;
894 TftpContext
->DownloadedNbOfBytes
= 0;
895 TftpContext
->LastReportedNbOfBytes
= 0;
897 ZeroMem (&Mtftp4Token
, sizeof (EFI_MTFTP4_TOKEN
));
898 Mtftp4Token
.Filename
= (UINT8
*)AsciiFilePath
;
899 Mtftp4Token
.BufferSize
= FileSize
;
900 Mtftp4Token
.Buffer
= Buffer
;
901 Mtftp4Token
.CheckPacket
= CheckPacket
;
902 Mtftp4Token
.Context
= (VOID
*)TftpContext
;
905 -1, -1, NULL
, STRING_TOKEN (STR_TFTP_DOWNLOADING
),
906 gShellTftpHiiHandle
, FilePath
909 Status
= Mtftp4
->ReadFile (Mtftp4
, &Mtftp4Token
);
911 -1, -1, NULL
, STRING_TOKEN (STR_GEN_CRLF
),
917 if (TftpContext
== NULL
) {
918 FreePool (TftpContext
);
921 if (EFI_ERROR (Status
)) {
922 gBS
->FreePages (PagesAddress
, EFI_SIZE_TO_PAGES (FileSize
));
932 Update the progress of a file download
933 This procedure is called each time a new TFTP packet is received.
935 @param[in] This MTFTP4 protocol interface
936 @param[in] Token Parameters for the download of the file
937 @param[in] PacketLen Length of the packet
938 @param[in] Packet Address of the packet
940 @retval EFI_SUCCESS All packets are accepted.
947 IN EFI_MTFTP4_PROTOCOL
*This
,
948 IN EFI_MTFTP4_TOKEN
*Token
,
950 IN EFI_MTFTP4_PACKET
*Packet
953 DOWNLOAD_CONTEXT
*Context
;
954 CHAR16 Progress
[TFTP_PROGRESS_MESSAGE_SIZE
];
961 if ((NTOHS (Packet
->OpCode
)) != EFI_MTFTP4_OPCODE_DATA
) {
965 Context
= (DOWNLOAD_CONTEXT
*)Token
->Context
;
966 if (Context
->DownloadedNbOfBytes
== 0) {
967 ShellPrintEx (-1, -1, L
"%s 0 Kb", mTftpProgressFrame
);
971 // The data in the packet are prepended with two UINT16 :
972 // . OpCode = EFI_MTFTP4_OPCODE_DATA
973 // . Block = the number of this block of data
975 Context
->DownloadedNbOfBytes
+= PacketLen
- sizeof (Packet
->OpCode
)
976 - sizeof (Packet
->Data
.Block
);
977 NbOfKb
= Context
->DownloadedNbOfBytes
/ 1024;
980 LastStep
= (Context
->LastReportedNbOfBytes
* TFTP_PROGRESS_SLIDER_STEPS
) / Context
->FileSize
;
981 Step
= (Context
->DownloadedNbOfBytes
* TFTP_PROGRESS_SLIDER_STEPS
) / Context
->FileSize
;
983 if (Step
<= LastStep
) {
987 ShellPrintEx (-1, -1, L
"%s", mTftpProgressDelete
);
989 Status
= StrCpyS (Progress
, TFTP_PROGRESS_MESSAGE_SIZE
, mTftpProgressFrame
);
990 if (EFI_ERROR(Status
)) {
993 for (Index
= 1; Index
< Step
; Index
++) {
994 Progress
[Index
] = L
'=';
996 Progress
[Step
] = L
'>';
999 Progress
+ (sizeof (mTftpProgressFrame
) / sizeof (CHAR16
)) - 1,
1000 sizeof (Progress
) - sizeof (mTftpProgressFrame
),
1004 Context
->LastReportedNbOfBytes
= Context
->DownloadedNbOfBytes
;
1006 ShellPrintEx (-1, -1, L
"%s", Progress
);