summaryrefslogtreecommitdiff
path: root/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.c
diff options
context:
space:
mode:
Diffstat (limited to 'ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.c')
-rw-r--r--ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.c2496
1 files changed, 1248 insertions, 1248 deletions
diff --git a/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.c b/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.c
index 7e5c73b3da..01614a2e66 100644
--- a/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.c
+++ b/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.c
@@ -1,1248 +1,1248 @@
-/** @file
- The implementation for the 'tftp' Shell command.
-
- Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
- Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved. <BR>
- (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
-
- SPDX-License-Identifier: BSD-2-Clause-Patent
-**/
-
-#include "Tftp.h"
-
-#define IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH 32
-EFI_HII_HANDLE mTftpHiiHandle;
-
-/*
- Constant strings and definitions related to the message indicating the amount of
- progress in the downloading 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";
-
-// Local File Handle
-SHELL_FILE_HANDLE mFileHandle;
-
-// Path of the local file, Unicode encoded
-CONST CHAR16 *mLocalFilePath;
-
-/**
- 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 occurred.
-**/
-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[in] WindowSize Value of the TFTP window size option
-
- @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,
- IN UINT16 WindowSize
- );
-
-/**
- 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 - The number of times to transmit request packets and wait for a response.
- 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 },
- { L"-w", 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
-///
-/// The default windowsize (1) of tftp.
-///
-#define MTFTP_DEFAULT_WINDOWSIZE 1
-///
-/// The valid range of window size option.
-/// Note that: RFC 7440 does not mention max window size value, but for the
-/// stability reason, the value is limited to 64.
-///
-#define MTFTP_MIN_WINDOWSIZE 1
-#define MTFTP_MAX_WINDOWSIZE 64
-
-/**
- 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
-RunTftp (
- 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;
- 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;
- UINT16 BlockSize;
- UINT16 WindowSize;
-
- ShellStatus = SHELL_INVALID_PARAMETER;
- ProblemParam = NULL;
- NicFound = FALSE;
- AsciiRemoteFilePath = NULL;
- Handles = NULL;
- FileSize = 0;
- BlockSize = MTFTP_DEFAULT_BLKSIZE;
- WindowSize = MTFTP_DEFAULT_WINDOWSIZE;
-
- //
- // 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),
- mTftpHiiHandle,
- 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),
- mTftpHiiHandle,
- L"tftp"
- );
- goto Error;
- }
-
- if (ParamCount < 3) {
- ShellPrintHiiEx (
- -1,
- -1,
- NULL,
- STRING_TOKEN (STR_GEN_TOO_FEW),
- mTftpHiiHandle,
- 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),
- mTftpHiiHandle,
- 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) {
- mLocalFilePath = ShellCommandLineGetRawValue (CheckPackage, 3);
- } else {
- Walker = RemoteFilePath + StrLen (RemoteFilePath);
- while ((--Walker) >= RemoteFilePath) {
- if ((*Walker == L'\\') ||
- (*Walker == L'/'))
- {
- break;
- }
- }
-
- mLocalFilePath = 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;
- }
-
- if (Mtftp4ConfigData.TryCount == 0) {
- Mtftp4ConfigData.TryCount = 6;
- }
- }
-
- 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),
- mTftpHiiHandle,
- 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),
- mTftpHiiHandle,
- L"tftp",
- ValueStr
- );
- goto Error;
- }
- }
-
- ValueStr = ShellCommandLineGetValue (CheckPackage, L"-w");
- if (ValueStr != NULL) {
- if (!StringToUint16 (ValueStr, &WindowSize)) {
- goto Error;
- }
-
- if ((WindowSize < MTFTP_MIN_WINDOWSIZE) || (WindowSize > MTFTP_MAX_WINDOWSIZE)) {
- ShellPrintHiiEx (
- -1,
- -1,
- NULL,
- STRING_TOKEN (STR_GEN_PARAM_INV),
- mTftpHiiHandle,
- 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),
- mTftpHiiHandle
- );
- goto Error;
- }
-
- for (NicNumber = 0;
- (NicNumber < HandleCount) && (ShellStatus != SHELL_SUCCESS);
- NicNumber++)
- {
- ControllerHandle = Handles[NicNumber];
-
- Status = GetNicName (ControllerHandle, NicNumber, NicName);
- if (EFI_ERROR (Status)) {
- ShellPrintHiiEx (
- -1,
- -1,
- NULL,
- STRING_TOKEN (STR_TFTP_ERR_NIC_NAME),
- mTftpHiiHandle,
- 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),
- mTftpHiiHandle,
- NicName,
- Status
- );
- continue;
- }
-
- Status = Mtftp4->Configure (Mtftp4, &Mtftp4ConfigData);
- if (EFI_ERROR (Status)) {
- ShellPrintHiiEx (
- -1,
- -1,
- NULL,
- STRING_TOKEN (STR_TFTP_ERR_CONFIGURE),
- mTftpHiiHandle,
- NicName,
- Status
- );
- goto NextHandle;
- }
-
- Status = GetFileSize (Mtftp4, AsciiRemoteFilePath, &FileSize);
- if (EFI_ERROR (Status)) {
- ShellPrintHiiEx (
- -1,
- -1,
- NULL,
- STRING_TOKEN (STR_TFTP_ERR_FILE_SIZE),
- mTftpHiiHandle,
- RemoteFilePath,
- NicName,
- Status
- );
- goto NextHandle;
- }
-
- Status = DownloadFile (Mtftp4, RemoteFilePath, AsciiRemoteFilePath, FileSize, BlockSize, WindowSize);
- if (EFI_ERROR (Status)) {
- ShellPrintHiiEx (
- -1,
- -1,
- NULL,
- STRING_TOKEN (STR_TFTP_ERR_DOWNLOAD),
- mTftpHiiHandle,
- RemoteFilePath,
- NicName,
- Status
- );
- goto NextHandle;
- }
-
- ShellStatus = SHELL_SUCCESS;
-
-NextHandle:
-
- CloseProtocolAndDestroyServiceChild (
- ControllerHandle,
- &gEfiMtftp4ServiceBindingProtocolGuid,
- &gEfiMtftp4ProtocolGuid,
- Mtftp4ChildHandle
- );
- }
-
- if ((UserNicName != NULL) && (!NicFound)) {
- ShellPrintHiiEx (
- -1,
- -1,
- NULL,
- STRING_TOKEN (STR_TFTP_ERR_NIC_NOT_FOUND),
- mTftpHiiHandle,
- UserNicName
- );
- }
-
-Error:
-
- ShellCommandLineFreeVarList (CheckPackage);
- if (AsciiRemoteFilePath != NULL) {
- FreePool (AsciiRemoteFilePath);
- }
-
- if (Handles != NULL) {
- FreePool (Handles);
- }
-
- if ((ShellStatus != SHELL_SUCCESS) && (EFI_ERROR (Status))) {
- ShellStatus = Status & ~MAX_BIT;
- }
-
- 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 occurred.
-**/
-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),
- mTftpHiiHandle,
- 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[in] WindowSize Value of the TFTP window size option
-
- @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,
- IN UINT16 WindowSize
- )
-{
- EFI_STATUS Status;
- DOWNLOAD_CONTEXT *TftpContext;
- EFI_MTFTP4_TOKEN Mtftp4Token;
- UINT8 BlksizeBuf[10];
- UINT8 WindowsizeBuf[10];
-
- ZeroMem (&Mtftp4Token, sizeof (EFI_MTFTP4_TOKEN));
-
- TftpContext = AllocatePool (sizeof (DOWNLOAD_CONTEXT));
- if (TftpContext == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Error;
- }
-
- TftpContext->FileSize = FileSize;
- TftpContext->DownloadedNbOfBytes = 0;
- TftpContext->LastReportedNbOfBytes = 0;
-
- Mtftp4Token.Filename = (UINT8 *)AsciiFilePath;
- Mtftp4Token.CheckPacket = CheckPacket;
- Mtftp4Token.Context = (VOID *)TftpContext;
- Mtftp4Token.OptionCount = 0;
- Mtftp4Token.OptionList = AllocatePool (sizeof (EFI_MTFTP4_OPTION) * 2);
- if (Mtftp4Token.OptionList == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Error;
- }
-
- if (BlockSize != MTFTP_DEFAULT_BLKSIZE) {
- Mtftp4Token.OptionList[Mtftp4Token.OptionCount].OptionStr = (UINT8 *)"blksize";
- AsciiSPrint ((CHAR8 *)BlksizeBuf, sizeof (BlksizeBuf), "%d", BlockSize);
- Mtftp4Token.OptionList[Mtftp4Token.OptionCount].ValueStr = BlksizeBuf;
- Mtftp4Token.OptionCount++;
- }
-
- if (WindowSize != MTFTP_DEFAULT_WINDOWSIZE) {
- Mtftp4Token.OptionList[Mtftp4Token.OptionCount].OptionStr = (UINT8 *)"windowsize";
- AsciiSPrint ((CHAR8 *)WindowsizeBuf, sizeof (WindowsizeBuf), "%d", WindowSize);
- Mtftp4Token.OptionList[Mtftp4Token.OptionCount].ValueStr = WindowsizeBuf;
- Mtftp4Token.OptionCount++;
- }
-
- ShellPrintHiiEx (
- -1,
- -1,
- NULL,
- STRING_TOKEN (STR_TFTP_DOWNLOADING),
- mTftpHiiHandle,
- FilePath
- );
-
- //
- // OPEN FILE
- //
- if (!EFI_ERROR (ShellFileExists (mLocalFilePath))) {
- ShellDeleteFileByName (mLocalFilePath);
- }
-
- Status = ShellOpenFileByName (
- mLocalFilePath,
- &mFileHandle,
- 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),
- mTftpHiiHandle,
- L"tftp",
- mLocalFilePath
- );
- goto Error;
- }
-
- Status = Mtftp4->ReadFile (Mtftp4, &Mtftp4Token);
- ShellPrintHiiEx (
- -1,
- -1,
- NULL,
- STRING_TOKEN (STR_GEN_CRLF),
- mTftpHiiHandle
- );
-
- //
- // CLOSE FILE
- //
- ShellCloseFile (&mFileHandle);
-
-Error:
- if (TftpContext != NULL) {
- FreePool (TftpContext);
- }
-
- if (Mtftp4Token.OptionList != NULL) {
- FreePool (Mtftp4Token.OptionList);
- }
-
- return Status;
-}
-
-/**
- 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;
- UINTN DownloadLen;
- EFI_STATUS Status;
-
- if ((NTOHS (Packet->OpCode)) != EFI_MTFTP4_OPCODE_DATA) {
- return EFI_SUCCESS;
- }
-
- Context = (DOWNLOAD_CONTEXT *)Token->Context;
-
- //
- // The data in the packet are prepended with two UINT16 :
- // . OpCode = EFI_MTFTP4_OPCODE_DATA
- // . Block = the number of this block of data
- //
- DownloadLen = (UINTN)PacketLen - sizeof (Packet->OpCode) - sizeof (Packet->Data.Block);
-
- ShellSetFilePosition (mFileHandle, Context->DownloadedNbOfBytes);
- Status = ShellWriteFile (mFileHandle, &DownloadLen, Packet->Data.Data);
- if (EFI_ERROR (Status)) {
- if (Context->DownloadedNbOfBytes > 0) {
- ShellPrintHiiEx (
- -1,
- -1,
- NULL,
- STRING_TOKEN (STR_GEN_CRLF),
- mTftpHiiHandle
- );
- }
-
- ShellPrintHiiEx (
- -1,
- -1,
- NULL,
- STRING_TOKEN (STR_TFTP_ERR_WRITE),
- mTftpHiiHandle,
- mLocalFilePath,
- Status
- );
- return Status;
- }
-
- if (Context->DownloadedNbOfBytes == 0) {
- ShellPrintEx (-1, -1, L"%s 0 Kb", mTftpProgressFrame);
- }
-
- Context->DownloadedNbOfBytes += DownloadLen;
- 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;
-}
-
-/**
- Retrieve HII package list from ImageHandle and publish to HII database.
-
- @param ImageHandle The image handle of the process.
-
- @return HII handle.
-**/
-EFI_HII_HANDLE
-InitializeHiiPackage (
- EFI_HANDLE ImageHandle
- )
-{
- EFI_STATUS Status;
- EFI_HII_PACKAGE_LIST_HEADER *PackageList;
- EFI_HII_HANDLE HiiHandle;
-
- //
- // Retrieve HII package list from ImageHandle
- //
- Status = gBS->OpenProtocol (
- ImageHandle,
- &gEfiHiiPackageListProtocolGuid,
- (VOID **)&PackageList,
- ImageHandle,
- NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- ASSERT_EFI_ERROR (Status);
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- //
- // Publish HII package list to HII Database.
- //
- Status = gHiiDatabase->NewPackageList (
- gHiiDatabase,
- PackageList,
- NULL,
- &HiiHandle
- );
- ASSERT_EFI_ERROR (Status);
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- return HiiHandle;
-}
+/** @file
+ The implementation for the 'tftp' Shell command.
+
+ Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
+ Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved. <BR>
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "Tftp.h"
+
+#define IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH 32
+EFI_HII_HANDLE mTftpHiiHandle;
+
+/*
+ Constant strings and definitions related to the message indicating the amount of
+ progress in the downloading 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";
+
+// Local File Handle
+SHELL_FILE_HANDLE mFileHandle;
+
+// Path of the local file, Unicode encoded
+CONST CHAR16 *mLocalFilePath;
+
+/**
+ 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 occurred.
+**/
+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[in] WindowSize Value of the TFTP window size option
+
+ @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,
+ IN UINT16 WindowSize
+ );
+
+/**
+ 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 - The number of times to transmit request packets and wait for a response.
+ 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 },
+ { L"-w", 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
+///
+/// The default windowsize (1) of tftp.
+///
+#define MTFTP_DEFAULT_WINDOWSIZE 1
+///
+/// The valid range of window size option.
+/// Note that: RFC 7440 does not mention max window size value, but for the
+/// stability reason, the value is limited to 64.
+///
+#define MTFTP_MIN_WINDOWSIZE 1
+#define MTFTP_MAX_WINDOWSIZE 64
+
+/**
+ 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
+RunTftp (
+ 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;
+ 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;
+ UINT16 BlockSize;
+ UINT16 WindowSize;
+
+ ShellStatus = SHELL_INVALID_PARAMETER;
+ ProblemParam = NULL;
+ NicFound = FALSE;
+ AsciiRemoteFilePath = NULL;
+ Handles = NULL;
+ FileSize = 0;
+ BlockSize = MTFTP_DEFAULT_BLKSIZE;
+ WindowSize = MTFTP_DEFAULT_WINDOWSIZE;
+
+ //
+ // 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),
+ mTftpHiiHandle,
+ 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),
+ mTftpHiiHandle,
+ L"tftp"
+ );
+ goto Error;
+ }
+
+ if (ParamCount < 3) {
+ ShellPrintHiiEx (
+ -1,
+ -1,
+ NULL,
+ STRING_TOKEN (STR_GEN_TOO_FEW),
+ mTftpHiiHandle,
+ 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),
+ mTftpHiiHandle,
+ 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) {
+ mLocalFilePath = ShellCommandLineGetRawValue (CheckPackage, 3);
+ } else {
+ Walker = RemoteFilePath + StrLen (RemoteFilePath);
+ while ((--Walker) >= RemoteFilePath) {
+ if ((*Walker == L'\\') ||
+ (*Walker == L'/'))
+ {
+ break;
+ }
+ }
+
+ mLocalFilePath = 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;
+ }
+
+ if (Mtftp4ConfigData.TryCount == 0) {
+ Mtftp4ConfigData.TryCount = 6;
+ }
+ }
+
+ 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),
+ mTftpHiiHandle,
+ 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),
+ mTftpHiiHandle,
+ L"tftp",
+ ValueStr
+ );
+ goto Error;
+ }
+ }
+
+ ValueStr = ShellCommandLineGetValue (CheckPackage, L"-w");
+ if (ValueStr != NULL) {
+ if (!StringToUint16 (ValueStr, &WindowSize)) {
+ goto Error;
+ }
+
+ if ((WindowSize < MTFTP_MIN_WINDOWSIZE) || (WindowSize > MTFTP_MAX_WINDOWSIZE)) {
+ ShellPrintHiiEx (
+ -1,
+ -1,
+ NULL,
+ STRING_TOKEN (STR_GEN_PARAM_INV),
+ mTftpHiiHandle,
+ 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),
+ mTftpHiiHandle
+ );
+ goto Error;
+ }
+
+ for (NicNumber = 0;
+ (NicNumber < HandleCount) && (ShellStatus != SHELL_SUCCESS);
+ NicNumber++)
+ {
+ ControllerHandle = Handles[NicNumber];
+
+ Status = GetNicName (ControllerHandle, NicNumber, NicName);
+ if (EFI_ERROR (Status)) {
+ ShellPrintHiiEx (
+ -1,
+ -1,
+ NULL,
+ STRING_TOKEN (STR_TFTP_ERR_NIC_NAME),
+ mTftpHiiHandle,
+ 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),
+ mTftpHiiHandle,
+ NicName,
+ Status
+ );
+ continue;
+ }
+
+ Status = Mtftp4->Configure (Mtftp4, &Mtftp4ConfigData);
+ if (EFI_ERROR (Status)) {
+ ShellPrintHiiEx (
+ -1,
+ -1,
+ NULL,
+ STRING_TOKEN (STR_TFTP_ERR_CONFIGURE),
+ mTftpHiiHandle,
+ NicName,
+ Status
+ );
+ goto NextHandle;
+ }
+
+ Status = GetFileSize (Mtftp4, AsciiRemoteFilePath, &FileSize);
+ if (EFI_ERROR (Status)) {
+ ShellPrintHiiEx (
+ -1,
+ -1,
+ NULL,
+ STRING_TOKEN (STR_TFTP_ERR_FILE_SIZE),
+ mTftpHiiHandle,
+ RemoteFilePath,
+ NicName,
+ Status
+ );
+ goto NextHandle;
+ }
+
+ Status = DownloadFile (Mtftp4, RemoteFilePath, AsciiRemoteFilePath, FileSize, BlockSize, WindowSize);
+ if (EFI_ERROR (Status)) {
+ ShellPrintHiiEx (
+ -1,
+ -1,
+ NULL,
+ STRING_TOKEN (STR_TFTP_ERR_DOWNLOAD),
+ mTftpHiiHandle,
+ RemoteFilePath,
+ NicName,
+ Status
+ );
+ goto NextHandle;
+ }
+
+ ShellStatus = SHELL_SUCCESS;
+
+NextHandle:
+
+ CloseProtocolAndDestroyServiceChild (
+ ControllerHandle,
+ &gEfiMtftp4ServiceBindingProtocolGuid,
+ &gEfiMtftp4ProtocolGuid,
+ Mtftp4ChildHandle
+ );
+ }
+
+ if ((UserNicName != NULL) && (!NicFound)) {
+ ShellPrintHiiEx (
+ -1,
+ -1,
+ NULL,
+ STRING_TOKEN (STR_TFTP_ERR_NIC_NOT_FOUND),
+ mTftpHiiHandle,
+ UserNicName
+ );
+ }
+
+Error:
+
+ ShellCommandLineFreeVarList (CheckPackage);
+ if (AsciiRemoteFilePath != NULL) {
+ FreePool (AsciiRemoteFilePath);
+ }
+
+ if (Handles != NULL) {
+ FreePool (Handles);
+ }
+
+ if ((ShellStatus != SHELL_SUCCESS) && (EFI_ERROR (Status))) {
+ ShellStatus = Status & ~MAX_BIT;
+ }
+
+ 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 occurred.
+**/
+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),
+ mTftpHiiHandle,
+ 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[in] WindowSize Value of the TFTP window size option
+
+ @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,
+ IN UINT16 WindowSize
+ )
+{
+ EFI_STATUS Status;
+ DOWNLOAD_CONTEXT *TftpContext;
+ EFI_MTFTP4_TOKEN Mtftp4Token;
+ UINT8 BlksizeBuf[10];
+ UINT8 WindowsizeBuf[10];
+
+ ZeroMem (&Mtftp4Token, sizeof (EFI_MTFTP4_TOKEN));
+
+ TftpContext = AllocatePool (sizeof (DOWNLOAD_CONTEXT));
+ if (TftpContext == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ TftpContext->FileSize = FileSize;
+ TftpContext->DownloadedNbOfBytes = 0;
+ TftpContext->LastReportedNbOfBytes = 0;
+
+ Mtftp4Token.Filename = (UINT8 *)AsciiFilePath;
+ Mtftp4Token.CheckPacket = CheckPacket;
+ Mtftp4Token.Context = (VOID *)TftpContext;
+ Mtftp4Token.OptionCount = 0;
+ Mtftp4Token.OptionList = AllocatePool (sizeof (EFI_MTFTP4_OPTION) * 2);
+ if (Mtftp4Token.OptionList == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ if (BlockSize != MTFTP_DEFAULT_BLKSIZE) {
+ Mtftp4Token.OptionList[Mtftp4Token.OptionCount].OptionStr = (UINT8 *)"blksize";
+ AsciiSPrint ((CHAR8 *)BlksizeBuf, sizeof (BlksizeBuf), "%d", BlockSize);
+ Mtftp4Token.OptionList[Mtftp4Token.OptionCount].ValueStr = BlksizeBuf;
+ Mtftp4Token.OptionCount++;
+ }
+
+ if (WindowSize != MTFTP_DEFAULT_WINDOWSIZE) {
+ Mtftp4Token.OptionList[Mtftp4Token.OptionCount].OptionStr = (UINT8 *)"windowsize";
+ AsciiSPrint ((CHAR8 *)WindowsizeBuf, sizeof (WindowsizeBuf), "%d", WindowSize);
+ Mtftp4Token.OptionList[Mtftp4Token.OptionCount].ValueStr = WindowsizeBuf;
+ Mtftp4Token.OptionCount++;
+ }
+
+ ShellPrintHiiEx (
+ -1,
+ -1,
+ NULL,
+ STRING_TOKEN (STR_TFTP_DOWNLOADING),
+ mTftpHiiHandle,
+ FilePath
+ );
+
+ //
+ // OPEN FILE
+ //
+ if (!EFI_ERROR (ShellFileExists (mLocalFilePath))) {
+ ShellDeleteFileByName (mLocalFilePath);
+ }
+
+ Status = ShellOpenFileByName (
+ mLocalFilePath,
+ &mFileHandle,
+ 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),
+ mTftpHiiHandle,
+ L"tftp",
+ mLocalFilePath
+ );
+ goto Error;
+ }
+
+ Status = Mtftp4->ReadFile (Mtftp4, &Mtftp4Token);
+ ShellPrintHiiEx (
+ -1,
+ -1,
+ NULL,
+ STRING_TOKEN (STR_GEN_CRLF),
+ mTftpHiiHandle
+ );
+
+ //
+ // CLOSE FILE
+ //
+ ShellCloseFile (&mFileHandle);
+
+Error:
+ if (TftpContext != NULL) {
+ FreePool (TftpContext);
+ }
+
+ if (Mtftp4Token.OptionList != NULL) {
+ FreePool (Mtftp4Token.OptionList);
+ }
+
+ return Status;
+}
+
+/**
+ 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;
+ UINTN DownloadLen;
+ EFI_STATUS Status;
+
+ if ((NTOHS (Packet->OpCode)) != EFI_MTFTP4_OPCODE_DATA) {
+ return EFI_SUCCESS;
+ }
+
+ Context = (DOWNLOAD_CONTEXT *)Token->Context;
+
+ //
+ // The data in the packet are prepended with two UINT16 :
+ // . OpCode = EFI_MTFTP4_OPCODE_DATA
+ // . Block = the number of this block of data
+ //
+ DownloadLen = (UINTN)PacketLen - sizeof (Packet->OpCode) - sizeof (Packet->Data.Block);
+
+ ShellSetFilePosition (mFileHandle, Context->DownloadedNbOfBytes);
+ Status = ShellWriteFile (mFileHandle, &DownloadLen, Packet->Data.Data);
+ if (EFI_ERROR (Status)) {
+ if (Context->DownloadedNbOfBytes > 0) {
+ ShellPrintHiiEx (
+ -1,
+ -1,
+ NULL,
+ STRING_TOKEN (STR_GEN_CRLF),
+ mTftpHiiHandle
+ );
+ }
+
+ ShellPrintHiiEx (
+ -1,
+ -1,
+ NULL,
+ STRING_TOKEN (STR_TFTP_ERR_WRITE),
+ mTftpHiiHandle,
+ mLocalFilePath,
+ Status
+ );
+ return Status;
+ }
+
+ if (Context->DownloadedNbOfBytes == 0) {
+ ShellPrintEx (-1, -1, L"%s 0 Kb", mTftpProgressFrame);
+ }
+
+ Context->DownloadedNbOfBytes += DownloadLen;
+ 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;
+}
+
+/**
+ Retrieve HII package list from ImageHandle and publish to HII database.
+
+ @param ImageHandle The image handle of the process.
+
+ @return HII handle.
+**/
+EFI_HII_HANDLE
+InitializeHiiPackage (
+ EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_LIST_HEADER *PackageList;
+ EFI_HII_HANDLE HiiHandle;
+
+ //
+ // Retrieve HII package list from ImageHandle
+ //
+ Status = gBS->OpenProtocol (
+ ImageHandle,
+ &gEfiHiiPackageListProtocolGuid,
+ (VOID **)&PackageList,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ //
+ // Publish HII package list to HII Database.
+ //
+ Status = gHiiDatabase->NewPackageList (
+ gHiiDatabase,
+ PackageList,
+ NULL,
+ &HiiHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ return HiiHandle;
+}