mirror of https://github.com/acidanthera/audk.git
1052 lines
33 KiB
C
Executable File
1052 lines
33 KiB
C
Executable File
/** @file
|
|
The implementation for the 'tftp' Shell command.
|
|
|
|
Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
|
|
Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved. <BR>
|
|
(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
|
|
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php.
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
**/
|
|
|
|
#include "UefiShellTftpCommandLib.h"
|
|
|
|
#define IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH 32
|
|
|
|
/*
|
|
Constant strings and definitions related to the message indicating the amount of
|
|
progress in the dowloading of a TFTP file.
|
|
*/
|
|
|
|
// Frame for the progression slider
|
|
STATIC CONST CHAR16 mTftpProgressFrame[] = L"[ ]";
|
|
|
|
// Number of steps in the progression slider
|
|
#define TFTP_PROGRESS_SLIDER_STEPS ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 3)
|
|
|
|
// Size in number of characters plus one (final zero) of the message to
|
|
// indicate the progress of a TFTP download. The format is "[(progress slider:
|
|
// 40 characters)] (nb of KBytes downloaded so far: 7 characters) Kb". There
|
|
// are thus the number of characters in mTftpProgressFrame[] plus 11 characters
|
|
// (2 // spaces, "Kb" and seven characters for the number of KBytes).
|
|
#define TFTP_PROGRESS_MESSAGE_SIZE ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) + 12)
|
|
|
|
// String to delete the TFTP progress message to be able to update it :
|
|
// (TFTP_PROGRESS_MESSAGE_SIZE-1) '\b'
|
|
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";
|
|
|
|
/**
|
|
Check and convert the UINT16 option values of the 'tftp' command
|
|
|
|
@param[in] ValueStr Value as an Unicode encoded string
|
|
@param[out] Value UINT16 value
|
|
|
|
@return TRUE The value was returned.
|
|
@return FALSE A parsing error occured.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
StringToUint16 (
|
|
IN CONST CHAR16 *ValueStr,
|
|
OUT UINT16 *Value
|
|
);
|
|
|
|
/**
|
|
Get the name of the NIC.
|
|
|
|
@param[in] ControllerHandle The network physical device handle.
|
|
@param[in] NicNumber The network physical device number.
|
|
@param[out] NicName Address where to store the NIC name.
|
|
The memory area has to be at least
|
|
IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH
|
|
double byte wide.
|
|
|
|
@return EFI_SUCCESS The name of the NIC was returned.
|
|
@return Others The creation of the child for the Managed
|
|
Network Service failed or the opening of
|
|
the Managed Network Protocol failed or
|
|
the operational parameters for the
|
|
Managed Network Protocol could not be
|
|
read.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
GetNicName (
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN UINTN NicNumber,
|
|
OUT CHAR16 *NicName
|
|
);
|
|
|
|
/**
|
|
Create a child for the service identified by its service binding protocol GUID
|
|
and get from the child the interface of the protocol identified by its GUID.
|
|
|
|
@param[in] ControllerHandle Controller handle.
|
|
@param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the
|
|
service to be created.
|
|
@param[in] ProtocolGuid GUID of the protocol to be open.
|
|
@param[out] ChildHandle Address where the handler of the
|
|
created child is returned. NULL is
|
|
returned in case of error.
|
|
@param[out] Interface Address where a pointer to the
|
|
protocol interface is returned in
|
|
case of success.
|
|
|
|
@return EFI_SUCCESS The child was created and the protocol opened.
|
|
@return Others Either the creation of the child or the opening
|
|
of the protocol failed.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
CreateServiceChildAndOpenProtocol (
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_GUID *ServiceBindingProtocolGuid,
|
|
IN EFI_GUID *ProtocolGuid,
|
|
OUT EFI_HANDLE *ChildHandle,
|
|
OUT VOID **Interface
|
|
);
|
|
|
|
/**
|
|
Close the protocol identified by its GUID on the child handle of the service
|
|
identified by its service binding protocol GUID, then destroy the child
|
|
handle.
|
|
|
|
@param[in] ControllerHandle Controller handle.
|
|
@param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the
|
|
service to be destroyed.
|
|
@param[in] ProtocolGuid GUID of the protocol to be closed.
|
|
@param[in] ChildHandle Handle of the child to be destroyed.
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
CloseProtocolAndDestroyServiceChild (
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_GUID *ServiceBindingProtocolGuid,
|
|
IN EFI_GUID *ProtocolGuid,
|
|
IN EFI_HANDLE ChildHandle
|
|
);
|
|
|
|
/**
|
|
Worker function that gets the size in numbers of bytes of a file from a TFTP
|
|
server before to download the file.
|
|
|
|
@param[in] Mtftp4 MTFTP4 protocol interface
|
|
@param[in] FilePath Path of the file, ASCII encoded
|
|
@param[out] FileSize Address where to store the file size in number of
|
|
bytes.
|
|
|
|
@retval EFI_SUCCESS The size of the file was returned.
|
|
@retval EFI_UNSUPPORTED The server does not support the "tsize" option.
|
|
@retval Others Error when retrieving the information from the server
|
|
(see EFI_MTFTP4_PROTOCOL.GetInfo() status codes)
|
|
or error when parsing the response of the server.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
GetFileSize (
|
|
IN EFI_MTFTP4_PROTOCOL *Mtftp4,
|
|
IN CONST CHAR8 *FilePath,
|
|
OUT UINTN *FileSize
|
|
);
|
|
|
|
/**
|
|
Worker function that download the data of a file from a TFTP server given
|
|
the path of the file and its size.
|
|
|
|
@param[in] Mtftp4 MTFTP4 protocol interface
|
|
@param[in] FilePath Path of the file, Unicode encoded
|
|
@param[in] AsciiFilePath Path of the file, ASCII encoded
|
|
@param[in] FileSize Size of the file in number of bytes
|
|
@param[in] BlockSize Value of the TFTP blksize option
|
|
@param[out] Data Address where to store the address of the buffer
|
|
where the data of the file were downloaded in
|
|
case of success.
|
|
|
|
@retval EFI_SUCCESS The file was downloaded.
|
|
@retval EFI_OUT_OF_RESOURCES A memory allocation failed.
|
|
@retval Others The downloading of the file from the server failed
|
|
(see EFI_MTFTP4_PROTOCOL.ReadFile() status codes).
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
DownloadFile (
|
|
IN EFI_MTFTP4_PROTOCOL *Mtftp4,
|
|
IN CONST CHAR16 *FilePath,
|
|
IN CONST CHAR8 *AsciiFilePath,
|
|
IN UINTN FileSize,
|
|
IN UINT16 BlockSize,
|
|
OUT VOID **Data
|
|
);
|
|
|
|
/**
|
|
Update the progress of a file download
|
|
This procedure is called each time a new TFTP packet is received.
|
|
|
|
@param[in] This MTFTP4 protocol interface
|
|
@param[in] Token Parameters for the download of the file
|
|
@param[in] PacketLen Length of the packet
|
|
@param[in] Packet Address of the packet
|
|
|
|
@retval EFI_SUCCESS All packets are accepted.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CheckPacket (
|
|
IN EFI_MTFTP4_PROTOCOL *This,
|
|
IN EFI_MTFTP4_TOKEN *Token,
|
|
IN UINT16 PacketLen,
|
|
IN EFI_MTFTP4_PACKET *Packet
|
|
);
|
|
|
|
EFI_MTFTP4_CONFIG_DATA DefaultMtftp4ConfigData = {
|
|
TRUE, // Use default setting
|
|
{ { 0, 0, 0, 0 } }, // StationIp - Not relevant as UseDefaultSetting=TRUE
|
|
{ { 0, 0, 0, 0 } }, // SubnetMask - Not relevant as UseDefaultSetting=TRUE
|
|
0, // LocalPort - Automatically assigned port number.
|
|
{ { 0, 0, 0, 0 } }, // GatewayIp - Not relevant as UseDefaultSetting=TRUE
|
|
{ { 0, 0, 0, 0 } }, // ServerIp - Not known yet
|
|
69, // InitialServerPort - Standard TFTP server port
|
|
6, // TryCount - Max number of retransmissions.
|
|
4 // TimeoutValue - Retransmission timeout in seconds.
|
|
};
|
|
|
|
STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
|
|
{L"-i", TypeValue},
|
|
{L"-l", TypeValue},
|
|
{L"-r", TypeValue},
|
|
{L"-c", TypeValue},
|
|
{L"-t", TypeValue},
|
|
{L"-s", TypeValue},
|
|
{NULL , TypeMax}
|
|
};
|
|
|
|
///
|
|
/// The default block size (512) of tftp is defined in the RFC1350.
|
|
///
|
|
#define MTFTP_DEFAULT_BLKSIZE 512
|
|
///
|
|
/// The valid range of block size option is defined in the RFC2348.
|
|
///
|
|
#define MTFTP_MIN_BLKSIZE 8
|
|
#define MTFTP_MAX_BLKSIZE 65464
|
|
|
|
|
|
/**
|
|
Function for 'tftp' command.
|
|
|
|
@param[in] ImageHandle Handle to the Image (NULL if Internal).
|
|
@param[in] SystemTable Pointer to the System Table (NULL if Internal).
|
|
|
|
@return SHELL_SUCCESS The 'tftp' command completed successfully.
|
|
@return SHELL_ABORTED The Shell Library initialization failed.
|
|
@return SHELL_INVALID_PARAMETER At least one of the command's arguments is
|
|
not valid.
|
|
@return SHELL_OUT_OF_RESOURCES A memory allocation failed.
|
|
@return SHELL_NOT_FOUND Network Interface Card not found or server
|
|
error or file error.
|
|
|
|
**/
|
|
SHELL_STATUS
|
|
EFIAPI
|
|
ShellCommandRunTftp (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
SHELL_STATUS ShellStatus;
|
|
EFI_STATUS Status;
|
|
LIST_ENTRY *CheckPackage;
|
|
CHAR16 *ProblemParam;
|
|
UINTN ParamCount;
|
|
CONST CHAR16 *UserNicName;
|
|
BOOLEAN NicFound;
|
|
CONST CHAR16 *ValueStr;
|
|
CONST CHAR16 *RemoteFilePath;
|
|
CHAR8 *AsciiRemoteFilePath;
|
|
UINTN FilePathSize;
|
|
CONST CHAR16 *Walker;
|
|
CONST CHAR16 *LocalFilePath;
|
|
EFI_MTFTP4_CONFIG_DATA Mtftp4ConfigData;
|
|
EFI_HANDLE *Handles;
|
|
UINTN HandleCount;
|
|
UINTN NicNumber;
|
|
CHAR16 NicName[IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH];
|
|
EFI_HANDLE ControllerHandle;
|
|
EFI_HANDLE Mtftp4ChildHandle;
|
|
EFI_MTFTP4_PROTOCOL *Mtftp4;
|
|
UINTN FileSize;
|
|
VOID *Data;
|
|
SHELL_FILE_HANDLE FileHandle;
|
|
UINT16 BlockSize;
|
|
|
|
ShellStatus = SHELL_INVALID_PARAMETER;
|
|
ProblemParam = NULL;
|
|
NicFound = FALSE;
|
|
AsciiRemoteFilePath = NULL;
|
|
Handles = NULL;
|
|
FileSize = 0;
|
|
BlockSize = MTFTP_DEFAULT_BLKSIZE;
|
|
|
|
//
|
|
// Initialize the Shell library (we must be in non-auto-init...)
|
|
//
|
|
Status = ShellInitialize ();
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT_EFI_ERROR (Status);
|
|
return SHELL_ABORTED;
|
|
}
|
|
|
|
//
|
|
// Parse the command line.
|
|
//
|
|
Status = ShellCommandLineParse (ParamList, &CheckPackage, &ProblemParam, TRUE);
|
|
if (EFI_ERROR (Status)) {
|
|
if ((Status == EFI_VOLUME_CORRUPTED) &&
|
|
(ProblemParam != NULL) ) {
|
|
ShellPrintHiiEx (
|
|
-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellTftpHiiHandle,
|
|
L"tftp", ProblemParam
|
|
);
|
|
FreePool (ProblemParam);
|
|
} else {
|
|
ASSERT (FALSE);
|
|
}
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Check the number of parameters
|
|
//
|
|
ParamCount = ShellCommandLineGetCount (CheckPackage);
|
|
if (ParamCount > 4) {
|
|
ShellPrintHiiEx (
|
|
-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY),
|
|
gShellTftpHiiHandle, L"tftp"
|
|
);
|
|
goto Error;
|
|
}
|
|
if (ParamCount < 3) {
|
|
ShellPrintHiiEx (
|
|
-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW),
|
|
gShellTftpHiiHandle, L"tftp"
|
|
);
|
|
goto Error;
|
|
}
|
|
|
|
CopyMem (&Mtftp4ConfigData, &DefaultMtftp4ConfigData, sizeof (EFI_MTFTP4_CONFIG_DATA));
|
|
|
|
//
|
|
// Check the host IPv4 address
|
|
//
|
|
ValueStr = ShellCommandLineGetRawValue (CheckPackage, 1);
|
|
Status = NetLibStrToIp4 (ValueStr, &Mtftp4ConfigData.ServerIp);
|
|
if (EFI_ERROR (Status)) {
|
|
ShellPrintHiiEx (
|
|
-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
|
|
gShellTftpHiiHandle, L"tftp", ValueStr
|
|
);
|
|
goto Error;
|
|
}
|
|
|
|
RemoteFilePath = ShellCommandLineGetRawValue (CheckPackage, 2);
|
|
ASSERT(RemoteFilePath != NULL);
|
|
FilePathSize = StrLen (RemoteFilePath) + 1;
|
|
AsciiRemoteFilePath = AllocatePool (FilePathSize);
|
|
if (AsciiRemoteFilePath == NULL) {
|
|
ShellStatus = SHELL_OUT_OF_RESOURCES;
|
|
goto Error;
|
|
}
|
|
UnicodeStrToAsciiStrS (RemoteFilePath, AsciiRemoteFilePath, FilePathSize);
|
|
|
|
if (ParamCount == 4) {
|
|
LocalFilePath = ShellCommandLineGetRawValue (CheckPackage, 3);
|
|
} else {
|
|
Walker = RemoteFilePath + StrLen (RemoteFilePath);
|
|
while ((--Walker) >= RemoteFilePath) {
|
|
if ((*Walker == L'\\') ||
|
|
(*Walker == L'/' ) ) {
|
|
break;
|
|
}
|
|
}
|
|
LocalFilePath = Walker + 1;
|
|
}
|
|
|
|
//
|
|
// Get the name of the Network Interface Card to be used if any.
|
|
//
|
|
UserNicName = ShellCommandLineGetValue (CheckPackage, L"-i");
|
|
|
|
ValueStr = ShellCommandLineGetValue (CheckPackage, L"-l");
|
|
if (ValueStr != NULL) {
|
|
if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.LocalPort)) {
|
|
goto Error;
|
|
}
|
|
}
|
|
|
|
ValueStr = ShellCommandLineGetValue (CheckPackage, L"-r");
|
|
if (ValueStr != NULL) {
|
|
if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.InitialServerPort)) {
|
|
goto Error;
|
|
}
|
|
}
|
|
|
|
ValueStr = ShellCommandLineGetValue (CheckPackage, L"-c");
|
|
if (ValueStr != NULL) {
|
|
if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.TryCount)) {
|
|
goto Error;
|
|
}
|
|
}
|
|
|
|
ValueStr = ShellCommandLineGetValue (CheckPackage, L"-t");
|
|
if (ValueStr != NULL) {
|
|
if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.TimeoutValue)) {
|
|
goto Error;
|
|
}
|
|
if (Mtftp4ConfigData.TimeoutValue == 0) {
|
|
ShellPrintHiiEx (
|
|
-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
|
|
gShellTftpHiiHandle, L"tftp", ValueStr
|
|
);
|
|
goto Error;
|
|
}
|
|
}
|
|
|
|
ValueStr = ShellCommandLineGetValue (CheckPackage, L"-s");
|
|
if (ValueStr != NULL) {
|
|
if (!StringToUint16 (ValueStr, &BlockSize)) {
|
|
goto Error;
|
|
}
|
|
if (BlockSize < MTFTP_MIN_BLKSIZE || BlockSize > MTFTP_MAX_BLKSIZE) {
|
|
ShellPrintHiiEx (
|
|
-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
|
|
gShellTftpHiiHandle, L"tftp", ValueStr
|
|
);
|
|
goto Error;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Locate all MTFTP4 Service Binding protocols
|
|
//
|
|
ShellStatus = SHELL_NOT_FOUND;
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiManagedNetworkServiceBindingProtocolGuid,
|
|
NULL,
|
|
&HandleCount,
|
|
&Handles
|
|
);
|
|
if (EFI_ERROR (Status) || (HandleCount == 0)) {
|
|
ShellPrintHiiEx (
|
|
-1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_NO_NIC),
|
|
gShellTftpHiiHandle
|
|
);
|
|
goto Error;
|
|
}
|
|
|
|
for (NicNumber = 0;
|
|
(NicNumber < HandleCount) && (ShellStatus != SHELL_SUCCESS);
|
|
NicNumber++) {
|
|
ControllerHandle = Handles[NicNumber];
|
|
Data = NULL;
|
|
|
|
Status = GetNicName (ControllerHandle, NicNumber, NicName);
|
|
if (EFI_ERROR (Status)) {
|
|
ShellPrintHiiEx (
|
|
-1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_NIC_NAME),
|
|
gShellTftpHiiHandle, NicNumber, Status
|
|
);
|
|
continue;
|
|
}
|
|
|
|
if (UserNicName != NULL) {
|
|
if (StrCmp (NicName, UserNicName) != 0) {
|
|
continue;
|
|
}
|
|
NicFound = TRUE;
|
|
}
|
|
|
|
Status = CreateServiceChildAndOpenProtocol (
|
|
ControllerHandle,
|
|
&gEfiMtftp4ServiceBindingProtocolGuid,
|
|
&gEfiMtftp4ProtocolGuid,
|
|
&Mtftp4ChildHandle,
|
|
(VOID**)&Mtftp4
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ShellPrintHiiEx (
|
|
-1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_OPEN_PROTOCOL),
|
|
gShellTftpHiiHandle, NicName, Status
|
|
);
|
|
continue;
|
|
}
|
|
|
|
Status = Mtftp4->Configure (Mtftp4, &Mtftp4ConfigData);
|
|
if (EFI_ERROR (Status)) {
|
|
ShellPrintHiiEx (
|
|
-1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_CONFIGURE),
|
|
gShellTftpHiiHandle, NicName, Status
|
|
);
|
|
goto NextHandle;
|
|
}
|
|
|
|
Status = GetFileSize (Mtftp4, AsciiRemoteFilePath, &FileSize);
|
|
if (EFI_ERROR (Status)) {
|
|
ShellPrintHiiEx (
|
|
-1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_FILE_SIZE),
|
|
gShellTftpHiiHandle, RemoteFilePath, NicName, Status
|
|
);
|
|
goto NextHandle;
|
|
}
|
|
|
|
Status = DownloadFile (Mtftp4, RemoteFilePath, AsciiRemoteFilePath, FileSize, BlockSize, &Data);
|
|
if (EFI_ERROR (Status)) {
|
|
ShellPrintHiiEx (
|
|
-1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_DOWNLOAD),
|
|
gShellTftpHiiHandle, RemoteFilePath, NicName, Status
|
|
);
|
|
goto NextHandle;
|
|
}
|
|
|
|
if (!EFI_ERROR (ShellFileExists (LocalFilePath))) {
|
|
ShellDeleteFileByName (LocalFilePath);
|
|
}
|
|
|
|
Status = ShellOpenFileByName (
|
|
LocalFilePath,
|
|
&FileHandle,
|
|
EFI_FILE_MODE_CREATE |
|
|
EFI_FILE_MODE_WRITE |
|
|
EFI_FILE_MODE_READ,
|
|
0
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ShellPrintHiiEx (
|
|
-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL),
|
|
gShellTftpHiiHandle, L"tftp", LocalFilePath
|
|
);
|
|
goto NextHandle;
|
|
}
|
|
|
|
Status = ShellWriteFile (FileHandle, &FileSize, Data);
|
|
if (!EFI_ERROR (Status)) {
|
|
ShellStatus = SHELL_SUCCESS;
|
|
} else {
|
|
ShellPrintHiiEx (
|
|
-1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_WRITE),
|
|
gShellTftpHiiHandle, LocalFilePath, Status
|
|
);
|
|
}
|
|
ShellCloseFile (&FileHandle);
|
|
|
|
NextHandle:
|
|
|
|
if (Data != NULL) {
|
|
gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)Data, EFI_SIZE_TO_PAGES (FileSize));
|
|
}
|
|
|
|
CloseProtocolAndDestroyServiceChild (
|
|
ControllerHandle,
|
|
&gEfiMtftp4ServiceBindingProtocolGuid,
|
|
&gEfiMtftp4ProtocolGuid,
|
|
Mtftp4ChildHandle
|
|
);
|
|
}
|
|
|
|
if ((UserNicName != NULL) && (!NicFound)) {
|
|
ShellPrintHiiEx (
|
|
-1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_NIC_NOT_FOUND),
|
|
gShellTftpHiiHandle, UserNicName
|
|
);
|
|
}
|
|
|
|
Error:
|
|
|
|
ShellCommandLineFreeVarList (CheckPackage);
|
|
if (AsciiRemoteFilePath != NULL) {
|
|
FreePool (AsciiRemoteFilePath);
|
|
}
|
|
if (Handles != NULL) {
|
|
FreePool (Handles);
|
|
}
|
|
|
|
return ShellStatus;
|
|
}
|
|
|
|
/**
|
|
Check and convert the UINT16 option values of the 'tftp' command
|
|
|
|
@param[in] ValueStr Value as an Unicode encoded string
|
|
@param[out] Value UINT16 value
|
|
|
|
@return TRUE The value was returned.
|
|
@return FALSE A parsing error occured.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
StringToUint16 (
|
|
IN CONST CHAR16 *ValueStr,
|
|
OUT UINT16 *Value
|
|
)
|
|
{
|
|
UINTN Val;
|
|
|
|
Val = ShellStrToUintn (ValueStr);
|
|
if (Val > MAX_UINT16) {
|
|
ShellPrintHiiEx (
|
|
-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
|
|
gShellTftpHiiHandle, L"tftp", ValueStr
|
|
);
|
|
return FALSE;
|
|
}
|
|
|
|
*Value = (UINT16)Val;
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
Get the name of the NIC.
|
|
|
|
@param[in] ControllerHandle The network physical device handle.
|
|
@param[in] NicNumber The network physical device number.
|
|
@param[out] NicName Address where to store the NIC name.
|
|
The memory area has to be at least
|
|
IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH
|
|
double byte wide.
|
|
|
|
@return EFI_SUCCESS The name of the NIC was returned.
|
|
@return Others The creation of the child for the Managed
|
|
Network Service failed or the opening of
|
|
the Managed Network Protocol failed or
|
|
the operational parameters for the
|
|
Managed Network Protocol could not be
|
|
read.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
GetNicName (
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN UINTN NicNumber,
|
|
OUT CHAR16 *NicName
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE MnpHandle;
|
|
EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
|
|
EFI_SIMPLE_NETWORK_MODE SnpMode;
|
|
|
|
Status = CreateServiceChildAndOpenProtocol (
|
|
ControllerHandle,
|
|
&gEfiManagedNetworkServiceBindingProtocolGuid,
|
|
&gEfiManagedNetworkProtocolGuid,
|
|
&MnpHandle,
|
|
(VOID**)&Mnp
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
Status = Mnp->GetModeData (Mnp, NULL, &SnpMode);
|
|
if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {
|
|
goto Error;
|
|
}
|
|
|
|
UnicodeSPrint (
|
|
NicName,
|
|
IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH,
|
|
SnpMode.IfType == NET_IFTYPE_ETHERNET ?
|
|
L"eth%d" :
|
|
L"unk%d" ,
|
|
NicNumber
|
|
);
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
Error:
|
|
|
|
if (MnpHandle != NULL) {
|
|
CloseProtocolAndDestroyServiceChild (
|
|
ControllerHandle,
|
|
&gEfiManagedNetworkServiceBindingProtocolGuid,
|
|
&gEfiManagedNetworkProtocolGuid,
|
|
MnpHandle
|
|
);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Create a child for the service identified by its service binding protocol GUID
|
|
and get from the child the interface of the protocol identified by its GUID.
|
|
|
|
@param[in] ControllerHandle Controller handle.
|
|
@param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the
|
|
service to be created.
|
|
@param[in] ProtocolGuid GUID of the protocol to be open.
|
|
@param[out] ChildHandle Address where the handler of the
|
|
created child is returned. NULL is
|
|
returned in case of error.
|
|
@param[out] Interface Address where a pointer to the
|
|
protocol interface is returned in
|
|
case of success.
|
|
|
|
@return EFI_SUCCESS The child was created and the protocol opened.
|
|
@return Others Either the creation of the child or the opening
|
|
of the protocol failed.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
CreateServiceChildAndOpenProtocol (
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_GUID *ServiceBindingProtocolGuid,
|
|
IN EFI_GUID *ProtocolGuid,
|
|
OUT EFI_HANDLE *ChildHandle,
|
|
OUT VOID **Interface
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
*ChildHandle = NULL;
|
|
Status = NetLibCreateServiceChild (
|
|
ControllerHandle,
|
|
gImageHandle,
|
|
ServiceBindingProtocolGuid,
|
|
ChildHandle
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = gBS->OpenProtocol (
|
|
*ChildHandle,
|
|
ProtocolGuid,
|
|
Interface,
|
|
gImageHandle,
|
|
ControllerHandle,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
NetLibDestroyServiceChild (
|
|
ControllerHandle,
|
|
gImageHandle,
|
|
ServiceBindingProtocolGuid,
|
|
*ChildHandle
|
|
);
|
|
*ChildHandle = NULL;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Close the protocol identified by its GUID on the child handle of the service
|
|
identified by its service binding protocol GUID, then destroy the child
|
|
handle.
|
|
|
|
@param[in] ControllerHandle Controller handle.
|
|
@param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the
|
|
service to be destroyed.
|
|
@param[in] ProtocolGuid GUID of the protocol to be closed.
|
|
@param[in] ChildHandle Handle of the child to be destroyed.
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
CloseProtocolAndDestroyServiceChild (
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_GUID *ServiceBindingProtocolGuid,
|
|
IN EFI_GUID *ProtocolGuid,
|
|
IN EFI_HANDLE ChildHandle
|
|
)
|
|
{
|
|
gBS->CloseProtocol (
|
|
ChildHandle,
|
|
ProtocolGuid,
|
|
gImageHandle,
|
|
ControllerHandle
|
|
);
|
|
|
|
NetLibDestroyServiceChild (
|
|
ControllerHandle,
|
|
gImageHandle,
|
|
ServiceBindingProtocolGuid,
|
|
ChildHandle
|
|
);
|
|
}
|
|
|
|
/**
|
|
Worker function that gets the size in numbers of bytes of a file from a TFTP
|
|
server before to download the file.
|
|
|
|
@param[in] Mtftp4 MTFTP4 protocol interface
|
|
@param[in] FilePath Path of the file, ASCII encoded
|
|
@param[out] FileSize Address where to store the file size in number of
|
|
bytes.
|
|
|
|
@retval EFI_SUCCESS The size of the file was returned.
|
|
@retval EFI_UNSUPPORTED The server does not support the "tsize" option.
|
|
@retval Others Error when retrieving the information from the server
|
|
(see EFI_MTFTP4_PROTOCOL.GetInfo() status codes)
|
|
or error when parsing the response of the server.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
GetFileSize (
|
|
IN EFI_MTFTP4_PROTOCOL *Mtftp4,
|
|
IN CONST CHAR8 *FilePath,
|
|
OUT UINTN *FileSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_MTFTP4_OPTION ReqOpt[1];
|
|
EFI_MTFTP4_PACKET *Packet;
|
|
UINT32 PktLen;
|
|
EFI_MTFTP4_OPTION *TableOfOptions;
|
|
EFI_MTFTP4_OPTION *Option;
|
|
UINT32 OptCnt;
|
|
UINT8 OptBuf[128];
|
|
|
|
ReqOpt[0].OptionStr = (UINT8*)"tsize";
|
|
OptBuf[0] = '0';
|
|
OptBuf[1] = 0;
|
|
ReqOpt[0].ValueStr = OptBuf;
|
|
|
|
Status = Mtftp4->GetInfo (
|
|
Mtftp4,
|
|
NULL,
|
|
(UINT8*)FilePath,
|
|
NULL,
|
|
1,
|
|
ReqOpt,
|
|
&PktLen,
|
|
&Packet
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
Status = Mtftp4->ParseOptions (
|
|
Mtftp4,
|
|
PktLen,
|
|
Packet,
|
|
(UINT32 *) &OptCnt,
|
|
&TableOfOptions
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
Option = TableOfOptions;
|
|
while (OptCnt != 0) {
|
|
if (AsciiStrnCmp ((CHAR8 *)Option->OptionStr, "tsize", 5) == 0) {
|
|
*FileSize = AsciiStrDecimalToUintn ((CHAR8 *)Option->ValueStr);
|
|
break;
|
|
}
|
|
OptCnt--;
|
|
Option++;
|
|
}
|
|
FreePool (TableOfOptions);
|
|
|
|
if (OptCnt == 0) {
|
|
Status = EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Error :
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Worker function that download the data of a file from a TFTP server given
|
|
the path of the file and its size.
|
|
|
|
@param[in] Mtftp4 MTFTP4 protocol interface
|
|
@param[in] FilePath Path of the file, Unicode encoded
|
|
@param[in] AsciiFilePath Path of the file, ASCII encoded
|
|
@param[in] FileSize Size of the file in number of bytes
|
|
@param[in] BlockSize Value of the TFTP blksize option
|
|
@param[out] Data Address where to store the address of the buffer
|
|
where the data of the file were downloaded in
|
|
case of success.
|
|
|
|
@retval EFI_SUCCESS The file was downloaded.
|
|
@retval EFI_OUT_OF_RESOURCES A memory allocation failed.
|
|
@retval Others The downloading of the file from the server failed
|
|
(see EFI_MTFTP4_PROTOCOL.ReadFile() status codes).
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
DownloadFile (
|
|
IN EFI_MTFTP4_PROTOCOL *Mtftp4,
|
|
IN CONST CHAR16 *FilePath,
|
|
IN CONST CHAR8 *AsciiFilePath,
|
|
IN UINTN FileSize,
|
|
IN UINT16 BlockSize,
|
|
OUT VOID **Data
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_PHYSICAL_ADDRESS PagesAddress;
|
|
VOID *Buffer;
|
|
DOWNLOAD_CONTEXT *TftpContext;
|
|
EFI_MTFTP4_TOKEN Mtftp4Token;
|
|
EFI_MTFTP4_OPTION ReqOpt;
|
|
UINT8 OptBuf[10];
|
|
|
|
// Downloaded file can be large. BS.AllocatePages() is more faster
|
|
// than AllocatePool() and avoid fragmentation.
|
|
// The downloaded file could be an EFI application. Marking the
|
|
// allocated page as EfiBootServicesCode would allow to execute a
|
|
// potential downloaded EFI application.
|
|
Status = gBS->AllocatePages (
|
|
AllocateAnyPages,
|
|
EfiBootServicesCode,
|
|
EFI_SIZE_TO_PAGES (FileSize),
|
|
&PagesAddress
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Buffer = (VOID*)(UINTN)PagesAddress;
|
|
TftpContext = AllocatePool (sizeof (DOWNLOAD_CONTEXT));
|
|
if (TftpContext == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Error;
|
|
}
|
|
TftpContext->FileSize = FileSize;
|
|
TftpContext->DownloadedNbOfBytes = 0;
|
|
TftpContext->LastReportedNbOfBytes = 0;
|
|
|
|
ZeroMem (&Mtftp4Token, sizeof (EFI_MTFTP4_TOKEN));
|
|
Mtftp4Token.Filename = (UINT8*)AsciiFilePath;
|
|
Mtftp4Token.BufferSize = FileSize;
|
|
Mtftp4Token.Buffer = Buffer;
|
|
Mtftp4Token.CheckPacket = CheckPacket;
|
|
Mtftp4Token.Context = (VOID*)TftpContext;
|
|
if (BlockSize != MTFTP_DEFAULT_BLKSIZE) {
|
|
ReqOpt.OptionStr = (UINT8 *) "blksize";
|
|
AsciiSPrint ((CHAR8 *)OptBuf, sizeof (OptBuf), "%d", BlockSize);
|
|
ReqOpt.ValueStr = OptBuf;
|
|
|
|
Mtftp4Token.OptionCount = 1;
|
|
Mtftp4Token.OptionList = &ReqOpt;
|
|
}
|
|
|
|
ShellPrintHiiEx (
|
|
-1, -1, NULL, STRING_TOKEN (STR_TFTP_DOWNLOADING),
|
|
gShellTftpHiiHandle, FilePath
|
|
);
|
|
|
|
Status = Mtftp4->ReadFile (Mtftp4, &Mtftp4Token);
|
|
ShellPrintHiiEx (
|
|
-1, -1, NULL, STRING_TOKEN (STR_GEN_CRLF),
|
|
gShellTftpHiiHandle
|
|
);
|
|
|
|
Error :
|
|
|
|
if (TftpContext == NULL) {
|
|
FreePool (TftpContext);
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->FreePages (PagesAddress, EFI_SIZE_TO_PAGES (FileSize));
|
|
return Status;
|
|
}
|
|
|
|
*Data = Buffer;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Update the progress of a file download
|
|
This procedure is called each time a new TFTP packet is received.
|
|
|
|
@param[in] This MTFTP4 protocol interface
|
|
@param[in] Token Parameters for the download of the file
|
|
@param[in] PacketLen Length of the packet
|
|
@param[in] Packet Address of the packet
|
|
|
|
@retval EFI_SUCCESS All packets are accepted.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CheckPacket (
|
|
IN EFI_MTFTP4_PROTOCOL *This,
|
|
IN EFI_MTFTP4_TOKEN *Token,
|
|
IN UINT16 PacketLen,
|
|
IN EFI_MTFTP4_PACKET *Packet
|
|
)
|
|
{
|
|
DOWNLOAD_CONTEXT *Context;
|
|
CHAR16 Progress[TFTP_PROGRESS_MESSAGE_SIZE];
|
|
UINTN NbOfKb;
|
|
UINTN Index;
|
|
UINTN LastStep;
|
|
UINTN Step;
|
|
EFI_STATUS Status;
|
|
|
|
if ((NTOHS (Packet->OpCode)) != EFI_MTFTP4_OPCODE_DATA) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
Context = (DOWNLOAD_CONTEXT*)Token->Context;
|
|
if (Context->DownloadedNbOfBytes == 0) {
|
|
ShellPrintEx (-1, -1, L"%s 0 Kb", mTftpProgressFrame);
|
|
}
|
|
|
|
//
|
|
// The data in the packet are prepended with two UINT16 :
|
|
// . OpCode = EFI_MTFTP4_OPCODE_DATA
|
|
// . Block = the number of this block of data
|
|
//
|
|
Context->DownloadedNbOfBytes += PacketLen - sizeof (Packet->OpCode)
|
|
- sizeof (Packet->Data.Block);
|
|
NbOfKb = Context->DownloadedNbOfBytes / 1024;
|
|
|
|
Progress[0] = L'\0';
|
|
LastStep = (Context->LastReportedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize;
|
|
Step = (Context->DownloadedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize;
|
|
|
|
if (Step <= LastStep) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
ShellPrintEx (-1, -1, L"%s", mTftpProgressDelete);
|
|
|
|
Status = StrCpyS (Progress, TFTP_PROGRESS_MESSAGE_SIZE, mTftpProgressFrame);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
for (Index = 1; Index < Step; Index++) {
|
|
Progress[Index] = L'=';
|
|
}
|
|
Progress[Step] = L'>';
|
|
|
|
UnicodeSPrint (
|
|
Progress + (sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 1,
|
|
sizeof (Progress) - sizeof (mTftpProgressFrame),
|
|
L" %7d Kb",
|
|
NbOfKb
|
|
);
|
|
Context->LastReportedNbOfBytes = Context->DownloadedNbOfBytes;
|
|
|
|
ShellPrintEx (-1, -1, L"%s", Progress);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|