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.
201 IN EFI_MTFTP4_PROTOCOL
*This
,
202 IN EFI_MTFTP4_TOKEN
*Token
,
204 IN EFI_MTFTP4_PACKET
*Packet
207 EFI_MTFTP4_CONFIG_DATA DefaultMtftp4ConfigData
= {
208 TRUE
, // Use default setting
209 { { 0, 0, 0, 0 } }, // StationIp - Not relevant as UseDefaultSetting=TRUE
210 { { 0, 0, 0, 0 } }, // SubnetMask - Not relevant as UseDefaultSetting=TRUE
211 0, // LocalPort - Automatically assigned port number.
212 { { 0, 0, 0, 0 } }, // GatewayIp - Not relevant as UseDefaultSetting=TRUE
213 { { 0, 0, 0, 0 } }, // ServerIp - Not known yet
214 69, // InitialServerPort - Standard TFTP server port
215 6, // TryCount - Max number of retransmissions.
216 4 // TimeoutValue - Retransmission timeout in seconds.
219 STATIC CONST SHELL_PARAM_ITEM ParamList
[] = {
229 Function for 'tftp' command.
231 @param[in] ImageHandle Handle to the Image (NULL if Internal).
232 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
234 @return SHELL_SUCCESS The 'tftp' command completed successfully.
235 @return SHELL_ABORTED The Shell Library initialization failed.
236 @return SHELL_INVALID_PARAMETER At least one of the command's arguments is
238 @return SHELL_OUT_OF_RESOURCES A memory allocation failed.
239 @return SHELL_NOT_FOUND Network Interface Card not found or server
245 ShellCommandRunTftp (
246 IN EFI_HANDLE ImageHandle
,
247 IN EFI_SYSTEM_TABLE
*SystemTable
250 SHELL_STATUS ShellStatus
;
252 LIST_ENTRY
*CheckPackage
;
253 CHAR16
*ProblemParam
;
255 CONST CHAR16
*UserNicName
;
257 CONST CHAR16
*ValueStr
;
258 CONST CHAR16
*RemoteFilePath
;
259 CHAR8
*AsciiRemoteFilePath
;
260 CONST CHAR16
*Walker
;
261 CONST CHAR16
*LocalFilePath
;
262 EFI_MTFTP4_CONFIG_DATA Mtftp4ConfigData
;
266 CHAR16 NicName
[IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH
];
267 EFI_HANDLE ControllerHandle
;
268 EFI_HANDLE Mtftp4ChildHandle
;
269 EFI_MTFTP4_PROTOCOL
*Mtftp4
;
272 SHELL_FILE_HANDLE FileHandle
;
274 ShellStatus
= SHELL_INVALID_PARAMETER
;
277 AsciiRemoteFilePath
= NULL
;
282 // Initialize the Shell library (we must be in non-auto-init...)
284 Status
= ShellInitialize ();
285 if (EFI_ERROR (Status
)) {
286 ASSERT_EFI_ERROR (Status
);
287 return SHELL_ABORTED
;
291 // Parse the command line.
293 Status
= ShellCommandLineParse (ParamList
, &CheckPackage
, &ProblemParam
, TRUE
);
294 if (EFI_ERROR (Status
)) {
295 if ((Status
== EFI_VOLUME_CORRUPTED
) &&
296 (ProblemParam
!= NULL
) ) {
298 -1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellTftpHiiHandle
,
299 L
"tftp", ProblemParam
301 FreePool (ProblemParam
);
309 // Check the number of parameters
311 ParamCount
= ShellCommandLineGetCount (CheckPackage
);
312 if (ParamCount
> 4) {
314 -1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
),
315 gShellTftpHiiHandle
, L
"tftp"
319 if (ParamCount
< 3) {
321 -1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
),
322 gShellTftpHiiHandle
, L
"tftp"
327 Mtftp4ConfigData
= DefaultMtftp4ConfigData
;
330 // Check the host IPv4 address
332 ValueStr
= ShellCommandLineGetRawValue (CheckPackage
, 1);
333 Status
= NetLibStrToIp4 (ValueStr
, &Mtftp4ConfigData
.ServerIp
);
334 if (EFI_ERROR (Status
)) {
336 -1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
),
337 gShellTftpHiiHandle
, L
"tftp", ValueStr
342 RemoteFilePath
= ShellCommandLineGetRawValue (CheckPackage
, 2);
343 AsciiRemoteFilePath
= AllocatePool (
344 (StrLen (RemoteFilePath
) + 1) * sizeof (CHAR8
)
346 if (AsciiRemoteFilePath
== NULL
) {
347 ShellStatus
= SHELL_OUT_OF_RESOURCES
;
350 UnicodeStrToAsciiStr (RemoteFilePath
, AsciiRemoteFilePath
);
352 if (ParamCount
== 4) {
353 LocalFilePath
= ShellCommandLineGetRawValue (CheckPackage
, 3);
355 Walker
= RemoteFilePath
+ StrLen (RemoteFilePath
);
356 while ((--Walker
) >= RemoteFilePath
) {
357 if ((*Walker
== L
'\\') ||
358 (*Walker
== L
'/' ) ) {
362 LocalFilePath
= Walker
+ 1;
366 // Get the name of the Network Interface Card to be used if any.
368 UserNicName
= ShellCommandLineGetValue (CheckPackage
, L
"-i");
370 ValueStr
= ShellCommandLineGetValue (CheckPackage
, L
"-l");
371 if (ValueStr
!= NULL
) {
372 if (!StringToUint16 (ValueStr
, &Mtftp4ConfigData
.LocalPort
)) {
377 ValueStr
= ShellCommandLineGetValue (CheckPackage
, L
"-r");
378 if (ValueStr
!= NULL
) {
379 if (!StringToUint16 (ValueStr
, &Mtftp4ConfigData
.InitialServerPort
)) {
384 ValueStr
= ShellCommandLineGetValue (CheckPackage
, L
"-c");
385 if (ValueStr
!= NULL
) {
386 if (!StringToUint16 (ValueStr
, &Mtftp4ConfigData
.TryCount
)) {
391 ValueStr
= ShellCommandLineGetValue (CheckPackage
, L
"-t");
392 if (ValueStr
!= NULL
) {
393 if (!StringToUint16 (ValueStr
, &Mtftp4ConfigData
.TimeoutValue
)) {
396 if (Mtftp4ConfigData
.TimeoutValue
== 0) {
398 -1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
),
399 gShellTftpHiiHandle
, L
"tftp", ValueStr
406 // Locate all MTFTP4 Service Binding protocols
408 ShellStatus
= SHELL_NOT_FOUND
;
409 Status
= gBS
->LocateHandleBuffer (
411 &gEfiManagedNetworkServiceBindingProtocolGuid
,
416 if (EFI_ERROR (Status
) || (HandleCount
== 0)) {
418 -1, -1, NULL
, STRING_TOKEN (STR_TFTP_ERR_NO_NIC
),
425 (NicNumber
< HandleCount
) && (ShellStatus
!= SHELL_SUCCESS
);
427 ControllerHandle
= Handles
[NicNumber
];
430 Status
= GetNicName (ControllerHandle
, NicNumber
, NicName
);
431 if (EFI_ERROR (Status
)) {
433 -1, -1, NULL
, STRING_TOKEN (STR_TFTP_ERR_NIC_NAME
),
434 gShellTftpHiiHandle
, NicNumber
, Status
439 if (UserNicName
!= NULL
) {
440 if (StrCmp (NicName
, UserNicName
) != 0) {
446 Status
= CreateServiceChildAndOpenProtocol (
448 &gEfiMtftp4ServiceBindingProtocolGuid
,
449 &gEfiMtftp4ProtocolGuid
,
453 if (EFI_ERROR (Status
)) {
455 -1, -1, NULL
, STRING_TOKEN (STR_TFTP_ERR_OPEN_PROTOCOL
),
456 gShellTftpHiiHandle
, NicName
, Status
461 Status
= Mtftp4
->Configure (Mtftp4
, &Mtftp4ConfigData
);
462 if (EFI_ERROR (Status
)) {
464 -1, -1, NULL
, STRING_TOKEN (STR_TFTP_ERR_CONFIGURE
),
465 gShellTftpHiiHandle
, NicName
, Status
470 Status
= GetFileSize (Mtftp4
, AsciiRemoteFilePath
, &FileSize
);
471 if (EFI_ERROR (Status
)) {
473 -1, -1, NULL
, STRING_TOKEN (STR_TFTP_ERR_FILE_SIZE
),
474 gShellTftpHiiHandle
, RemoteFilePath
, NicName
, Status
479 Status
= DownloadFile (Mtftp4
, RemoteFilePath
, AsciiRemoteFilePath
, FileSize
, &Data
);
480 if (EFI_ERROR (Status
)) {
482 -1, -1, NULL
, STRING_TOKEN (STR_TFTP_ERR_DOWNLOAD
),
483 gShellTftpHiiHandle
, RemoteFilePath
, NicName
, Status
488 if (!EFI_ERROR (ShellFileExists (LocalFilePath
))) {
489 ShellDeleteFileByName (LocalFilePath
);
492 Status
= ShellOpenFileByName (
495 EFI_FILE_MODE_CREATE
|
496 EFI_FILE_MODE_WRITE
|
500 if (EFI_ERROR (Status
)) {
502 -1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL
),
503 gShellTftpHiiHandle
, L
"tftp", LocalFilePath
508 Status
= ShellWriteFile (FileHandle
, &FileSize
, Data
);
509 if (!EFI_ERROR (Status
)) {
510 ShellStatus
= SHELL_SUCCESS
;
513 -1, -1, NULL
, STRING_TOKEN (STR_TFTP_ERR_WRITE
),
514 gShellTftpHiiHandle
, LocalFilePath
, Status
517 ShellCloseFile (&FileHandle
);
522 gBS
->FreePages ((EFI_PHYSICAL_ADDRESS
)(UINTN
)Data
, EFI_SIZE_TO_PAGES (FileSize
));
525 CloseProtocolAndDestroyServiceChild (
527 &gEfiMtftp4ServiceBindingProtocolGuid
,
528 &gEfiMtftp4ProtocolGuid
,
533 if ((UserNicName
!= NULL
) && (!NicFound
)) {
535 -1, -1, NULL
, STRING_TOKEN (STR_TFTP_ERR_NIC_NOT_FOUND
),
536 gShellTftpHiiHandle
, UserNicName
542 ShellCommandLineFreeVarList (CheckPackage
);
543 if (AsciiRemoteFilePath
!= NULL
) {
544 FreePool (AsciiRemoteFilePath
);
546 if (Handles
!= NULL
) {
554 Check and convert the UINT16 option values of the 'tftp' command
556 @param[in] ValueStr Value as an Unicode encoded string
557 @param[out] Value UINT16 value
559 @return TRUE The value was returned.
560 @return FALSE A parsing error occured.
565 IN CONST CHAR16
*ValueStr
,
571 Val
= ShellStrToUintn (ValueStr
);
572 if (Val
> MAX_UINT16
) {
574 -1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
),
575 gShellTftpHiiHandle
, L
"tftp", ValueStr
580 *Value
= (UINT16
)Val
;
585 Get the name of the NIC.
587 @param[in] ControllerHandle The network physical device handle.
588 @param[in] NicNumber The network physical device number.
589 @param[out] NicName Address where to store the NIC name.
590 The memory area has to be at least
591 IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH
594 @return EFI_SUCCESS The name of the NIC was returned.
595 @return Others The creation of the child for the Managed
596 Network Service failed or the opening of
597 the Managed Network Protocol failed or
598 the operational parameters for the
599 Managed Network Protocol could not be
605 IN EFI_HANDLE ControllerHandle
,
611 EFI_HANDLE MnpHandle
;
612 EFI_MANAGED_NETWORK_PROTOCOL
*Mnp
;
613 EFI_SIMPLE_NETWORK_MODE SnpMode
;
615 Status
= CreateServiceChildAndOpenProtocol (
617 &gEfiManagedNetworkServiceBindingProtocolGuid
,
618 &gEfiManagedNetworkProtocolGuid
,
622 if (EFI_ERROR (Status
)) {
626 Status
= Mnp
->GetModeData (Mnp
, NULL
, &SnpMode
);
627 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_STARTED
)) {
633 IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH
,
634 SnpMode
.IfType
== NET_IFTYPE_ETHERNET
?
640 Status
= EFI_SUCCESS
;
644 if (MnpHandle
!= NULL
) {
645 CloseProtocolAndDestroyServiceChild (
647 &gEfiManagedNetworkServiceBindingProtocolGuid
,
648 &gEfiManagedNetworkProtocolGuid
,
657 Create a child for the service identified by its service binding protocol GUID
658 and get from the child the interface of the protocol identified by its GUID.
660 @param[in] ControllerHandle Controller handle.
661 @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the
662 service to be created.
663 @param[in] ProtocolGuid GUID of the protocol to be open.
664 @param[out] ChildHandle Address where the handler of the
665 created child is returned. NULL is
666 returned in case of error.
667 @param[out] Interface Address where a pointer to the
668 protocol interface is returned in
671 @return EFI_SUCCESS The child was created and the protocol opened.
672 @return Others Either the creation of the child or the opening
673 of the protocol failed.
677 CreateServiceChildAndOpenProtocol (
678 IN EFI_HANDLE ControllerHandle
,
679 IN EFI_GUID
*ServiceBindingProtocolGuid
,
680 IN EFI_GUID
*ProtocolGuid
,
681 OUT EFI_HANDLE
*ChildHandle
,
688 Status
= NetLibCreateServiceChild (
691 ServiceBindingProtocolGuid
,
694 if (!EFI_ERROR (Status
)) {
695 Status
= gBS
->OpenProtocol (
701 EFI_OPEN_PROTOCOL_GET_PROTOCOL
703 if (EFI_ERROR (Status
)) {
704 NetLibDestroyServiceChild (
707 ServiceBindingProtocolGuid
,
718 Close the protocol identified by its GUID on the child handle of the service
719 identified by its service binding protocol GUID, then destroy the child
722 @param[in] ControllerHandle Controller handle.
723 @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the
724 service to be destroyed.
725 @param[in] ProtocolGuid GUID of the protocol to be closed.
726 @param[in] ChildHandle Handle of the child to be destroyed.
731 CloseProtocolAndDestroyServiceChild (
732 IN EFI_HANDLE ControllerHandle
,
733 IN EFI_GUID
*ServiceBindingProtocolGuid
,
734 IN EFI_GUID
*ProtocolGuid
,
735 IN EFI_HANDLE ChildHandle
745 NetLibDestroyServiceChild (
748 ServiceBindingProtocolGuid
,
754 Worker function that gets the size in numbers of bytes of a file from a TFTP
755 server before to download the file.
757 @param[in] Mtftp4 MTFTP4 protocol interface
758 @param[in] FilePath Path of the file, ASCII encoded
759 @param[out] FileSize Address where to store the file size in number of
762 @retval EFI_SUCCESS The size of the file was returned.
763 @retval EFI_UNSUPPORTED The server does not support the "tsize" option.
764 @retval Others Error when retrieving the information from the server
765 (see EFI_MTFTP4_PROTOCOL.GetInfo() status codes)
766 or error when parsing the response of the server.
771 IN EFI_MTFTP4_PROTOCOL
*Mtftp4
,
772 IN CONST CHAR8
*FilePath
,
777 EFI_MTFTP4_OPTION ReqOpt
[1];
778 EFI_MTFTP4_PACKET
*Packet
;
780 EFI_MTFTP4_OPTION
*TableOfOptions
;
781 EFI_MTFTP4_OPTION
*Option
;
785 ReqOpt
[0].OptionStr
= (UINT8
*)"tsize";
788 ReqOpt
[0].ValueStr
= OptBuf
;
790 Status
= Mtftp4
->GetInfo (
801 if (EFI_ERROR (Status
)) {
805 Status
= Mtftp4
->ParseOptions (
812 if (EFI_ERROR (Status
)) {
816 Option
= TableOfOptions
;
817 while (OptCnt
!= 0) {
818 if (AsciiStrnCmp ((CHAR8
*)Option
->OptionStr
, "tsize", 5) == 0) {
819 *FileSize
= AsciiStrDecimalToUintn ((CHAR8
*)Option
->ValueStr
);
825 FreePool (TableOfOptions
);
828 Status
= EFI_UNSUPPORTED
;
837 Worker function that download the data of a file from a TFTP server given
838 the path of the file and its size.
840 @param[in] Mtftp4 MTFTP4 protocol interface
841 @param[in] FilePath Path of the file, Unicode encoded
842 @param[in] AsciiFilePath Path of the file, ASCII encoded
843 @param[in] FileSize Size of the file in number of bytes
844 @param[out] Data Address where to store the address of the buffer
845 where the data of the file were downloaded in
848 @retval EFI_SUCCESS The file was downloaded.
849 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
850 @retval Others The downloading of the file from the server failed
851 (see EFI_MTFTP4_PROTOCOL.ReadFile() status codes).
857 IN EFI_MTFTP4_PROTOCOL
*Mtftp4
,
858 IN CONST CHAR16
*FilePath
,
859 IN CONST CHAR8
*AsciiFilePath
,
865 EFI_PHYSICAL_ADDRESS PagesAddress
;
867 DOWNLOAD_CONTEXT
*TftpContext
;
868 EFI_MTFTP4_TOKEN Mtftp4Token
;
870 // Downloaded file can be large. BS.AllocatePages() is more faster
871 // than AllocatePool() and avoid fragmentation.
872 // The downloaded file could be an EFI application. Marking the
873 // allocated page as EfiBootServicesCode would allow to execute a
874 // potential downloaded EFI application.
875 Status
= gBS
->AllocatePages (
878 EFI_SIZE_TO_PAGES (FileSize
),
881 if (EFI_ERROR (Status
)) {
885 Buffer
= (VOID
*)(UINTN
)PagesAddress
;
886 TftpContext
= AllocatePool (sizeof (DOWNLOAD_CONTEXT
));
887 if (TftpContext
== NULL
) {
888 Status
= EFI_OUT_OF_RESOURCES
;
891 TftpContext
->FileSize
= FileSize
;
892 TftpContext
->DownloadedNbOfBytes
= 0;
893 TftpContext
->LastReportedNbOfBytes
= 0;
895 ZeroMem (&Mtftp4Token
, sizeof (EFI_MTFTP4_TOKEN
));
896 Mtftp4Token
.Filename
= (UINT8
*)AsciiFilePath
;
897 Mtftp4Token
.BufferSize
= FileSize
;
898 Mtftp4Token
.Buffer
= Buffer
;
899 Mtftp4Token
.CheckPacket
= CheckPacket
;
900 Mtftp4Token
.Context
= (VOID
*)TftpContext
;
903 -1, -1, NULL
, STRING_TOKEN (STR_TFTP_DOWNLOADING
),
904 gShellTftpHiiHandle
, FilePath
907 Status
= Mtftp4
->ReadFile (Mtftp4
, &Mtftp4Token
);
909 -1, -1, NULL
, STRING_TOKEN (STR_GEN_CRLF
),
915 if (TftpContext
== NULL
) {
916 FreePool (TftpContext
);
919 if (EFI_ERROR (Status
)) {
920 gBS
->FreePages (PagesAddress
, EFI_SIZE_TO_PAGES (FileSize
));
930 Update the progress of a file download
931 This procedure is called each time a new TFTP packet is received.
933 @param[in] This MTFTP4 protocol interface
934 @param[in] Token Parameters for the download of the file
935 @param[in] PacketLen Length of the packet
936 @param[in] Packet Address of the packet
938 @retval EFI_SUCCESS All packets are accepted.
944 IN EFI_MTFTP4_PROTOCOL
*This
,
945 IN EFI_MTFTP4_TOKEN
*Token
,
947 IN EFI_MTFTP4_PACKET
*Packet
950 DOWNLOAD_CONTEXT
*Context
;
951 CHAR16 Progress
[TFTP_PROGRESS_MESSAGE_SIZE
];
957 if ((NTOHS (Packet
->OpCode
)) != EFI_MTFTP4_OPCODE_DATA
) {
961 Context
= (DOWNLOAD_CONTEXT
*)Token
->Context
;
962 if (Context
->DownloadedNbOfBytes
== 0) {
963 ShellPrintEx (-1, -1, L
"%s 0 Kb", mTftpProgressFrame
);
967 // The data in the packet are prepended with two UINT16 :
968 // . OpCode = EFI_MTFTP4_OPCODE_DATA
969 // . Block = the number of this block of data
971 Context
->DownloadedNbOfBytes
+= PacketLen
- sizeof (Packet
->OpCode
)
972 - sizeof (Packet
->Data
.Block
);
973 NbOfKb
= Context
->DownloadedNbOfBytes
/ 1024;
976 LastStep
= (Context
->LastReportedNbOfBytes
* TFTP_PROGRESS_SLIDER_STEPS
) / Context
->FileSize
;
977 Step
= (Context
->DownloadedNbOfBytes
* TFTP_PROGRESS_SLIDER_STEPS
) / Context
->FileSize
;
979 if (Step
<= LastStep
) {
983 ShellPrintEx (-1, -1, L
"%s", mTftpProgressDelete
);
985 StrCpy (Progress
, mTftpProgressFrame
);
986 for (Index
= 1; Index
< Step
; Index
++) {
987 Progress
[Index
] = L
'=';
989 Progress
[Step
] = L
'>';
992 Progress
+ (sizeof (mTftpProgressFrame
) / sizeof (CHAR16
)) - 1,
993 sizeof (Progress
) - sizeof (mTftpProgressFrame
),
997 Context
->LastReportedNbOfBytes
= Context
->DownloadedNbOfBytes
;
999 ShellPrintEx (-1, -1, L
"%s", Progress
);