NetworkPkg: Move Network library and drivers from MdeModulePkg to NetworkPkg
Signed-off-by: Liming Gao <liming.gao@intel.com> Cc: Siyuan Fu <siyuan.fu@intel.com> Cc: Jiaxin Wu <jiaxin.wu@intel.com> Reviewed-by: Jiaxin Wu <jiaxin.wu@intel.com> Reviewed-by: Siyuan Fu <siyuan.fu@intel.com>
This commit is contained in:
425
NetworkPkg/Mtftp4Dxe/ComponentName.c
Normal file
425
NetworkPkg/Mtftp4Dxe/ComponentName.c
Normal file
@@ -0,0 +1,425 @@
|
||||
/** @file
|
||||
UEFI Component Name(2) protocol implementation for Mtftp4Dxe driver.
|
||||
|
||||
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#include "Mtftp4Impl.h"
|
||||
|
||||
//
|
||||
// EFI Component Name Functions
|
||||
//
|
||||
/**
|
||||
Retrieves a Unicode string that is the user readable name of the driver.
|
||||
|
||||
This function retrieves the user readable name of a driver in the form of a
|
||||
Unicode string. If the driver specified by This has a user readable name in
|
||||
the language specified by Language, then a pointer to the driver name is
|
||||
returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
|
||||
by This does not support the language specified by Language,
|
||||
then EFI_UNSUPPORTED is returned.
|
||||
|
||||
@param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
|
||||
EFI_COMPONENT_NAME_PROTOCOL instance.
|
||||
|
||||
@param[in] Language A pointer to a Null-terminated ASCII string
|
||||
array indicating the language. This is the
|
||||
language of the driver name that the caller is
|
||||
requesting, and it must match one of the
|
||||
languages specified in SupportedLanguages. The
|
||||
number of languages supported by a driver is up
|
||||
to the driver writer. Language is specified
|
||||
in RFC 4646 or ISO 639-2 language code format.
|
||||
|
||||
@param[out] DriverName A pointer to the Unicode string to return.
|
||||
This Unicode string is the name of the
|
||||
driver specified by This in the language
|
||||
specified by Language.
|
||||
|
||||
@retval EFI_SUCCESS The Unicode string for the Driver specified by
|
||||
This and the language specified by Language was
|
||||
returned in DriverName.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER Language is NULL.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER DriverName is NULL.
|
||||
|
||||
@retval EFI_UNSUPPORTED The driver specified by This does not support
|
||||
the language specified by Language.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4ComponentNameGetDriverName (
|
||||
IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **DriverName
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
Retrieves a Unicode string that is the user readable name of the controller
|
||||
that is being managed by a driver.
|
||||
|
||||
This function retrieves the user readable name of the controller specified by
|
||||
ControllerHandle and ChildHandle in the form of a Unicode string. If the
|
||||
driver specified by This has a user readable name in the language specified by
|
||||
Language, then a pointer to the controller name is returned in ControllerName,
|
||||
and EFI_SUCCESS is returned. If the driver specified by This is not currently
|
||||
managing the controller specified by ControllerHandle and ChildHandle,
|
||||
then EFI_UNSUPPORTED is returned. If the driver specified by This does not
|
||||
support the language specified by Language, then EFI_UNSUPPORTED is returned.
|
||||
|
||||
@param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
|
||||
EFI_COMPONENT_NAME_PROTOCOL instance.
|
||||
|
||||
@param[in] ControllerHandle The handle of a controller that the driver
|
||||
specified by This is managing. This handle
|
||||
specifies the controller whose name is to be
|
||||
returned.
|
||||
|
||||
@param[in] ChildHandle The handle of the child controller to retrieve
|
||||
the name of. This is an optional parameter that
|
||||
may be NULL. It will be NULL for device
|
||||
drivers. It will also be NULL for a bus drivers
|
||||
that wish to retrieve the name of the bus
|
||||
controller. It will not be NULL for a bus
|
||||
driver that wishes to retrieve the name of a
|
||||
child controller.
|
||||
|
||||
@param[in] Language A pointer to a Null-terminated ASCII string
|
||||
array indicating the language. This is the
|
||||
language of the driver name that the caller is
|
||||
requesting, and it must match one of the
|
||||
languages specified in SupportedLanguages. The
|
||||
number of languages supported by a driver is up
|
||||
to the driver writer. Language is specified in
|
||||
RFC 4646 or ISO 639-2 language code format.
|
||||
|
||||
@param[out] ControllerName A pointer to the Unicode string to return.
|
||||
This Unicode string is the name of the
|
||||
controller specified by ControllerHandle and
|
||||
ChildHandle in the language specified by
|
||||
Language from the point of view of the driver
|
||||
specified by This.
|
||||
|
||||
@retval EFI_SUCCESS The Unicode string for the user readable name in
|
||||
the language specified by Language for the
|
||||
driver specified by This was returned in
|
||||
DriverName.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
|
||||
EFI_HANDLE.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER Language is NULL.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER ControllerName is NULL.
|
||||
|
||||
@retval EFI_UNSUPPORTED The driver specified by This is not currently
|
||||
managing the controller specified by
|
||||
ControllerHandle and ChildHandle.
|
||||
|
||||
@retval EFI_UNSUPPORTED The driver specified by This does not support
|
||||
the language specified by Language.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4ComponentNameGetControllerName (
|
||||
IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_HANDLE ChildHandle OPTIONAL,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **ControllerName
|
||||
);
|
||||
|
||||
|
||||
///
|
||||
/// EFI Component Name Protocol
|
||||
///
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gMtftp4ComponentName = {
|
||||
Mtftp4ComponentNameGetDriverName,
|
||||
Mtftp4ComponentNameGetControllerName,
|
||||
"eng"
|
||||
};
|
||||
|
||||
///
|
||||
/// EFI Component Name 2 Protocol
|
||||
///
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gMtftp4ComponentName2 = {
|
||||
(EFI_COMPONENT_NAME2_GET_DRIVER_NAME) Mtftp4ComponentNameGetDriverName,
|
||||
(EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) Mtftp4ComponentNameGetControllerName,
|
||||
"en"
|
||||
};
|
||||
|
||||
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mMtftp4DriverNameTable[] = {
|
||||
{
|
||||
"eng;en",
|
||||
L"MTFTP4 Network Service"
|
||||
},
|
||||
{
|
||||
NULL,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE *gMtftp4ControllerNameTable = NULL;
|
||||
|
||||
/**
|
||||
Retrieves a Unicode string that is the user readable name of the driver.
|
||||
|
||||
This function retrieves the user readable name of a driver in the form of a
|
||||
Unicode string. If the driver specified by This has a user readable name in
|
||||
the language specified by Language, then a pointer to the driver name is
|
||||
returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
|
||||
by This does not support the language specified by Language,
|
||||
then EFI_UNSUPPORTED is returned.
|
||||
|
||||
@param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
|
||||
EFI_COMPONENT_NAME_PROTOCOL instance.
|
||||
|
||||
@param[in] Language A pointer to a Null-terminated ASCII string
|
||||
array indicating the language. This is the
|
||||
language of the driver name that the caller is
|
||||
requesting, and it must match one of the
|
||||
languages specified in SupportedLanguages. The
|
||||
number of languages supported by a driver is up
|
||||
to the driver writer. Language is specified
|
||||
in RFC 4646 or ISO 639-2 language code format.
|
||||
|
||||
@param[out] DriverName A pointer to the Unicode string to return.
|
||||
This Unicode string is the name of the
|
||||
driver specified by This in the language
|
||||
specified by Language.
|
||||
|
||||
@retval EFI_SUCCESS The Unicode string for the Driver specified by
|
||||
This and the language specified by Language was
|
||||
returned in DriverName.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER Language is NULL.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER DriverName is NULL.
|
||||
|
||||
@retval EFI_UNSUPPORTED The driver specified by This does not support
|
||||
the language specified by Language.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4ComponentNameGetDriverName (
|
||||
IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **DriverName
|
||||
)
|
||||
{
|
||||
return LookupUnicodeString2 (
|
||||
Language,
|
||||
This->SupportedLanguages,
|
||||
mMtftp4DriverNameTable,
|
||||
DriverName,
|
||||
(BOOLEAN)(This == &gMtftp4ComponentName)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
Update the component name for the Mtftp4 child handle.
|
||||
|
||||
@param Mtftp4[in] A pointer to the EFI_MTFTP4_PROTOCOL.
|
||||
|
||||
|
||||
@retval EFI_SUCCESS Update the ControllerNameTable of this instance successfully.
|
||||
@retval EFI_INVALID_PARAMETER The input parameter is invalid.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
UpdateName (
|
||||
IN EFI_MTFTP4_PROTOCOL *Mtftp4
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
CHAR16 HandleName[80];
|
||||
EFI_MTFTP4_MODE_DATA ModeData;
|
||||
|
||||
if (Mtftp4 == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// Format the child name into the string buffer as:
|
||||
// MTFTPv4 (ServerIp=192.168.1.10, ServerPort=69)
|
||||
//
|
||||
Status = Mtftp4->GetModeData (Mtftp4, &ModeData);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
UnicodeSPrint (HandleName, sizeof (HandleName),
|
||||
L"MTFTPv4 (ServerIp=%d.%d.%d.%d, ServerPort=%d)",
|
||||
ModeData.ConfigData.ServerIp.Addr[0],
|
||||
ModeData.ConfigData.ServerIp.Addr[1],
|
||||
ModeData.ConfigData.ServerIp.Addr[2],
|
||||
ModeData.ConfigData.ServerIp.Addr[3],
|
||||
ModeData.ConfigData.InitialServerPort
|
||||
);
|
||||
|
||||
if (gMtftp4ControllerNameTable != NULL) {
|
||||
FreeUnicodeStringTable (gMtftp4ControllerNameTable);
|
||||
gMtftp4ControllerNameTable = NULL;
|
||||
}
|
||||
|
||||
Status = AddUnicodeString2 (
|
||||
"eng",
|
||||
gMtftp4ComponentName.SupportedLanguages,
|
||||
&gMtftp4ControllerNameTable,
|
||||
HandleName,
|
||||
TRUE
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
return AddUnicodeString2 (
|
||||
"en",
|
||||
gMtftp4ComponentName2.SupportedLanguages,
|
||||
&gMtftp4ControllerNameTable,
|
||||
HandleName,
|
||||
FALSE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
Retrieves a Unicode string that is the user readable name of the controller
|
||||
that is being managed by a driver.
|
||||
|
||||
This function retrieves the user readable name of the controller specified by
|
||||
ControllerHandle and ChildHandle in the form of a Unicode string. If the
|
||||
driver specified by This has a user readable name in the language specified by
|
||||
Language, then a pointer to the controller name is returned in ControllerName,
|
||||
and EFI_SUCCESS is returned. If the driver specified by This is not currently
|
||||
managing the controller specified by ControllerHandle and ChildHandle,
|
||||
then EFI_UNSUPPORTED is returned. If the driver specified by This does not
|
||||
support the language specified by Language, then EFI_UNSUPPORTED is returned.
|
||||
|
||||
@param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
|
||||
EFI_COMPONENT_NAME_PROTOCOL instance.
|
||||
|
||||
@param[in] ControllerHandle The handle of a controller that the driver
|
||||
specified by This is managing. This handle
|
||||
specifies the controller whose name is to be
|
||||
returned.
|
||||
|
||||
@param[in] ChildHandle The handle of the child controller to retrieve
|
||||
the name of. This is an optional parameter that
|
||||
may be NULL. It will be NULL for device
|
||||
drivers. It will also be NULL for a bus drivers
|
||||
that wish to retrieve the name of the bus
|
||||
controller. It will not be NULL for a bus
|
||||
driver that wishes to retrieve the name of a
|
||||
child controller.
|
||||
|
||||
@param[in] Language A pointer to a Null-terminated ASCII string
|
||||
array indicating the language. This is the
|
||||
language of the driver name that the caller is
|
||||
requesting, and it must match one of the
|
||||
languages specified in SupportedLanguages. The
|
||||
number of languages supported by a driver is up
|
||||
to the driver writer. Language is specified in
|
||||
RFC 4646 or ISO 639-2 language code format.
|
||||
|
||||
@param[out] ControllerName A pointer to the Unicode string to return.
|
||||
This Unicode string is the name of the
|
||||
controller specified by ControllerHandle and
|
||||
ChildHandle in the language specified by
|
||||
Language from the point of view of the driver
|
||||
specified by This.
|
||||
|
||||
@retval EFI_SUCCESS The Unicode string for the user readable name in
|
||||
the language specified by Language for the
|
||||
driver specified by This was returned in
|
||||
DriverName.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
|
||||
EFI_HANDLE.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER Language is NULL.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER ControllerName is NULL.
|
||||
|
||||
@retval EFI_UNSUPPORTED The driver specified by This is not currently
|
||||
managing the controller specified by
|
||||
ControllerHandle and ChildHandle.
|
||||
|
||||
@retval EFI_UNSUPPORTED The driver specified by This does not support
|
||||
the language specified by Language.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4ComponentNameGetControllerName (
|
||||
IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_HANDLE ChildHandle OPTIONAL,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **ControllerName
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_MTFTP4_PROTOCOL *Mtftp4;
|
||||
|
||||
//
|
||||
// Only provide names for child handles.
|
||||
//
|
||||
if (ChildHandle == NULL) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
//
|
||||
// Make sure this driver produced ChildHandle
|
||||
//
|
||||
Status = EfiTestChildHandle (
|
||||
ControllerHandle,
|
||||
ChildHandle,
|
||||
&gEfiUdp4ProtocolGuid
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Retrieve an instance of a produced protocol from ChildHandle
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
ChildHandle,
|
||||
&gEfiMtftp4ProtocolGuid,
|
||||
(VOID **)&Mtftp4,
|
||||
NULL,
|
||||
NULL,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Update the component name for this child handle.
|
||||
//
|
||||
Status = UpdateName (Mtftp4);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
return LookupUnicodeString2 (
|
||||
Language,
|
||||
This->SupportedLanguages,
|
||||
gMtftp4ControllerNameTable,
|
||||
ControllerName,
|
||||
(BOOLEAN)(This == &gMtftp4ComponentName)
|
||||
);
|
||||
}
|
739
NetworkPkg/Mtftp4Dxe/Mtftp4Driver.c
Normal file
739
NetworkPkg/Mtftp4Dxe/Mtftp4Driver.c
Normal file
@@ -0,0 +1,739 @@
|
||||
/** @file
|
||||
Implementation of Mtftp drivers.
|
||||
|
||||
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#include "Mtftp4Impl.h"
|
||||
|
||||
EFI_DRIVER_BINDING_PROTOCOL gMtftp4DriverBinding = {
|
||||
Mtftp4DriverBindingSupported,
|
||||
Mtftp4DriverBindingStart,
|
||||
Mtftp4DriverBindingStop,
|
||||
0xa,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
EFI_SERVICE_BINDING_PROTOCOL gMtftp4ServiceBindingTemplete = {
|
||||
Mtftp4ServiceBindingCreateChild,
|
||||
Mtftp4ServiceBindingDestroyChild
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
The driver entry point which installs multiple protocols to the ImageHandle.
|
||||
|
||||
@param ImageHandle The MTFTP's image handle.
|
||||
@param SystemTable The system table.
|
||||
|
||||
@retval EFI_SUCCESS The handles are successfully installed on the image.
|
||||
@retval others some EFI_ERROR occured.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4DriverEntryPoint (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
{
|
||||
return EfiLibInstallDriverBindingComponentName2 (
|
||||
ImageHandle,
|
||||
SystemTable,
|
||||
&gMtftp4DriverBinding,
|
||||
ImageHandle,
|
||||
&gMtftp4ComponentName,
|
||||
&gMtftp4ComponentName2
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Test whether MTFTP driver support this controller.
|
||||
|
||||
@param This The MTFTP driver binding instance
|
||||
@param Controller The controller to test
|
||||
@param RemainingDevicePath The remaining device path
|
||||
|
||||
@retval EFI_SUCCESS The controller has UDP service binding protocol
|
||||
installed, MTFTP can support it.
|
||||
@retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
|
||||
RemainingDevicePath is already being managed by
|
||||
the driver specified by This.
|
||||
@retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
|
||||
RemainingDevicePath is already being managed by a
|
||||
different driver or an application that requires
|
||||
exclusive access.
|
||||
@retval EFI_UNSUPPORTED The device specified by ControllerHandle and
|
||||
RemainingDevicePath is not supported by the driver
|
||||
specified by This.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4DriverBindingSupported (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE Controller,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
Controller,
|
||||
&gEfiUdp4ServiceBindingProtocolGuid,
|
||||
NULL,
|
||||
This->DriverBindingHandle,
|
||||
Controller,
|
||||
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
|
||||
);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Config a NULL UDP that is used to keep the connection between UDP and MTFTP.
|
||||
|
||||
Just leave the Udp child unconfigured. When UDP is unloaded,
|
||||
MTFTP will be informed with DriverBinding Stop.
|
||||
|
||||
@param UdpIo The UDP_IO to configure
|
||||
@param Context The opaque parameter to the callback
|
||||
|
||||
@retval EFI_SUCCESS It always return EFI_SUCCESS directly.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4ConfigNullUdp (
|
||||
IN UDP_IO *UdpIo,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Create then initialize a MTFTP service binding instance.
|
||||
|
||||
@param Controller The controller to install the MTFTP service
|
||||
binding on
|
||||
@param Image The driver binding image of the MTFTP driver
|
||||
@param Service The variable to receive the created service
|
||||
binding instance.
|
||||
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource to create the instance
|
||||
@retval EFI_DEVICE_ERROR Failed to create a NULL UDP port to keep
|
||||
connection with UDP.
|
||||
@retval EFI_SUCCESS The service instance is created for the
|
||||
controller.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4CreateService (
|
||||
IN EFI_HANDLE Controller,
|
||||
IN EFI_HANDLE Image,
|
||||
OUT MTFTP4_SERVICE **Service
|
||||
)
|
||||
{
|
||||
MTFTP4_SERVICE *MtftpSb;
|
||||
EFI_STATUS Status;
|
||||
|
||||
*Service = NULL;
|
||||
MtftpSb = AllocatePool (sizeof (MTFTP4_SERVICE));
|
||||
|
||||
if (MtftpSb == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
MtftpSb->Signature = MTFTP4_SERVICE_SIGNATURE;
|
||||
MtftpSb->ServiceBinding = gMtftp4ServiceBindingTemplete;
|
||||
MtftpSb->ChildrenNum = 0;
|
||||
InitializeListHead (&MtftpSb->Children);
|
||||
|
||||
MtftpSb->Timer = NULL;
|
||||
MtftpSb->TimerNotifyLevel = NULL;
|
||||
MtftpSb->TimerToGetMap = NULL;
|
||||
MtftpSb->Controller = Controller;
|
||||
MtftpSb->Image = Image;
|
||||
MtftpSb->ConnectUdp = NULL;
|
||||
|
||||
//
|
||||
// Create the timer and a udp to be notified when UDP is uninstalled
|
||||
//
|
||||
Status = gBS->CreateEvent (
|
||||
EVT_NOTIFY_SIGNAL | EVT_TIMER,
|
||||
TPL_CALLBACK,
|
||||
Mtftp4OnTimerTick,
|
||||
MtftpSb,
|
||||
&MtftpSb->Timer
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (MtftpSb);
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = gBS->CreateEvent (
|
||||
EVT_NOTIFY_SIGNAL | EVT_TIMER,
|
||||
TPL_NOTIFY,
|
||||
Mtftp4OnTimerTickNotifyLevel,
|
||||
MtftpSb,
|
||||
&MtftpSb->TimerNotifyLevel
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
gBS->CloseEvent (MtftpSb->Timer);
|
||||
FreePool (MtftpSb);
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Create the timer used to time out the procedure which is used to
|
||||
// get the default IP address.
|
||||
//
|
||||
Status = gBS->CreateEvent (
|
||||
EVT_TIMER,
|
||||
TPL_CALLBACK,
|
||||
NULL,
|
||||
NULL,
|
||||
&MtftpSb->TimerToGetMap
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
gBS->CloseEvent (MtftpSb->TimerNotifyLevel);
|
||||
gBS->CloseEvent (MtftpSb->Timer);
|
||||
FreePool (MtftpSb);
|
||||
return Status;
|
||||
}
|
||||
|
||||
MtftpSb->ConnectUdp = UdpIoCreateIo (
|
||||
Controller,
|
||||
Image,
|
||||
Mtftp4ConfigNullUdp,
|
||||
UDP_IO_UDP4_VERSION,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (MtftpSb->ConnectUdp == NULL) {
|
||||
gBS->CloseEvent (MtftpSb->TimerToGetMap);
|
||||
gBS->CloseEvent (MtftpSb->TimerNotifyLevel);
|
||||
gBS->CloseEvent (MtftpSb->Timer);
|
||||
FreePool (MtftpSb);
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
*Service = MtftpSb;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Release all the resource used the MTFTP service binding instance.
|
||||
|
||||
@param MtftpSb The MTFTP service binding instance.
|
||||
|
||||
**/
|
||||
VOID
|
||||
Mtftp4CleanService (
|
||||
IN MTFTP4_SERVICE *MtftpSb
|
||||
)
|
||||
{
|
||||
UdpIoFreeIo (MtftpSb->ConnectUdp);
|
||||
gBS->CloseEvent (MtftpSb->TimerToGetMap);
|
||||
gBS->CloseEvent (MtftpSb->TimerNotifyLevel);
|
||||
gBS->CloseEvent (MtftpSb->Timer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Start the MTFTP driver on this controller.
|
||||
|
||||
MTFTP driver will install a MTFTP SERVICE BINDING protocol on the supported
|
||||
controller, which can be used to create/destroy MTFTP children.
|
||||
|
||||
@param This The MTFTP driver binding protocol.
|
||||
@param Controller The controller to manage.
|
||||
@param RemainingDevicePath Remaining device path.
|
||||
|
||||
@retval EFI_ALREADY_STARTED The MTFTP service binding protocol has been
|
||||
started on the controller.
|
||||
@retval EFI_SUCCESS The MTFTP service binding is installed on the
|
||||
controller.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4DriverBindingStart (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE Controller,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
||||
)
|
||||
{
|
||||
MTFTP4_SERVICE *MtftpSb;
|
||||
EFI_STATUS Status;
|
||||
|
||||
//
|
||||
// Directly return if driver is already running.
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
Controller,
|
||||
&gEfiMtftp4ServiceBindingProtocolGuid,
|
||||
NULL,
|
||||
This->DriverBindingHandle,
|
||||
Controller,
|
||||
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
|
||||
);
|
||||
|
||||
if (Status == EFI_SUCCESS) {
|
||||
return EFI_ALREADY_STARTED;
|
||||
}
|
||||
|
||||
Status = Mtftp4CreateService (Controller, This->DriverBindingHandle, &MtftpSb);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
ASSERT (MtftpSb != NULL);
|
||||
|
||||
Status = gBS->SetTimer (MtftpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
Status = gBS->SetTimer (MtftpSb->TimerNotifyLevel, TimerPeriodic, TICKS_PER_SECOND);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Install the Mtftp4ServiceBinding Protocol onto Controller
|
||||
//
|
||||
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||
&Controller,
|
||||
&gEfiMtftp4ServiceBindingProtocolGuid,
|
||||
&MtftpSb->ServiceBinding,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
|
||||
ON_ERROR:
|
||||
Mtftp4CleanService (MtftpSb);
|
||||
FreePool (MtftpSb);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Callback function which provided by user to remove one node in NetDestroyLinkList process.
|
||||
|
||||
@param[in] Entry The entry to be removed.
|
||||
@param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
|
||||
|
||||
@retval EFI_SUCCESS The entry has been removed successfully.
|
||||
@retval Others Fail to remove the entry.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4DestroyChildEntryInHandleBuffer (
|
||||
IN LIST_ENTRY *Entry,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
MTFTP4_PROTOCOL *Instance;
|
||||
EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
|
||||
UINTN NumberOfChildren;
|
||||
EFI_HANDLE *ChildHandleBuffer;
|
||||
|
||||
if (Entry == NULL || Context == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Instance = NET_LIST_USER_STRUCT_S (Entry, MTFTP4_PROTOCOL, Link, MTFTP4_PROTOCOL_SIGNATURE);
|
||||
ServiceBinding = ((MTFTP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
|
||||
NumberOfChildren = ((MTFTP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
|
||||
ChildHandleBuffer = ((MTFTP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
|
||||
|
||||
if (!NetIsInHandleBuffer (Instance->Handle, NumberOfChildren, ChildHandleBuffer)) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
return ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);
|
||||
}
|
||||
|
||||
/**
|
||||
Stop the MTFTP driver on controller. The controller is a UDP
|
||||
child handle.
|
||||
|
||||
@param This The MTFTP driver binding protocol
|
||||
@param Controller The controller to stop
|
||||
@param NumberOfChildren The number of children
|
||||
@param ChildHandleBuffer The array of the child handle.
|
||||
|
||||
@retval EFI_SUCCESS The driver is stopped on the controller.
|
||||
@retval EFI_DEVICE_ERROR Failed to stop the driver on the controller.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4DriverBindingStop (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE Controller,
|
||||
IN UINTN NumberOfChildren,
|
||||
IN EFI_HANDLE *ChildHandleBuffer
|
||||
)
|
||||
{
|
||||
EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
|
||||
MTFTP4_SERVICE *MtftpSb;
|
||||
EFI_HANDLE NicHandle;
|
||||
EFI_STATUS Status;
|
||||
LIST_ENTRY *List;
|
||||
MTFTP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context;
|
||||
|
||||
//
|
||||
// MTFTP driver opens UDP child, So, Controller is a UDP
|
||||
// child handle. Locate the Nic handle first. Then get the
|
||||
// MTFTP private data back.
|
||||
//
|
||||
NicHandle = NetLibGetNicHandle (Controller, &gEfiUdp4ProtocolGuid);
|
||||
|
||||
if (NicHandle == NULL) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
NicHandle,
|
||||
&gEfiMtftp4ServiceBindingProtocolGuid,
|
||||
(VOID **) &ServiceBinding,
|
||||
This->DriverBindingHandle,
|
||||
NicHandle,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
MtftpSb = MTFTP4_SERVICE_FROM_THIS (ServiceBinding);
|
||||
|
||||
if (!IsListEmpty (&MtftpSb->Children)) {
|
||||
//
|
||||
// Destroy the Mtftp4 child instance in ChildHandleBuffer.
|
||||
//
|
||||
List = &MtftpSb->Children;
|
||||
Context.ServiceBinding = ServiceBinding;
|
||||
Context.NumberOfChildren = NumberOfChildren;
|
||||
Context.ChildHandleBuffer = ChildHandleBuffer;
|
||||
Status = NetDestroyLinkList (
|
||||
List,
|
||||
Mtftp4DestroyChildEntryInHandleBuffer,
|
||||
&Context,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
if (NumberOfChildren == 0 && IsListEmpty (&MtftpSb->Children)) {
|
||||
gBS->UninstallProtocolInterface (
|
||||
NicHandle,
|
||||
&gEfiMtftp4ServiceBindingProtocolGuid,
|
||||
ServiceBinding
|
||||
);
|
||||
|
||||
Mtftp4CleanService (MtftpSb);
|
||||
if (gMtftp4ControllerNameTable != NULL) {
|
||||
FreeUnicodeStringTable (gMtftp4ControllerNameTable);
|
||||
gMtftp4ControllerNameTable = NULL;
|
||||
}
|
||||
FreePool (MtftpSb);
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Initialize a MTFTP protocol instance which is the child of MtftpSb.
|
||||
|
||||
@param MtftpSb The MTFTP service binding protocol.
|
||||
@param Instance The MTFTP instance to initialize.
|
||||
|
||||
**/
|
||||
VOID
|
||||
Mtftp4InitProtocol (
|
||||
IN MTFTP4_SERVICE *MtftpSb,
|
||||
OUT MTFTP4_PROTOCOL *Instance
|
||||
)
|
||||
{
|
||||
ZeroMem (Instance, sizeof (MTFTP4_PROTOCOL));
|
||||
|
||||
Instance->Signature = MTFTP4_PROTOCOL_SIGNATURE;
|
||||
InitializeListHead (&Instance->Link);
|
||||
CopyMem (&Instance->Mtftp4, &gMtftp4ProtocolTemplate, sizeof (Instance->Mtftp4));
|
||||
Instance->State = MTFTP4_STATE_UNCONFIGED;
|
||||
Instance->Service = MtftpSb;
|
||||
|
||||
InitializeListHead (&Instance->Blocks);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Create a MTFTP child for the service binding instance, then
|
||||
install the MTFTP protocol to the ChildHandle.
|
||||
|
||||
@param This The MTFTP service binding instance.
|
||||
@param ChildHandle The Child handle to install the MTFTP protocol.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The parameter is invalid.
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the new child.
|
||||
@retval EFI_SUCCESS The child is successfully create.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4ServiceBindingCreateChild (
|
||||
IN EFI_SERVICE_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE *ChildHandle
|
||||
)
|
||||
{
|
||||
MTFTP4_SERVICE *MtftpSb;
|
||||
MTFTP4_PROTOCOL *Instance;
|
||||
EFI_STATUS Status;
|
||||
EFI_TPL OldTpl;
|
||||
VOID *Udp4;
|
||||
|
||||
if ((This == NULL) || (ChildHandle == NULL)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Instance = AllocatePool (sizeof (*Instance));
|
||||
|
||||
if (Instance == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);
|
||||
|
||||
Mtftp4InitProtocol (MtftpSb, Instance);
|
||||
|
||||
Instance->UnicastPort = UdpIoCreateIo (
|
||||
MtftpSb->Controller,
|
||||
MtftpSb->Image,
|
||||
Mtftp4ConfigNullUdp,
|
||||
UDP_IO_UDP4_VERSION,
|
||||
Instance
|
||||
);
|
||||
|
||||
if (Instance->UnicastPort == NULL) {
|
||||
FreePool (Instance);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
//
|
||||
// Install the MTFTP protocol onto ChildHandle
|
||||
//
|
||||
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||
ChildHandle,
|
||||
&gEfiMtftp4ProtocolGuid,
|
||||
&Instance->Mtftp4,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
UdpIoFreeIo (Instance->UnicastPort);
|
||||
FreePool (Instance);
|
||||
return Status;
|
||||
}
|
||||
|
||||
Instance->Handle = *ChildHandle;
|
||||
|
||||
//
|
||||
// Open the Udp4 protocol BY_CHILD.
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
MtftpSb->ConnectUdp->UdpHandle,
|
||||
&gEfiUdp4ProtocolGuid,
|
||||
(VOID **) &Udp4,
|
||||
gMtftp4DriverBinding.DriverBindingHandle,
|
||||
Instance->Handle,
|
||||
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Open the Udp4 protocol by child.
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
Instance->UnicastPort->UdpHandle,
|
||||
&gEfiUdp4ProtocolGuid,
|
||||
(VOID **) &Udp4,
|
||||
gMtftp4DriverBinding.DriverBindingHandle,
|
||||
Instance->Handle,
|
||||
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
//
|
||||
// Close the Udp4 protocol.
|
||||
//
|
||||
gBS->CloseProtocol (
|
||||
MtftpSb->ConnectUdp->UdpHandle,
|
||||
&gEfiUdp4ProtocolGuid,
|
||||
gMtftp4DriverBinding.DriverBindingHandle,
|
||||
ChildHandle
|
||||
);
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Add it to the parent's child list.
|
||||
//
|
||||
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
||||
|
||||
InsertTailList (&MtftpSb->Children, &Instance->Link);
|
||||
MtftpSb->ChildrenNum++;
|
||||
|
||||
gBS->RestoreTPL (OldTpl);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
|
||||
ON_ERROR:
|
||||
if (Instance->Handle != NULL) {
|
||||
gBS->UninstallMultipleProtocolInterfaces (
|
||||
Instance->Handle,
|
||||
&gEfiMtftp4ProtocolGuid,
|
||||
&Instance->Mtftp4,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
UdpIoFreeIo (Instance->UnicastPort);
|
||||
FreePool (Instance);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Destroy one of the service binding's child.
|
||||
|
||||
@param This The service binding instance
|
||||
@param ChildHandle The child handle to destroy
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The parameter is invaid.
|
||||
@retval EFI_UNSUPPORTED The child may have already been destroyed.
|
||||
@retval EFI_SUCCESS The child is destroyed and removed from the
|
||||
parent's child list.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4ServiceBindingDestroyChild (
|
||||
IN EFI_SERVICE_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE ChildHandle
|
||||
)
|
||||
{
|
||||
MTFTP4_SERVICE *MtftpSb;
|
||||
MTFTP4_PROTOCOL *Instance;
|
||||
EFI_MTFTP4_PROTOCOL *Mtftp4;
|
||||
EFI_STATUS Status;
|
||||
EFI_TPL OldTpl;
|
||||
|
||||
if ((This == NULL) || (ChildHandle == NULL)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// Retrieve the private context data structures
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
ChildHandle,
|
||||
&gEfiMtftp4ProtocolGuid,
|
||||
(VOID **) &Mtftp4,
|
||||
gMtftp4DriverBinding.DriverBindingHandle,
|
||||
ChildHandle,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
Instance = MTFTP4_PROTOCOL_FROM_THIS (Mtftp4);
|
||||
MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);
|
||||
|
||||
if (Instance->Service != MtftpSb) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (Instance->InDestroy) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
Instance->InDestroy = TRUE;
|
||||
|
||||
//
|
||||
// Close the Udp4 protocol.
|
||||
//
|
||||
gBS->CloseProtocol (
|
||||
MtftpSb->ConnectUdp->UdpHandle,
|
||||
&gEfiUdp4ProtocolGuid,
|
||||
gMtftp4DriverBinding.DriverBindingHandle,
|
||||
ChildHandle
|
||||
);
|
||||
|
||||
gBS->CloseProtocol (
|
||||
Instance->UnicastPort->UdpHandle,
|
||||
&gEfiUdp4ProtocolGuid,
|
||||
gMtftp4DriverBinding.DriverBindingHandle,
|
||||
ChildHandle
|
||||
);
|
||||
|
||||
if (Instance->McastUdpPort != NULL) {
|
||||
gBS->CloseProtocol (
|
||||
Instance->McastUdpPort->UdpHandle,
|
||||
&gEfiUdp4ProtocolGuid,
|
||||
gMtftp4DriverBinding.DriverBindingHandle,
|
||||
ChildHandle
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Uninstall the MTFTP4 protocol first to enable a top down destruction.
|
||||
//
|
||||
Status = gBS->UninstallProtocolInterface (
|
||||
ChildHandle,
|
||||
&gEfiMtftp4ProtocolGuid,
|
||||
Mtftp4
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
Instance->InDestroy = FALSE;
|
||||
return Status;
|
||||
}
|
||||
|
||||
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
||||
|
||||
Mtftp4CleanOperation (Instance, EFI_DEVICE_ERROR);
|
||||
UdpIoFreeIo (Instance->UnicastPort);
|
||||
|
||||
RemoveEntryList (&Instance->Link);
|
||||
MtftpSb->ChildrenNum--;
|
||||
|
||||
gBS->RestoreTPL (OldTpl);
|
||||
|
||||
FreePool (Instance);
|
||||
return EFI_SUCCESS;
|
||||
}
|
131
NetworkPkg/Mtftp4Dxe/Mtftp4Driver.h
Normal file
131
NetworkPkg/Mtftp4Dxe/Mtftp4Driver.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/** @file
|
||||
Mtftp drivers function header.
|
||||
|
||||
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#ifndef __EFI_MTFTP4_DRIVER_H__
|
||||
#define __EFI_MTFTP4_DRIVER_H__
|
||||
|
||||
#include <Uefi.h>
|
||||
|
||||
#include <Protocol/ServiceBinding.h>
|
||||
|
||||
#include <Library/NetLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/UefiDriverEntryPoint.h>
|
||||
|
||||
extern EFI_COMPONENT_NAME_PROTOCOL gMtftp4ComponentName;
|
||||
extern EFI_COMPONENT_NAME2_PROTOCOL gMtftp4ComponentName2;
|
||||
extern EFI_DRIVER_BINDING_PROTOCOL gMtftp4DriverBinding;
|
||||
extern EFI_UNICODE_STRING_TABLE *gMtftp4ControllerNameTable;
|
||||
|
||||
/**
|
||||
Test whether MTFTP driver support this controller.
|
||||
|
||||
@param This The MTFTP driver binding instance
|
||||
@param Controller The controller to test
|
||||
@param RemainingDevicePath The remaining device path
|
||||
|
||||
@retval EFI_SUCCESS The controller has UDP service binding protocol
|
||||
installed, MTFTP can support it.
|
||||
@retval Others MTFTP can't support the controller.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4DriverBindingSupported (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE Controller,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
||||
);
|
||||
|
||||
/**
|
||||
Start the MTFTP driver on this controller.
|
||||
|
||||
MTFTP driver will install a MTFTP SERVICE BINDING protocol on the supported
|
||||
controller, which can be used to create/destroy MTFTP children.
|
||||
|
||||
@param This The MTFTP driver binding protocol.
|
||||
@param Controller The controller to manage.
|
||||
@param RemainingDevicePath Remaining device path.
|
||||
|
||||
@retval EFI_ALREADY_STARTED The MTFTP service binding protocol has been
|
||||
started on the controller.
|
||||
@retval EFI_SUCCESS The MTFTP service binding is installed on the
|
||||
controller.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4DriverBindingStart (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE Controller,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
||||
);
|
||||
|
||||
/**
|
||||
Stop the MTFTP driver on controller. The controller is a UDP
|
||||
child handle.
|
||||
|
||||
@param This The MTFTP driver binding protocol
|
||||
@param Controller The controller to stop
|
||||
@param NumberOfChildren The number of children
|
||||
@param ChildHandleBuffer The array of the child handle.
|
||||
|
||||
@retval EFI_SUCCESS The driver is stopped on the controller.
|
||||
@retval EFI_DEVICE_ERROR Failed to stop the driver on the controller.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4DriverBindingStop (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE Controller,
|
||||
IN UINTN NumberOfChildren,
|
||||
IN EFI_HANDLE *ChildHandleBuffer
|
||||
);
|
||||
|
||||
/**
|
||||
Create a MTFTP child for the service binding instance, then
|
||||
install the MTFTP protocol to the ChildHandle.
|
||||
|
||||
@param This The MTFTP service binding instance.
|
||||
@param ChildHandle The Child handle to install the MTFTP protocol.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The parameter is invalid.
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the new child.
|
||||
@retval EFI_SUCCESS The child is successfully create.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4ServiceBindingCreateChild (
|
||||
IN EFI_SERVICE_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE *ChildHandle
|
||||
);
|
||||
|
||||
/**
|
||||
Destroy one of the service binding's child.
|
||||
|
||||
@param This The service binding instance
|
||||
@param ChildHandle The child handle to destroy
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The parameter is invaid.
|
||||
@retval EFI_UNSUPPORTED The child may have already been destroyed.
|
||||
@retval EFI_SUCCESS The child is destroyed and removed from the
|
||||
parent's child list.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4ServiceBindingDestroyChild (
|
||||
IN EFI_SERVICE_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE ChildHandle
|
||||
);
|
||||
|
||||
|
||||
|
||||
#endif
|
69
NetworkPkg/Mtftp4Dxe/Mtftp4Dxe.inf
Normal file
69
NetworkPkg/Mtftp4Dxe/Mtftp4Dxe.inf
Normal file
@@ -0,0 +1,69 @@
|
||||
## @file
|
||||
# This module produces EFI MTFTPv4 Protocol and EFI MTFTPv4 Service Binding Protocol.
|
||||
#
|
||||
# This module produces EFI MTFTPv4 Protocol upon EFI UDPv4 Protocol, to provide
|
||||
# basic services for client-side unicast and/or multicase TFTP operations.
|
||||
#
|
||||
# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = Mtftp4Dxe
|
||||
MODULE_UNI_FILE = Mtftp4Dxe.uni
|
||||
FILE_GUID = DC3641B8-2FA8-4ed3-BC1F-F9962A03454B
|
||||
MODULE_TYPE = UEFI_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
ENTRY_POINT = Mtftp4DriverEntryPoint
|
||||
UNLOAD_IMAGE = NetLibDefaultUnload
|
||||
#
|
||||
# The following information is for reference only and not required by the build tools.
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64 EBC
|
||||
#
|
||||
# DRIVER_BINDING = gMtftp4DriverBinding
|
||||
# COMPONENT_NAME = gMtftp4ComponentName
|
||||
# COMPONENT_NAME2 = gMtftp4ComponentName2
|
||||
#
|
||||
|
||||
[Sources]
|
||||
Mtftp4Option.c
|
||||
Mtftp4Rrq.c
|
||||
Mtftp4Impl.h
|
||||
ComponentName.c
|
||||
Mtftp4Support.c
|
||||
Mtftp4Impl.c
|
||||
Mtftp4Option.h
|
||||
Mtftp4Support.h
|
||||
Mtftp4Driver.h
|
||||
Mtftp4Driver.c
|
||||
Mtftp4Wrq.c
|
||||
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
|
||||
|
||||
[LibraryClasses]
|
||||
UefiLib
|
||||
UefiBootServicesTableLib
|
||||
UefiDriverEntryPoint
|
||||
DebugLib
|
||||
NetLib
|
||||
UdpIoLib
|
||||
MemoryAllocationLib
|
||||
BaseMemoryLib
|
||||
|
||||
|
||||
[Protocols]
|
||||
gEfiMtftp4ServiceBindingProtocolGuid ## BY_START
|
||||
gEfiUdp4ServiceBindingProtocolGuid ## TO_START
|
||||
gEfiMtftp4ProtocolGuid ## BY_START
|
||||
gEfiUdp4ProtocolGuid ## TO_START
|
||||
|
||||
[UserExtensions.TianoCore."ExtraFiles"]
|
||||
Mtftp4DxeExtra.uni
|
17
NetworkPkg/Mtftp4Dxe/Mtftp4Dxe.uni
Normal file
17
NetworkPkg/Mtftp4Dxe/Mtftp4Dxe.uni
Normal file
@@ -0,0 +1,17 @@
|
||||
// /** @file
|
||||
// This module produces EFI MTFTPv4 Protocol and EFI MTFTPv4 Service Binding Protocol.
|
||||
//
|
||||
// This module produces EFI MTFTPv4 Protocol upon EFI UDPv4 Protocol, to provide
|
||||
// basic services for client-side unicast and/or multicase TFTP operations.
|
||||
//
|
||||
// Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
//
|
||||
// **/
|
||||
|
||||
|
||||
#string STR_MODULE_ABSTRACT #language en-US "Produces EFI MTFTPv4 Protocol and EFI MTFTPv4 Service Binding Protocol"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "This module produces EFI MTFTPv4 Protocol upon EFI UDPv4 Protocol, to provide basic services for client-side unicast or multicase TFTP operations or both."
|
||||
|
14
NetworkPkg/Mtftp4Dxe/Mtftp4DxeExtra.uni
Normal file
14
NetworkPkg/Mtftp4Dxe/Mtftp4DxeExtra.uni
Normal file
@@ -0,0 +1,14 @@
|
||||
// /** @file
|
||||
// Mtftp4Dxe Localized Strings and Content
|
||||
//
|
||||
// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
//
|
||||
// **/
|
||||
|
||||
#string STR_PROPERTIES_MODULE_NAME
|
||||
#language en-US
|
||||
"MTFTP v4 DXE Driver"
|
||||
|
||||
|
1113
NetworkPkg/Mtftp4Dxe/Mtftp4Impl.c
Normal file
1113
NetworkPkg/Mtftp4Dxe/Mtftp4Impl.c
Normal file
File diff suppressed because it is too large
Load Diff
226
NetworkPkg/Mtftp4Dxe/Mtftp4Impl.h
Normal file
226
NetworkPkg/Mtftp4Dxe/Mtftp4Impl.h
Normal file
@@ -0,0 +1,226 @@
|
||||
/** @file
|
||||
|
||||
Mtftp4 Implementation.
|
||||
|
||||
Mtftp4 Implementation, it supports the following RFCs:
|
||||
RFC1350 - THE TFTP PROTOCOL (REVISION 2)
|
||||
RFC2090 - TFTP Multicast Option
|
||||
RFC2347 - TFTP Option Extension
|
||||
RFC2348 - TFTP Blocksize Option
|
||||
RFC2349 - TFTP Timeout Interval and Transfer Size Options
|
||||
RFC7440 - TFTP Windowsize Option
|
||||
|
||||
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
|
||||
#ifndef __EFI_MTFTP4_IMPL_H__
|
||||
#define __EFI_MTFTP4_IMPL_H__
|
||||
|
||||
#include <Uefi.h>
|
||||
|
||||
#include <Protocol/Udp4.h>
|
||||
#include <Protocol/Mtftp4.h>
|
||||
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UdpIoLib.h>
|
||||
#include <Library/PrintLib.h>
|
||||
|
||||
extern EFI_MTFTP4_PROTOCOL gMtftp4ProtocolTemplate;
|
||||
|
||||
typedef struct _MTFTP4_SERVICE MTFTP4_SERVICE;
|
||||
typedef struct _MTFTP4_PROTOCOL MTFTP4_PROTOCOL;
|
||||
|
||||
#include "Mtftp4Driver.h"
|
||||
#include "Mtftp4Option.h"
|
||||
#include "Mtftp4Support.h"
|
||||
|
||||
|
||||
///
|
||||
/// Some constant value of Mtftp service.
|
||||
///
|
||||
#define MTFTP4_SERVICE_SIGNATURE SIGNATURE_32 ('T', 'F', 'T', 'P')
|
||||
#define MTFTP4_PROTOCOL_SIGNATURE SIGNATURE_32 ('t', 'f', 't', 'p')
|
||||
|
||||
#define MTFTP4_DEFAULT_SERVER_PORT 69
|
||||
#define MTFTP4_DEFAULT_TIMEOUT 3
|
||||
#define MTFTP4_DEFAULT_RETRY 5
|
||||
#define MTFTP4_DEFAULT_BLKSIZE 512
|
||||
#define MTFTP4_DEFAULT_WINDOWSIZE 1
|
||||
#define MTFTP4_TIME_TO_GETMAP 5
|
||||
|
||||
#define MTFTP4_STATE_UNCONFIGED 0
|
||||
#define MTFTP4_STATE_CONFIGED 1
|
||||
#define MTFTP4_STATE_DESTROY 2
|
||||
|
||||
///
|
||||
/// Mtftp service block
|
||||
///
|
||||
struct _MTFTP4_SERVICE {
|
||||
UINT32 Signature;
|
||||
EFI_SERVICE_BINDING_PROTOCOL ServiceBinding;
|
||||
|
||||
UINT16 ChildrenNum;
|
||||
LIST_ENTRY Children;
|
||||
|
||||
EFI_EVENT Timer; ///< Ticking timer for all the MTFTP clients to handle the packet timeout case.
|
||||
EFI_EVENT TimerNotifyLevel; ///< Ticking timer for all the MTFTP clients to calculate the packet live time.
|
||||
EFI_EVENT TimerToGetMap;
|
||||
|
||||
EFI_HANDLE Controller;
|
||||
EFI_HANDLE Image;
|
||||
|
||||
//
|
||||
// This UDP child is used to keep the connection between the UDP
|
||||
// and MTFTP, so MTFTP will be notified when UDP is uninstalled.
|
||||
//
|
||||
UDP_IO *ConnectUdp;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
EFI_MTFTP4_PACKET **Packet;
|
||||
UINT32 *PacketLen;
|
||||
EFI_STATUS Status;
|
||||
} MTFTP4_GETINFO_STATE;
|
||||
|
||||
struct _MTFTP4_PROTOCOL {
|
||||
UINT32 Signature;
|
||||
LIST_ENTRY Link;
|
||||
EFI_MTFTP4_PROTOCOL Mtftp4;
|
||||
|
||||
INTN State;
|
||||
BOOLEAN InDestroy;
|
||||
|
||||
MTFTP4_SERVICE *Service;
|
||||
EFI_HANDLE Handle;
|
||||
|
||||
EFI_MTFTP4_CONFIG_DATA Config;
|
||||
|
||||
//
|
||||
// Operation parameters: token and requested options.
|
||||
//
|
||||
EFI_MTFTP4_TOKEN *Token;
|
||||
MTFTP4_OPTION RequestOption;
|
||||
UINT16 Operation;
|
||||
|
||||
//
|
||||
// Blocks is a list of MTFTP4_BLOCK_RANGE which contains
|
||||
// holes in the file
|
||||
//
|
||||
UINT16 BlkSize;
|
||||
UINT16 LastBlock;
|
||||
LIST_ENTRY Blocks;
|
||||
|
||||
UINT16 WindowSize;
|
||||
|
||||
//
|
||||
// Record the total received and saved block number.
|
||||
//
|
||||
UINT64 TotalBlock;
|
||||
|
||||
//
|
||||
// Record the acked block number.
|
||||
//
|
||||
UINT64 AckedBlock;
|
||||
|
||||
//
|
||||
// The server's communication end point: IP and two ports. one for
|
||||
// initial request, one for its selected port.
|
||||
//
|
||||
IP4_ADDR ServerIp;
|
||||
UINT16 ListeningPort;
|
||||
UINT16 ConnectedPort;
|
||||
IP4_ADDR Gateway;
|
||||
UDP_IO *UnicastPort;
|
||||
|
||||
//
|
||||
// Timeout and retransmit status
|
||||
//
|
||||
NET_BUF *LastPacket;
|
||||
UINT32 PacketToLive;
|
||||
BOOLEAN HasTimeout;
|
||||
UINT32 CurRetry;
|
||||
UINT32 MaxRetry;
|
||||
UINT32 Timeout;
|
||||
|
||||
//
|
||||
// Parameter used by RRQ's multicast download.
|
||||
//
|
||||
IP4_ADDR McastIp;
|
||||
UINT16 McastPort;
|
||||
BOOLEAN Master;
|
||||
UDP_IO *McastUdpPort;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
|
||||
UINTN NumberOfChildren;
|
||||
EFI_HANDLE *ChildHandleBuffer;
|
||||
} MTFTP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT;
|
||||
|
||||
/**
|
||||
Clean up the MTFTP session to get ready for new operation.
|
||||
|
||||
@param Instance The MTFTP session to clean up
|
||||
@param Result The result to return to the caller who initiated
|
||||
the operation.
|
||||
**/
|
||||
VOID
|
||||
Mtftp4CleanOperation (
|
||||
IN OUT MTFTP4_PROTOCOL *Instance,
|
||||
IN EFI_STATUS Result
|
||||
);
|
||||
|
||||
/**
|
||||
Start the MTFTP session for upload.
|
||||
|
||||
It will first init some states, then send the WRQ request packet,
|
||||
and start receiving the packet.
|
||||
|
||||
@param Instance The MTFTP session
|
||||
@param Operation Redundant parameter, which is always
|
||||
EFI_MTFTP4_OPCODE_WRQ here.
|
||||
|
||||
@retval EFI_SUCCESS The upload process has been started.
|
||||
@retval Others Failed to start the upload.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4WrqStart (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN UINT16 Operation
|
||||
);
|
||||
|
||||
/**
|
||||
Start the MTFTP session to download.
|
||||
|
||||
It will first initialize some of the internal states then build and send a RRQ
|
||||
reqeuest packet, at last, it will start receive for the downloading.
|
||||
|
||||
@param Instance The Mtftp session
|
||||
@param Operation The MTFTP opcode, it may be a EFI_MTFTP4_OPCODE_RRQ
|
||||
or EFI_MTFTP4_OPCODE_DIR.
|
||||
|
||||
@retval EFI_SUCCESS The mtftp download session is started.
|
||||
@retval Others Failed to start downloading.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4RrqStart (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN UINT16 Operation
|
||||
);
|
||||
|
||||
#define MTFTP4_SERVICE_FROM_THIS(a) \
|
||||
CR (a, MTFTP4_SERVICE, ServiceBinding, MTFTP4_SERVICE_SIGNATURE)
|
||||
|
||||
#define MTFTP4_PROTOCOL_FROM_THIS(a) \
|
||||
CR (a, MTFTP4_PROTOCOL, Mtftp4, MTFTP4_PROTOCOL_SIGNATURE)
|
||||
|
||||
#endif
|
549
NetworkPkg/Mtftp4Dxe/Mtftp4Option.c
Normal file
549
NetworkPkg/Mtftp4Dxe/Mtftp4Option.c
Normal file
@@ -0,0 +1,549 @@
|
||||
/** @file
|
||||
Routines to process MTFTP4 options.
|
||||
|
||||
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#include "Mtftp4Impl.h"
|
||||
|
||||
CHAR8 *mMtftp4SupportedOptions[MTFTP4_SUPPORTED_OPTIONS] = {
|
||||
"blksize",
|
||||
"windowsize",
|
||||
"timeout",
|
||||
"tsize",
|
||||
"multicast"
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Check whether two ascii strings are equel, ignore the case.
|
||||
|
||||
@param Str1 The first ascii string
|
||||
@param Str2 The second ascii string
|
||||
|
||||
@retval TRUE Two strings are equal when case is ignored.
|
||||
@retval FALSE Two string are not equal.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
NetStringEqualNoCase (
|
||||
IN UINT8 *Str1,
|
||||
IN UINT8 *Str2
|
||||
)
|
||||
{
|
||||
UINT8 Ch1;
|
||||
UINT8 Ch2;
|
||||
|
||||
ASSERT ((Str1 != NULL) && (Str2 != NULL));
|
||||
|
||||
for (; (*Str1 != '\0') && (*Str2 != '\0'); Str1++, Str2++) {
|
||||
Ch1 = *Str1;
|
||||
Ch2 = *Str2;
|
||||
|
||||
//
|
||||
// Convert them to lower case then compare two
|
||||
//
|
||||
if (('A' <= Ch1) && (Ch1 <= 'Z')) {
|
||||
Ch1 += 'a' - 'A';
|
||||
}
|
||||
|
||||
if (('A' <= Ch2) && (Ch2 <= 'Z')) {
|
||||
Ch2 += 'a' - 'A';
|
||||
}
|
||||
|
||||
if (Ch1 != Ch2) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return (BOOLEAN) (*Str1 == *Str2);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Convert a string to a UINT32 number.
|
||||
|
||||
@param Str The string to convert from
|
||||
|
||||
@return The number get from the string
|
||||
|
||||
**/
|
||||
UINT32
|
||||
NetStringToU32 (
|
||||
IN UINT8 *Str
|
||||
)
|
||||
{
|
||||
UINT32 Num;
|
||||
|
||||
ASSERT (Str != NULL);
|
||||
|
||||
Num = 0;
|
||||
|
||||
for (; NET_IS_DIGIT (*Str); Str++) {
|
||||
Num = Num * 10 + (*Str - '0');
|
||||
}
|
||||
|
||||
return Num;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Convert a string of the format "192.168.0.1" to an IP address.
|
||||
|
||||
@param Str The string representation of IP
|
||||
@param Ip The varible to get IP.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The IP string is invalid.
|
||||
@retval EFI_SUCCESS The IP is parsed into the Ip
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
NetStringToIp (
|
||||
IN UINT8 *Str,
|
||||
OUT IP4_ADDR *Ip
|
||||
)
|
||||
{
|
||||
UINT32 Byte;
|
||||
UINT32 Addr;
|
||||
UINTN Index;
|
||||
|
||||
*Ip = 0;
|
||||
Addr = 0;
|
||||
|
||||
for (Index = 0; Index < 4; Index++) {
|
||||
if (!NET_IS_DIGIT (*Str)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Byte = NetStringToU32 (Str);
|
||||
|
||||
if (Byte > 255) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Addr = (Addr << 8) | Byte;
|
||||
|
||||
//
|
||||
// Skip all the digitals and check whether the sepeator is the dot
|
||||
//
|
||||
while (NET_IS_DIGIT (*Str)) {
|
||||
Str++;
|
||||
}
|
||||
|
||||
if ((Index < 3) && (*Str != '.')) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Str++;
|
||||
}
|
||||
|
||||
*Ip = Addr;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Go through the packet to fill the Options array with the start
|
||||
addresses of each MTFTP option name/value pair.
|
||||
|
||||
@param Packet The packet to check
|
||||
@param PacketLen The packet's length
|
||||
@param Count The size of the Options on input. The actual
|
||||
options on output
|
||||
@param Options The option array to fill in
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The packet is mal-formated
|
||||
@retval EFI_BUFFER_TOO_SMALL The Options array is too small
|
||||
@retval EFI_SUCCESS The packet has been parsed into the Options array.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4FillOptions (
|
||||
IN EFI_MTFTP4_PACKET *Packet,
|
||||
IN UINT32 PacketLen,
|
||||
IN OUT UINT32 *Count,
|
||||
OUT EFI_MTFTP4_OPTION *Options OPTIONAL
|
||||
)
|
||||
{
|
||||
UINT8 *Cur;
|
||||
UINT8 *Last;
|
||||
UINT8 Num;
|
||||
UINT8 *Name;
|
||||
UINT8 *Value;
|
||||
|
||||
Num = 0;
|
||||
Cur = (UINT8 *) Packet + MTFTP4_OPCODE_LEN;
|
||||
Last = (UINT8 *) Packet + PacketLen - 1;
|
||||
|
||||
//
|
||||
// process option name and value pairs. The last byte is always zero
|
||||
//
|
||||
while (Cur < Last) {
|
||||
Name = Cur;
|
||||
|
||||
while (*Cur != 0) {
|
||||
Cur++;
|
||||
}
|
||||
|
||||
if (Cur == Last) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Value = ++Cur;
|
||||
|
||||
while (*Cur != 0) {
|
||||
Cur++;
|
||||
}
|
||||
|
||||
Num++;
|
||||
|
||||
if ((Options != NULL) && (Num <= *Count)) {
|
||||
Options[Num - 1].OptionStr = Name;
|
||||
Options[Num - 1].ValueStr = Value;
|
||||
}
|
||||
|
||||
Cur++;
|
||||
}
|
||||
|
||||
if ((*Count < Num) || (Options == NULL)) {
|
||||
*Count = Num;
|
||||
return EFI_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
*Count = Num;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Allocate and fill in a array of Mtftp options from the Packet.
|
||||
|
||||
It first calls Mtftp4FillOption to get the option number, then allocate
|
||||
the array, at last, call Mtftp4FillOption again to save the options.
|
||||
|
||||
@param Packet The packet to parse
|
||||
@param PacketLen The length of the packet
|
||||
@param OptionCount The number of options in the packet
|
||||
@param OptionList The point to get the option array.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The parametera are invalid or packet isn't a
|
||||
well-formated OACK packet.
|
||||
@retval EFI_SUCCESS The option array is build
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the array
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4ExtractOptions (
|
||||
IN EFI_MTFTP4_PACKET *Packet,
|
||||
IN UINT32 PacketLen,
|
||||
OUT UINT32 *OptionCount,
|
||||
OUT EFI_MTFTP4_OPTION **OptionList OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
*OptionCount = 0;
|
||||
|
||||
if (OptionList != NULL) {
|
||||
*OptionList = NULL;
|
||||
}
|
||||
|
||||
if (NTOHS (Packet->OpCode) != EFI_MTFTP4_OPCODE_OACK) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (PacketLen == MTFTP4_OPCODE_LEN) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// The last byte must be zero to terminate the options
|
||||
//
|
||||
if (*((UINT8 *) Packet + PacketLen - 1) != 0) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the number of options
|
||||
//
|
||||
Status = Mtftp4FillOptions (Packet, PacketLen, OptionCount, NULL);
|
||||
|
||||
if ((Status == EFI_SUCCESS) || (Status != EFI_BUFFER_TOO_SMALL)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Allocate memory for the options, then call Mtftp4FillOptions to
|
||||
// fill it if caller want that.
|
||||
//
|
||||
if (OptionList == NULL) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
*OptionList = AllocatePool (*OptionCount * sizeof (EFI_MTFTP4_OPTION));
|
||||
|
||||
if (*OptionList == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Mtftp4FillOptions (Packet, PacketLen, OptionCount, *OptionList);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Parse the MTFTP multicast option.
|
||||
|
||||
@param Value The Mtftp multicast value string
|
||||
@param Option The option to save the info into.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The multicast value string is invalid.
|
||||
@retval EFI_SUCCESS The multicast value is parsed into the Option
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4ExtractMcast (
|
||||
IN UINT8 *Value,
|
||||
IN OUT MTFTP4_OPTION *Option
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINT32 Num;
|
||||
|
||||
//
|
||||
// The multicast option is formated like "204.0.0.1,1857,1"
|
||||
// The server can also omit the ip and port, use ",,1"
|
||||
//
|
||||
if (*Value == ',') {
|
||||
Option->McastIp = 0;
|
||||
} else {
|
||||
Status = NetStringToIp (Value, &Option->McastIp);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
while ((*Value != 0) && (*Value != ',')) {
|
||||
Value++;
|
||||
}
|
||||
}
|
||||
|
||||
if (*Value != ',') {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Value++;
|
||||
|
||||
//
|
||||
// Convert the port setting. the server can send us a port number or
|
||||
// empty string. such as the port in ",,1"
|
||||
//
|
||||
if (*Value == ',') {
|
||||
Option->McastPort = 0;
|
||||
} else {
|
||||
Num = NetStringToU32 (Value);
|
||||
|
||||
if (Num > 65535) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Option->McastPort = (UINT16) Num;
|
||||
|
||||
while (NET_IS_DIGIT (*Value)) {
|
||||
Value++;
|
||||
}
|
||||
}
|
||||
|
||||
if (*Value != ',') {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Value++;
|
||||
|
||||
//
|
||||
// Check the master/slave setting, 1 for master, 0 for slave.
|
||||
//
|
||||
Num = NetStringToU32 (Value);
|
||||
|
||||
if ((Num != 0) && (Num != 1)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Option->Master = (BOOLEAN) (Num == 1);
|
||||
|
||||
while (NET_IS_DIGIT (*Value)) {
|
||||
Value++;
|
||||
}
|
||||
|
||||
if (*Value != '\0') {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Parse the option in Options array to MTFTP4_OPTION which program
|
||||
can access directly.
|
||||
|
||||
@param Options The option array, which contains addresses of each
|
||||
option's name/value string.
|
||||
@param Count The number of options in the Options
|
||||
@param Request Whether this is a request or OACK. The format of
|
||||
multicast is different according to this setting.
|
||||
@param Operation The current performed operation.
|
||||
@param MtftpOption The MTFTP4_OPTION for easy access.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The option is mal-formated
|
||||
@retval EFI_UNSUPPORTED Some option isn't supported
|
||||
@retval EFI_SUCCESS The option are OK and has been parsed.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4ParseOption (
|
||||
IN EFI_MTFTP4_OPTION *Options,
|
||||
IN UINT32 Count,
|
||||
IN BOOLEAN Request,
|
||||
IN UINT16 Operation,
|
||||
OUT MTFTP4_OPTION *MtftpOption
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINT32 Index;
|
||||
UINT32 Value;
|
||||
EFI_MTFTP4_OPTION *This;
|
||||
|
||||
MtftpOption->Exist = 0;
|
||||
|
||||
for (Index = 0; Index < Count; Index++) {
|
||||
This = Options + Index;
|
||||
|
||||
if ((This->OptionStr == NULL) || (This->ValueStr == NULL)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (NetStringEqualNoCase (This->OptionStr, (UINT8 *) "blksize")) {
|
||||
//
|
||||
// block size option, valid value is between [8, 65464]
|
||||
//
|
||||
Value = NetStringToU32 (This->ValueStr);
|
||||
|
||||
if ((Value < 8) || (Value > 65464)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
MtftpOption->BlkSize = (UINT16) Value;
|
||||
MtftpOption->Exist |= MTFTP4_BLKSIZE_EXIST;
|
||||
|
||||
} else if (NetStringEqualNoCase (This->OptionStr, (UINT8 *) "timeout")) {
|
||||
//
|
||||
// timeout option, valid value is between [1, 255]
|
||||
//
|
||||
Value = NetStringToU32 (This->ValueStr);
|
||||
|
||||
if ((Value < 1) || (Value > 255)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
MtftpOption->Timeout = (UINT8) Value;
|
||||
|
||||
} else if (NetStringEqualNoCase (This->OptionStr, (UINT8 *) "tsize")) {
|
||||
//
|
||||
// tsize option, the biggest transfer supported is 4GB with block size option
|
||||
//
|
||||
MtftpOption->Tsize = NetStringToU32 (This->ValueStr);
|
||||
MtftpOption->Exist |= MTFTP4_TSIZE_EXIST;
|
||||
|
||||
} else if (NetStringEqualNoCase (This->OptionStr, (UINT8 *) "multicast")) {
|
||||
//
|
||||
// Multicast option, if it is a request, the value must be a zero
|
||||
// length string, otherwise, it is formated like "204.0.0.1,1857,1\0"
|
||||
//
|
||||
if (Request) {
|
||||
if (*(This->ValueStr) != '\0') {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
} else {
|
||||
Status = Mtftp4ExtractMcast (This->ValueStr, MtftpOption);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
MtftpOption->Exist |= MTFTP4_MCAST_EXIST;
|
||||
|
||||
} else if (NetStringEqualNoCase (This->OptionStr, (UINT8 *) "windowsize")) {
|
||||
if (Operation == EFI_MTFTP4_OPCODE_WRQ) {
|
||||
//
|
||||
// Currently, windowsize is not supported in the write operation.
|
||||
//
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
Value = NetStringToU32 (This->ValueStr);
|
||||
|
||||
if (Value < 1) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
MtftpOption->WindowSize = (UINT16) Value;
|
||||
MtftpOption->Exist |= MTFTP4_WINDOWSIZE_EXIST;
|
||||
} else if (Request) {
|
||||
//
|
||||
// Ignore the unsupported option if it is a reply, and return
|
||||
// EFI_UNSUPPORTED if it's a request according to the UEFI spec.
|
||||
//
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Parse the options in the OACK packet to MTFTP4_OPTION which program
|
||||
can access directly.
|
||||
|
||||
@param Packet The OACK packet to parse
|
||||
@param PacketLen The length of the packet
|
||||
@param Operation The current performed operation.
|
||||
@param MtftpOption The MTFTP_OPTION for easy access.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The packet option is mal-formated
|
||||
@retval EFI_UNSUPPORTED Some option isn't supported
|
||||
@retval EFI_SUCCESS The option are OK and has been parsed.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4ParseOptionOack (
|
||||
IN EFI_MTFTP4_PACKET *Packet,
|
||||
IN UINT32 PacketLen,
|
||||
IN UINT16 Operation,
|
||||
OUT MTFTP4_OPTION *MtftpOption
|
||||
)
|
||||
{
|
||||
EFI_MTFTP4_OPTION *OptionList;
|
||||
EFI_STATUS Status;
|
||||
UINT32 Count;
|
||||
|
||||
MtftpOption->Exist = 0;
|
||||
|
||||
Status = Mtftp4ExtractOptions (Packet, PacketLen, &Count, &OptionList);
|
||||
|
||||
if (EFI_ERROR (Status) || (Count == 0)) {
|
||||
return Status;
|
||||
}
|
||||
ASSERT (OptionList != NULL);
|
||||
|
||||
Status = Mtftp4ParseOption (OptionList, Count, FALSE, Operation, MtftpOption);
|
||||
|
||||
FreePool (OptionList);
|
||||
return Status;
|
||||
}
|
111
NetworkPkg/Mtftp4Dxe/Mtftp4Option.h
Normal file
111
NetworkPkg/Mtftp4Dxe/Mtftp4Option.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/** @file
|
||||
Routines to process MTFTP4 options.
|
||||
|
||||
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
|
||||
#ifndef __EFI_MTFTP4_OPTION_H__
|
||||
#define __EFI_MTFTP4_OPTION_H__
|
||||
|
||||
#define MTFTP4_SUPPORTED_OPTIONS 5
|
||||
#define MTFTP4_OPCODE_LEN 2
|
||||
#define MTFTP4_ERRCODE_LEN 2
|
||||
#define MTFTP4_BLKNO_LEN 2
|
||||
#define MTFTP4_DATA_HEAD_LEN 4
|
||||
|
||||
#define MTFTP4_BLKSIZE_EXIST 0x01
|
||||
#define MTFTP4_TIMEOUT_EXIST 0x02
|
||||
#define MTFTP4_TSIZE_EXIST 0x04
|
||||
#define MTFTP4_MCAST_EXIST 0x08
|
||||
#define MTFTP4_WINDOWSIZE_EXIST 0x10
|
||||
|
||||
typedef struct {
|
||||
UINT16 BlkSize;
|
||||
UINT16 WindowSize;
|
||||
UINT8 Timeout;
|
||||
UINT32 Tsize;
|
||||
IP4_ADDR McastIp;
|
||||
UINT16 McastPort;
|
||||
BOOLEAN Master;
|
||||
UINT32 Exist;
|
||||
} MTFTP4_OPTION;
|
||||
|
||||
/**
|
||||
Allocate and fill in a array of Mtftp options from the Packet.
|
||||
|
||||
It first calls Mtftp4FillOption to get the option number, then allocate
|
||||
the array, at last, call Mtftp4FillOption again to save the options.
|
||||
|
||||
@param Packet The packet to parse
|
||||
@param PacketLen The length of the packet
|
||||
@param OptionCount The number of options in the packet
|
||||
@param OptionList The point to get the option array.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The parametera are invalid or packet isn't a
|
||||
well-formated OACK packet.
|
||||
@retval EFI_SUCCESS The option array is build
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the array
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4ExtractOptions (
|
||||
IN EFI_MTFTP4_PACKET *Packet,
|
||||
IN UINT32 PacketLen,
|
||||
OUT UINT32 *OptionCount,
|
||||
OUT EFI_MTFTP4_OPTION **OptionList OPTIONAL
|
||||
);
|
||||
|
||||
/**
|
||||
Parse the option in Options array to MTFTP4_OPTION which program
|
||||
can access directly.
|
||||
|
||||
@param Options The option array, which contains addresses of each
|
||||
option's name/value string.
|
||||
@param Count The number of options in the Options
|
||||
@param Request Whether this is a request or OACK. The format of
|
||||
multicast is different according to this setting.
|
||||
@param Operation The current performed operation.
|
||||
@param MtftpOption The MTFTP4_OPTION for easy access.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The option is mal-formated
|
||||
@retval EFI_UNSUPPORTED Some option isn't supported
|
||||
@retval EFI_SUCCESS The option are OK and has been parsed.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4ParseOption (
|
||||
IN EFI_MTFTP4_OPTION *Options,
|
||||
IN UINT32 Count,
|
||||
IN BOOLEAN Request,
|
||||
IN UINT16 Operation,
|
||||
OUT MTFTP4_OPTION *MtftpOption
|
||||
);
|
||||
|
||||
/**
|
||||
Parse the options in the OACK packet to MTFTP4_OPTION which program
|
||||
can access directly.
|
||||
|
||||
@param Packet The OACK packet to parse
|
||||
@param PacketLen The length of the packet
|
||||
@param Operation The current performed operation.
|
||||
@param MtftpOption The MTFTP_OPTION for easy access.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The packet option is mal-formated
|
||||
@retval EFI_UNSUPPORTED Some option isn't supported
|
||||
@retval EFI_SUCCESS The option are OK and has been parsed.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4ParseOptionOack (
|
||||
IN EFI_MTFTP4_PACKET *Packet,
|
||||
IN UINT32 PacketLen,
|
||||
IN UINT16 Operation,
|
||||
OUT MTFTP4_OPTION *MtftpOption
|
||||
);
|
||||
|
||||
extern CHAR8 *mMtftp4SupportedOptions[MTFTP4_SUPPORTED_OPTIONS];
|
||||
|
||||
#endif
|
818
NetworkPkg/Mtftp4Dxe/Mtftp4Rrq.c
Normal file
818
NetworkPkg/Mtftp4Dxe/Mtftp4Rrq.c
Normal file
@@ -0,0 +1,818 @@
|
||||
/** @file
|
||||
Routines to process Rrq (download).
|
||||
|
||||
(C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
|
||||
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
|
||||
#include "Mtftp4Impl.h"
|
||||
|
||||
|
||||
/**
|
||||
The packet process callback for MTFTP download.
|
||||
|
||||
@param UdpPacket The packet received
|
||||
@param EndPoint The local/remote access point of the packet
|
||||
@param IoStatus The status of the receiving
|
||||
@param Context Opaque parameter, which is the MTFTP session
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
Mtftp4RrqInput (
|
||||
IN NET_BUF *UdpPacket,
|
||||
IN UDP_END_POINT *EndPoint,
|
||||
IN EFI_STATUS IoStatus,
|
||||
IN VOID *Context
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
Start the MTFTP session to download.
|
||||
|
||||
It will first initialize some of the internal states then build and send a RRQ
|
||||
reqeuest packet, at last, it will start receive for the downloading.
|
||||
|
||||
@param Instance The Mtftp session
|
||||
@param Operation The MTFTP opcode, it may be a EFI_MTFTP4_OPCODE_RRQ
|
||||
or EFI_MTFTP4_OPCODE_DIR.
|
||||
|
||||
@retval EFI_SUCCESS The mtftp download session is started.
|
||||
@retval Others Failed to start downloading.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4RrqStart (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN UINT16 Operation
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
//
|
||||
// The valid block number range are [1, 0xffff]. For example:
|
||||
// the client sends an RRQ request to the server, the server
|
||||
// transfers the DATA1 block. If option negoitation is ongoing,
|
||||
// the server will send back an OACK, then client will send ACK0.
|
||||
//
|
||||
Status = Mtftp4InitBlockRange (&Instance->Blocks, 1, 0xffff);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = Mtftp4SendRequest (Instance);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
return UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4RrqInput, Instance, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Build and send a ACK packet for the download session.
|
||||
|
||||
@param Instance The Mtftp session
|
||||
@param BlkNo The BlkNo to ack.
|
||||
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet
|
||||
@retval EFI_SUCCESS The ACK has been sent
|
||||
@retval Others Failed to send the ACK.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4RrqSendAck (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN UINT16 BlkNo
|
||||
)
|
||||
{
|
||||
EFI_MTFTP4_PACKET *Ack;
|
||||
NET_BUF *Packet;
|
||||
EFI_STATUS Status;
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
|
||||
Packet = NetbufAlloc (sizeof (EFI_MTFTP4_ACK_HEADER));
|
||||
if (Packet == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Ack = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (
|
||||
Packet,
|
||||
sizeof (EFI_MTFTP4_ACK_HEADER),
|
||||
FALSE
|
||||
);
|
||||
ASSERT (Ack != NULL);
|
||||
|
||||
Ack->Ack.OpCode = HTONS (EFI_MTFTP4_OPCODE_ACK);
|
||||
Ack->Ack.Block[0] = HTONS (BlkNo);
|
||||
|
||||
Status = Mtftp4SendPacket (Instance, Packet);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
Instance->AckedBlock = Instance->TotalBlock;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Deliver the received data block to the user, which can be saved
|
||||
in the user provide buffer or through the CheckPacket callback.
|
||||
|
||||
@param Instance The Mtftp session
|
||||
@param Packet The received data packet
|
||||
@param Len The packet length
|
||||
|
||||
@retval EFI_SUCCESS The data is saved successfully
|
||||
@retval EFI_ABORTED The user tells to abort by return an error through
|
||||
CheckPacket
|
||||
@retval EFI_BUFFER_TOO_SMALL The user's buffer is too small and buffer length is
|
||||
updated to the actual buffer size needed.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4RrqSaveBlock (
|
||||
IN OUT MTFTP4_PROTOCOL *Instance,
|
||||
IN EFI_MTFTP4_PACKET *Packet,
|
||||
IN UINT32 Len
|
||||
)
|
||||
{
|
||||
EFI_MTFTP4_TOKEN *Token;
|
||||
EFI_STATUS Status;
|
||||
UINT16 Block;
|
||||
UINT64 Start;
|
||||
UINT32 DataLen;
|
||||
UINT64 BlockCounter;
|
||||
BOOLEAN Completed;
|
||||
|
||||
Completed = FALSE;
|
||||
Token = Instance->Token;
|
||||
Block = NTOHS (Packet->Data.Block);
|
||||
DataLen = Len - MTFTP4_DATA_HEAD_LEN;
|
||||
|
||||
//
|
||||
// This is the last block, save the block no
|
||||
//
|
||||
if (DataLen < Instance->BlkSize) {
|
||||
Completed = TRUE;
|
||||
Instance->LastBlock = Block;
|
||||
Mtftp4SetLastBlockNum (&Instance->Blocks, Block);
|
||||
}
|
||||
|
||||
//
|
||||
// Remove this block number from the file hole. If Mtftp4RemoveBlockNum
|
||||
// returns EFI_NOT_FOUND, the block has been saved, don't save it again.
|
||||
// Note that : For bigger files, allowing the block counter to roll over
|
||||
// to accept transfers of unlimited size. So BlockCounter is memorised as
|
||||
// continuous block counter.
|
||||
//
|
||||
Status = Mtftp4RemoveBlockNum (&Instance->Blocks, Block, Completed, &BlockCounter);
|
||||
|
||||
if (Status == EFI_NOT_FOUND) {
|
||||
return EFI_SUCCESS;
|
||||
} else if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (Token->CheckPacket != NULL) {
|
||||
Status = Token->CheckPacket (&Instance->Mtftp4, Token, (UINT16) Len, Packet);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,
|
||||
(UINT8 *) "User aborted download"
|
||||
);
|
||||
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
}
|
||||
|
||||
if (Token->Buffer != NULL) {
|
||||
Start = MultU64x32 (BlockCounter - 1, Instance->BlkSize);
|
||||
|
||||
if (Start + DataLen <= Token->BufferSize) {
|
||||
CopyMem ((UINT8 *) Token->Buffer + Start, Packet->Data.Data, DataLen);
|
||||
|
||||
//
|
||||
// Update the file size when received the last block
|
||||
//
|
||||
if ((Instance->LastBlock == Block) && Completed) {
|
||||
Token->BufferSize = Start + DataLen;
|
||||
}
|
||||
|
||||
} else if (Instance->LastBlock != 0) {
|
||||
//
|
||||
// Don't save the data if the buffer is too small, return
|
||||
// EFI_BUFFER_TOO_SMALL if received the last packet. This
|
||||
// will give a accurate file length.
|
||||
//
|
||||
Token->BufferSize = Start + DataLen;
|
||||
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_DISK_FULL,
|
||||
(UINT8 *) "User provided memory block is too small"
|
||||
);
|
||||
|
||||
return EFI_BUFFER_TOO_SMALL;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Function to process the received data packets.
|
||||
|
||||
It will save the block then send back an ACK if it is active.
|
||||
|
||||
@param Instance The downloading MTFTP session
|
||||
@param Packet The packet received
|
||||
@param Len The length of the packet
|
||||
@param Multicast Whether this packet is multicast or unicast
|
||||
@param Completed Return whether the download has completed
|
||||
|
||||
@retval EFI_SUCCESS The data packet is successfully processed
|
||||
@retval EFI_ABORTED The download is aborted by the user
|
||||
@retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4RrqHandleData (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN EFI_MTFTP4_PACKET *Packet,
|
||||
IN UINT32 Len,
|
||||
IN BOOLEAN Multicast,
|
||||
OUT BOOLEAN *Completed
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINT16 BlockNum;
|
||||
INTN Expected;
|
||||
|
||||
*Completed = FALSE;
|
||||
Status = EFI_SUCCESS;
|
||||
BlockNum = NTOHS (Packet->Data.Block);
|
||||
Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
|
||||
|
||||
ASSERT (Expected >= 0);
|
||||
|
||||
//
|
||||
// If we are active (Master) and received an unexpected packet, transmit
|
||||
// the ACK for the block we received, then restart receiving the
|
||||
// expected one. If we are passive (Slave), save the block.
|
||||
//
|
||||
if (Instance->Master && (Expected != BlockNum)) {
|
||||
//
|
||||
// If Expected is 0, (UINT16) (Expected - 1) is also the expected Ack number (65535).
|
||||
//
|
||||
return Mtftp4RrqSendAck (Instance, (UINT16) (Expected - 1));
|
||||
}
|
||||
|
||||
Status = Mtftp4RrqSaveBlock (Instance, Packet, Len);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Record the total received and saved block number.
|
||||
//
|
||||
Instance->TotalBlock ++;
|
||||
|
||||
//
|
||||
// Reset the passive client's timer whenever it received a
|
||||
// valid data packet.
|
||||
//
|
||||
if (!Instance->Master) {
|
||||
Mtftp4SetTimeout (Instance);
|
||||
}
|
||||
|
||||
//
|
||||
// Check whether we have received all the blocks. Send the ACK if we
|
||||
// are active (unicast client or master client for multicast download).
|
||||
// If we have received all the blocks, send an ACK even if we are passive
|
||||
// to tell the server that we are done.
|
||||
//
|
||||
Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
|
||||
|
||||
if (Instance->Master || (Expected < 0)) {
|
||||
if (Expected < 0) {
|
||||
//
|
||||
// If we are passive client, then the just received Block maybe
|
||||
// isn't the last block. We need to send an ACK to the last block
|
||||
// to inform the server that we are done. If we are active client,
|
||||
// the Block == Instance->LastBlock.
|
||||
//
|
||||
BlockNum = Instance->LastBlock;
|
||||
*Completed = TRUE;
|
||||
|
||||
} else {
|
||||
BlockNum = (UINT16) (Expected - 1);
|
||||
}
|
||||
|
||||
if (Instance->WindowSize == (Instance->TotalBlock - Instance->AckedBlock) || Expected < 0) {
|
||||
Status = Mtftp4RrqSendAck (Instance, BlockNum);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Validate whether the options received in the server's OACK packet is valid.
|
||||
|
||||
The options are valid only if:
|
||||
1. The server doesn't include options not requested by us
|
||||
2. The server can only use smaller blksize than that is requested
|
||||
3. The server can only use the same timeout as requested
|
||||
4. The server doesn't change its multicast channel.
|
||||
|
||||
@param This The downloading Mtftp session
|
||||
@param Reply The options in the OACK packet
|
||||
@param Request The requested options
|
||||
|
||||
@retval TRUE The options in the OACK is OK.
|
||||
@retval FALSE The options in the OACK is invalid.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
Mtftp4RrqOackValid (
|
||||
IN MTFTP4_PROTOCOL *This,
|
||||
IN MTFTP4_OPTION *Reply,
|
||||
IN MTFTP4_OPTION *Request
|
||||
)
|
||||
{
|
||||
|
||||
//
|
||||
// It is invalid for server to return options we don't request
|
||||
//
|
||||
if ((Reply->Exist &~Request->Exist) != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Server can only specify a smaller block size and window size to be used and
|
||||
// return the timeout matches that requested.
|
||||
//
|
||||
if ((((Reply->Exist & MTFTP4_BLKSIZE_EXIST) != 0)&& (Reply->BlkSize > Request->BlkSize)) ||
|
||||
(((Reply->Exist & MTFTP4_WINDOWSIZE_EXIST) != 0)&& (Reply->WindowSize > Request->WindowSize)) ||
|
||||
(((Reply->Exist & MTFTP4_TIMEOUT_EXIST) != 0) && (Reply->Timeout != Request->Timeout))
|
||||
) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// The server can send ",,master" to client to change its master
|
||||
// setting. But if it use the specific multicast channel, it can't
|
||||
// change the setting.
|
||||
//
|
||||
if (((Reply->Exist & MTFTP4_MCAST_EXIST) != 0) && (This->McastIp != 0)) {
|
||||
if ((Reply->McastIp != 0) && (Reply->McastIp != This->McastIp)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((Reply->McastPort != 0) && (Reply->McastPort != This->McastPort)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Configure a UDP IO port to receive the multicast.
|
||||
|
||||
@param McastIo The UDP IO to configure
|
||||
@param Context The opaque parameter to the function which is the
|
||||
MTFTP session.
|
||||
|
||||
@retval EFI_SUCCESS The UDP child is successfully configured.
|
||||
@retval Others Failed to configure the UDP child.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4RrqConfigMcastPort (
|
||||
IN UDP_IO *McastIo,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
MTFTP4_PROTOCOL *Instance;
|
||||
EFI_MTFTP4_CONFIG_DATA *Config;
|
||||
EFI_UDP4_CONFIG_DATA UdpConfig;
|
||||
EFI_IPv4_ADDRESS Group;
|
||||
EFI_STATUS Status;
|
||||
IP4_ADDR Ip;
|
||||
|
||||
Instance = (MTFTP4_PROTOCOL *) Context;
|
||||
Config = &Instance->Config;
|
||||
|
||||
UdpConfig.AcceptBroadcast = FALSE;
|
||||
UdpConfig.AcceptPromiscuous = FALSE;
|
||||
UdpConfig.AcceptAnyPort = FALSE;
|
||||
UdpConfig.AllowDuplicatePort = FALSE;
|
||||
UdpConfig.TypeOfService = 0;
|
||||
UdpConfig.TimeToLive = 64;
|
||||
UdpConfig.DoNotFragment = FALSE;
|
||||
UdpConfig.ReceiveTimeout = 0;
|
||||
UdpConfig.TransmitTimeout = 0;
|
||||
UdpConfig.UseDefaultAddress = Config->UseDefaultSetting;
|
||||
IP4_COPY_ADDRESS (&UdpConfig.StationAddress, &Config->StationIp);
|
||||
IP4_COPY_ADDRESS (&UdpConfig.SubnetMask, &Config->SubnetMask);
|
||||
UdpConfig.StationPort = Instance->McastPort;
|
||||
UdpConfig.RemotePort = 0;
|
||||
|
||||
Ip = HTONL (Instance->ServerIp);
|
||||
IP4_COPY_ADDRESS (&UdpConfig.RemoteAddress, &Ip);
|
||||
|
||||
Status = McastIo->Protocol.Udp4->Configure (McastIo->Protocol.Udp4, &UdpConfig);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (!Config->UseDefaultSetting &&
|
||||
!EFI_IP4_EQUAL (&mZeroIp4Addr, &Config->GatewayIp)) {
|
||||
//
|
||||
// The station IP address is manually configured and the Gateway IP is not 0.
|
||||
// Add the default route for this UDP instance.
|
||||
//
|
||||
Status = McastIo->Protocol.Udp4->Routes (
|
||||
McastIo->Protocol.Udp4,
|
||||
FALSE,
|
||||
&mZeroIp4Addr,
|
||||
&mZeroIp4Addr,
|
||||
&Config->GatewayIp
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
McastIo->Protocol.Udp4->Configure (McastIo->Protocol.Udp4, NULL);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// join the multicast group
|
||||
//
|
||||
Ip = HTONL (Instance->McastIp);
|
||||
IP4_COPY_ADDRESS (&Group, &Ip);
|
||||
|
||||
return McastIo->Protocol.Udp4->Groups (McastIo->Protocol.Udp4, TRUE, &Group);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Function to process the OACK.
|
||||
|
||||
It will first validate the OACK packet, then update the various negotiated parameters.
|
||||
|
||||
@param Instance The download MTFTP session
|
||||
@param Packet The packet received
|
||||
@param Len The packet length
|
||||
@param Multicast Whether this packet is received as a multicast
|
||||
@param Completed Returns whether the download has completed. NOT
|
||||
used by this function.
|
||||
|
||||
@retval EFI_DEVICE_ERROR Failed to create/start a multicast UDP child
|
||||
@retval EFI_TFTP_ERROR Some error happened during the process
|
||||
@retval EFI_SUCCESS The OACK is successfully processed.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4RrqHandleOack (
|
||||
IN OUT MTFTP4_PROTOCOL *Instance,
|
||||
IN EFI_MTFTP4_PACKET *Packet,
|
||||
IN UINT32 Len,
|
||||
IN BOOLEAN Multicast,
|
||||
OUT BOOLEAN *Completed
|
||||
)
|
||||
{
|
||||
MTFTP4_OPTION Reply;
|
||||
EFI_STATUS Status;
|
||||
INTN Expected;
|
||||
EFI_UDP4_PROTOCOL *Udp4;
|
||||
|
||||
*Completed = FALSE;
|
||||
|
||||
//
|
||||
// If already started the master download, don't change the
|
||||
// setting. Master download always succeeds.
|
||||
//
|
||||
Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
|
||||
ASSERT (Expected != -1);
|
||||
|
||||
if (Instance->Master && (Expected != 1)) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// Parse and validate the options from server
|
||||
//
|
||||
ZeroMem (&Reply, sizeof (MTFTP4_OPTION));
|
||||
|
||||
Status = Mtftp4ParseOptionOack (Packet, Len, Instance->Operation, &Reply);
|
||||
|
||||
if (EFI_ERROR (Status) ||
|
||||
!Mtftp4RrqOackValid (Instance, &Reply, &Instance->RequestOption)) {
|
||||
//
|
||||
// Don't send an ERROR packet if the error is EFI_OUT_OF_RESOURCES.
|
||||
//
|
||||
if (Status != EFI_OUT_OF_RESOURCES) {
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,
|
||||
(UINT8 *) "Mal-formated OACK packet"
|
||||
);
|
||||
}
|
||||
|
||||
return EFI_TFTP_ERROR;
|
||||
}
|
||||
|
||||
if ((Reply.Exist & MTFTP4_MCAST_EXIST) != 0) {
|
||||
|
||||
//
|
||||
// Save the multicast info. Always update the Master, only update the
|
||||
// multicast IP address, block size, window size, timeoute at the first time. If IP
|
||||
// address is updated, create a UDP child to receive the multicast.
|
||||
//
|
||||
Instance->Master = Reply.Master;
|
||||
|
||||
if (Instance->McastIp == 0) {
|
||||
if ((Reply.McastIp == 0) || (Reply.McastPort == 0)) {
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,
|
||||
(UINT8 *) "Illegal multicast setting"
|
||||
);
|
||||
|
||||
return EFI_TFTP_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Create a UDP child then start receive the multicast from it.
|
||||
//
|
||||
Instance->McastIp = Reply.McastIp;
|
||||
Instance->McastPort = Reply.McastPort;
|
||||
if (Instance->McastUdpPort == NULL) {
|
||||
Instance->McastUdpPort = UdpIoCreateIo (
|
||||
Instance->Service->Controller,
|
||||
Instance->Service->Image,
|
||||
Mtftp4RrqConfigMcastPort,
|
||||
UDP_IO_UDP4_VERSION,
|
||||
Instance
|
||||
);
|
||||
if (Instance->McastUdpPort != NULL) {
|
||||
Status = gBS->OpenProtocol (
|
||||
Instance->McastUdpPort->UdpHandle,
|
||||
&gEfiUdp4ProtocolGuid,
|
||||
(VOID **) &Udp4,
|
||||
Instance->Service->Image,
|
||||
Instance->Handle,
|
||||
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
UdpIoFreeIo (Instance->McastUdpPort);
|
||||
Instance->McastUdpPort = NULL;
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (Instance->McastUdpPort == NULL) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
Status = UdpIoRecvDatagram (Instance->McastUdpPort, Mtftp4RrqInput, Instance, 0);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_ACCESS_VIOLATION,
|
||||
(UINT8 *) "Failed to create socket to receive multicast packet"
|
||||
);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Update the parameters used.
|
||||
//
|
||||
if (Reply.BlkSize != 0) {
|
||||
Instance->BlkSize = Reply.BlkSize;
|
||||
}
|
||||
|
||||
if (Reply.WindowSize != 0) {
|
||||
Instance->WindowSize = Reply.WindowSize;
|
||||
}
|
||||
|
||||
if (Reply.Timeout != 0) {
|
||||
Instance->Timeout = Reply.Timeout;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
Instance->Master = TRUE;
|
||||
|
||||
if (Reply.BlkSize != 0) {
|
||||
Instance->BlkSize = Reply.BlkSize;
|
||||
}
|
||||
|
||||
if (Reply.WindowSize != 0) {
|
||||
Instance->WindowSize = Reply.WindowSize;
|
||||
}
|
||||
|
||||
if (Reply.Timeout != 0) {
|
||||
Instance->Timeout = Reply.Timeout;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Send an ACK to (Expected - 1) which is 0 for unicast download,
|
||||
// or tell the server we want to receive the Expected block.
|
||||
//
|
||||
return Mtftp4RrqSendAck (Instance, (UINT16) (Expected - 1));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
The packet process callback for MTFTP download.
|
||||
|
||||
@param UdpPacket The packet received
|
||||
@param EndPoint The local/remote access point of the packet
|
||||
@param IoStatus The status of the receiving
|
||||
@param Context Opaque parameter, which is the MTFTP session
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
Mtftp4RrqInput (
|
||||
IN NET_BUF *UdpPacket,
|
||||
IN UDP_END_POINT *EndPoint,
|
||||
IN EFI_STATUS IoStatus,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
MTFTP4_PROTOCOL *Instance;
|
||||
EFI_MTFTP4_PACKET *Packet;
|
||||
BOOLEAN Completed;
|
||||
BOOLEAN Multicast;
|
||||
EFI_STATUS Status;
|
||||
UINT16 Opcode;
|
||||
UINT32 Len;
|
||||
|
||||
Instance = (MTFTP4_PROTOCOL *) Context;
|
||||
NET_CHECK_SIGNATURE (Instance, MTFTP4_PROTOCOL_SIGNATURE);
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
Packet = NULL;
|
||||
Completed = FALSE;
|
||||
Multicast = FALSE;
|
||||
|
||||
if (EFI_ERROR (IoStatus)) {
|
||||
Status = IoStatus;
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
ASSERT (UdpPacket != NULL);
|
||||
|
||||
//
|
||||
// Find the port this packet is from to restart receive correctly.
|
||||
//
|
||||
Multicast = (BOOLEAN) (EndPoint->LocalAddr.Addr[0] == Instance->McastIp);
|
||||
|
||||
if (UdpPacket->TotalSize < MTFTP4_OPCODE_LEN) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
//
|
||||
// Client send initial request to server's listening port. Server
|
||||
// will select a UDP port to communicate with the client. The server
|
||||
// is required to use the same port as RemotePort to multicast the
|
||||
// data.
|
||||
//
|
||||
if (EndPoint->RemotePort != Instance->ConnectedPort) {
|
||||
if (Instance->ConnectedPort != 0) {
|
||||
goto ON_EXIT;
|
||||
} else {
|
||||
Instance->ConnectedPort = EndPoint->RemotePort;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Copy the MTFTP packet to a continuous buffer if it isn't already so.
|
||||
//
|
||||
Len = UdpPacket->TotalSize;
|
||||
|
||||
if (UdpPacket->BlockOpNum > 1) {
|
||||
Packet = AllocatePool (Len);
|
||||
|
||||
if (Packet == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet);
|
||||
|
||||
} else {
|
||||
Packet = (EFI_MTFTP4_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);
|
||||
ASSERT (Packet != NULL);
|
||||
}
|
||||
|
||||
Opcode = NTOHS (Packet->OpCode);
|
||||
|
||||
//
|
||||
// Call the user's CheckPacket if provided. Abort the transmission
|
||||
// if CheckPacket returns an EFI_ERROR code.
|
||||
//
|
||||
if ((Instance->Token->CheckPacket != NULL) &&
|
||||
((Opcode == EFI_MTFTP4_OPCODE_OACK) || (Opcode == EFI_MTFTP4_OPCODE_ERROR))) {
|
||||
|
||||
Status = Instance->Token->CheckPacket (
|
||||
&Instance->Mtftp4,
|
||||
Instance->Token,
|
||||
(UINT16) Len,
|
||||
Packet
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
//
|
||||
// Send an error message to the server to inform it
|
||||
//
|
||||
if (Opcode != EFI_MTFTP4_OPCODE_ERROR) {
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,
|
||||
(UINT8 *) "User aborted the transfer"
|
||||
);
|
||||
}
|
||||
|
||||
Status = EFI_ABORTED;
|
||||
goto ON_EXIT;
|
||||
}
|
||||
}
|
||||
|
||||
switch (Opcode) {
|
||||
case EFI_MTFTP4_OPCODE_DATA:
|
||||
if ((Len > (UINT32) (MTFTP4_DATA_HEAD_LEN + Instance->BlkSize)) ||
|
||||
(Len < (UINT32) MTFTP4_DATA_HEAD_LEN)) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
Status = Mtftp4RrqHandleData (Instance, Packet, Len, Multicast, &Completed);
|
||||
break;
|
||||
|
||||
case EFI_MTFTP4_OPCODE_OACK:
|
||||
if (Multicast || (Len <= MTFTP4_OPCODE_LEN)) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
Status = Mtftp4RrqHandleOack (Instance, Packet, Len, Multicast, &Completed);
|
||||
break;
|
||||
|
||||
case EFI_MTFTP4_OPCODE_ERROR:
|
||||
Status = EFI_TFTP_ERROR;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ON_EXIT:
|
||||
|
||||
//
|
||||
// Free the resources, then if !EFI_ERROR (Status), restart the
|
||||
// receive, otherwise end the session.
|
||||
//
|
||||
if ((Packet != NULL) && (UdpPacket->BlockOpNum > 1)) {
|
||||
FreePool (Packet);
|
||||
}
|
||||
|
||||
if (UdpPacket != NULL) {
|
||||
NetbufFree (UdpPacket);
|
||||
}
|
||||
|
||||
if (!EFI_ERROR (Status) && !Completed) {
|
||||
if (Multicast) {
|
||||
Status = UdpIoRecvDatagram (Instance->McastUdpPort, Mtftp4RrqInput, Instance, 0);
|
||||
} else {
|
||||
Status = UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4RrqInput, Instance, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (EFI_ERROR (Status) || Completed) {
|
||||
Mtftp4CleanOperation (Instance, Status);
|
||||
}
|
||||
}
|
663
NetworkPkg/Mtftp4Dxe/Mtftp4Support.c
Normal file
663
NetworkPkg/Mtftp4Dxe/Mtftp4Support.c
Normal file
@@ -0,0 +1,663 @@
|
||||
/** @file
|
||||
Support routines for Mtftp.
|
||||
|
||||
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#include "Mtftp4Impl.h"
|
||||
|
||||
|
||||
/**
|
||||
Allocate a MTFTP4 block range, then init it to the range of [Start, End]
|
||||
|
||||
@param Start The start block number
|
||||
@param End The last block number in the range
|
||||
|
||||
@return Pointer to the created block range, NULL if failed to allocate memory.
|
||||
|
||||
**/
|
||||
MTFTP4_BLOCK_RANGE *
|
||||
Mtftp4AllocateRange (
|
||||
IN UINT16 Start,
|
||||
IN UINT16 End
|
||||
)
|
||||
{
|
||||
MTFTP4_BLOCK_RANGE *Range;
|
||||
|
||||
Range = AllocateZeroPool (sizeof (MTFTP4_BLOCK_RANGE));
|
||||
|
||||
if (Range == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
InitializeListHead (&Range->Link);
|
||||
Range->Start = Start;
|
||||
Range->End = End;
|
||||
Range->Bound = End;
|
||||
|
||||
return Range;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Initialize the block range for either RRQ or WRQ.
|
||||
|
||||
RRQ and WRQ have different requirements for Start and End.
|
||||
For example, during start up, WRQ initializes its whole valid block range
|
||||
to [0, 0xffff]. This is bacause the server will send us a ACK0 to inform us
|
||||
to start the upload. When the client received ACK0, it will remove 0 from the
|
||||
range, get the next block number, which is 1, then upload the BLOCK1. For RRQ
|
||||
without option negotiation, the server will directly send us the BLOCK1 in
|
||||
response to the client's RRQ. When received BLOCK1, the client will remove
|
||||
it from the block range and send an ACK. It also works if there is option
|
||||
negotiation.
|
||||
|
||||
@param Head The block range head to initialize
|
||||
@param Start The Start block number.
|
||||
@param End The last block number.
|
||||
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory for initial block range
|
||||
@retval EFI_SUCCESS The initial block range is created.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4InitBlockRange (
|
||||
IN LIST_ENTRY *Head,
|
||||
IN UINT16 Start,
|
||||
IN UINT16 End
|
||||
)
|
||||
{
|
||||
MTFTP4_BLOCK_RANGE *Range;
|
||||
|
||||
Range = Mtftp4AllocateRange (Start, End);
|
||||
|
||||
if (Range == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
InsertTailList (Head, &Range->Link);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get the first valid block number on the range list.
|
||||
|
||||
@param Head The block range head
|
||||
|
||||
@return The first valid block number, -1 if the block range is empty.
|
||||
|
||||
**/
|
||||
INTN
|
||||
Mtftp4GetNextBlockNum (
|
||||
IN LIST_ENTRY *Head
|
||||
)
|
||||
{
|
||||
MTFTP4_BLOCK_RANGE *Range;
|
||||
|
||||
if (IsListEmpty (Head)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Range = NET_LIST_HEAD (Head, MTFTP4_BLOCK_RANGE, Link);
|
||||
return Range->Start;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Set the last block number of the block range list.
|
||||
|
||||
It will remove all the blocks after the Last. MTFTP initialize the block range
|
||||
to the maximum possible range, such as [0, 0xffff] for WRQ. When it gets the
|
||||
last block number, it will call this function to set the last block number.
|
||||
|
||||
@param Head The block range list
|
||||
@param Last The last block number
|
||||
|
||||
**/
|
||||
VOID
|
||||
Mtftp4SetLastBlockNum (
|
||||
IN LIST_ENTRY *Head,
|
||||
IN UINT16 Last
|
||||
)
|
||||
{
|
||||
MTFTP4_BLOCK_RANGE *Range;
|
||||
|
||||
//
|
||||
// Iterate from the tail to head to remove the block number
|
||||
// after the last.
|
||||
//
|
||||
while (!IsListEmpty (Head)) {
|
||||
Range = NET_LIST_TAIL (Head, MTFTP4_BLOCK_RANGE, Link);
|
||||
|
||||
if (Range->Start > Last) {
|
||||
RemoveEntryList (&Range->Link);
|
||||
FreePool (Range);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Range->End > Last) {
|
||||
Range->End = Last;
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Remove the block number from the block range list.
|
||||
|
||||
@param Head The block range list to remove from
|
||||
@param Num The block number to remove
|
||||
@param Completed Whether Num is the last block number.
|
||||
@param BlockCounter The continuous block counter instead of the value after roll-over.
|
||||
|
||||
@retval EFI_NOT_FOUND The block number isn't in the block range list
|
||||
@retval EFI_SUCCESS The block number has been removed from the list
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4RemoveBlockNum (
|
||||
IN LIST_ENTRY *Head,
|
||||
IN UINT16 Num,
|
||||
IN BOOLEAN Completed,
|
||||
OUT UINT64 *BlockCounter
|
||||
)
|
||||
{
|
||||
MTFTP4_BLOCK_RANGE *Range;
|
||||
MTFTP4_BLOCK_RANGE *NewRange;
|
||||
LIST_ENTRY *Entry;
|
||||
|
||||
NET_LIST_FOR_EACH (Entry, Head) {
|
||||
|
||||
//
|
||||
// Each block represents a hole [Start, End] in the file,
|
||||
// skip to the first range with End >= Num
|
||||
//
|
||||
Range = NET_LIST_USER_STRUCT (Entry, MTFTP4_BLOCK_RANGE, Link);
|
||||
|
||||
if (Range->End < Num) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// There are three different cases for Start
|
||||
// 1. (Start > Num) && (End >= Num):
|
||||
// because all the holes before this one has the condition of
|
||||
// End < Num, so this block number has been removed.
|
||||
//
|
||||
// 2. (Start == Num) && (End >= Num):
|
||||
// Need to increase the Start by one, and if End == Num, this
|
||||
// hole has been removed completely, remove it.
|
||||
//
|
||||
// 3. (Start < Num) && (End >= Num):
|
||||
// if End == Num, only need to decrease the End by one because
|
||||
// we have (Start < Num) && (Num == End), so (Start <= End - 1).
|
||||
// if (End > Num), the hold is splited into two holes, with
|
||||
// [Start, Num - 1] and [Num + 1, End].
|
||||
//
|
||||
if (Range->Start > Num) {
|
||||
return EFI_NOT_FOUND;
|
||||
|
||||
} else if (Range->Start == Num) {
|
||||
Range->Start++;
|
||||
|
||||
//
|
||||
// Note that: RFC 1350 does not mention block counter roll-over,
|
||||
// but several TFTP hosts implement the roll-over be able to accept
|
||||
// transfers of unlimited size. There is no consensus, however, whether
|
||||
// the counter should wrap around to zero or to one. Many implementations
|
||||
// wrap to zero, because this is the simplest to implement. Here we choose
|
||||
// this solution.
|
||||
//
|
||||
*BlockCounter = Num;
|
||||
|
||||
if (Range->Round > 0) {
|
||||
*BlockCounter += Range->Bound + MultU64x32 ((UINTN) (Range->Round -1), (UINT32) (Range->Bound + 1)) + 1;
|
||||
}
|
||||
|
||||
if (Range->Start > Range->Bound) {
|
||||
Range->Start = 0;
|
||||
Range->Round ++;
|
||||
}
|
||||
|
||||
if ((Range->Start > Range->End) || Completed) {
|
||||
RemoveEntryList (&Range->Link);
|
||||
FreePool (Range);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
|
||||
} else {
|
||||
if (Range->End == Num) {
|
||||
Range->End--;
|
||||
} else {
|
||||
NewRange = Mtftp4AllocateRange ((UINT16) (Num + 1), (UINT16) Range->End);
|
||||
|
||||
if (NewRange == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Range->End = Num - 1;
|
||||
NetListInsertAfter (&Range->Link, &NewRange->Link);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Build then transmit the request packet for the MTFTP session.
|
||||
|
||||
@param Instance The Mtftp session
|
||||
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the request
|
||||
@retval EFI_SUCCESS The request is built and sent
|
||||
@retval Others Failed to transmit the packet.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4SendRequest (
|
||||
IN MTFTP4_PROTOCOL *Instance
|
||||
)
|
||||
{
|
||||
EFI_MTFTP4_PACKET *Packet;
|
||||
EFI_MTFTP4_OPTION *Options;
|
||||
EFI_MTFTP4_TOKEN *Token;
|
||||
RETURN_STATUS Status;
|
||||
NET_BUF *Nbuf;
|
||||
UINT8 *Mode;
|
||||
UINT8 *Cur;
|
||||
UINTN Index;
|
||||
UINT32 BufferLength;
|
||||
UINTN FileNameLength;
|
||||
UINTN ModeLength;
|
||||
UINTN OptionStrLength;
|
||||
UINTN ValueStrLength;
|
||||
|
||||
Token = Instance->Token;
|
||||
Options = Token->OptionList;
|
||||
Mode = Instance->Token->ModeStr;
|
||||
|
||||
if (Mode == NULL) {
|
||||
Mode = (UINT8 *) "octet";
|
||||
}
|
||||
|
||||
//
|
||||
// Compute the packet length
|
||||
//
|
||||
FileNameLength = AsciiStrLen ((CHAR8 *) Token->Filename);
|
||||
ModeLength = AsciiStrLen ((CHAR8 *) Mode);
|
||||
BufferLength = (UINT32) FileNameLength + (UINT32) ModeLength + 4;
|
||||
|
||||
for (Index = 0; Index < Token->OptionCount; Index++) {
|
||||
OptionStrLength = AsciiStrLen ((CHAR8 *) Options[Index].OptionStr);
|
||||
ValueStrLength = AsciiStrLen ((CHAR8 *) Options[Index].ValueStr);
|
||||
BufferLength += (UINT32) OptionStrLength + (UINT32) ValueStrLength + 2;
|
||||
}
|
||||
//
|
||||
// Allocate a packet then copy the data over
|
||||
//
|
||||
if ((Nbuf = NetbufAlloc (BufferLength)) == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Packet = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (Nbuf, BufferLength, FALSE);
|
||||
ASSERT (Packet != NULL);
|
||||
|
||||
Packet->OpCode = HTONS (Instance->Operation);
|
||||
BufferLength -= sizeof (Packet->OpCode);
|
||||
|
||||
Cur = Packet->Rrq.Filename;
|
||||
Status = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Token->Filename);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
BufferLength -= (UINT32) (FileNameLength + 1);
|
||||
Cur += FileNameLength + 1;
|
||||
Status = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Mode);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
BufferLength -= (UINT32) (ModeLength + 1);
|
||||
Cur += ModeLength + 1;
|
||||
|
||||
for (Index = 0; Index < Token->OptionCount; ++Index) {
|
||||
OptionStrLength = AsciiStrLen ((CHAR8 *) Options[Index].OptionStr);
|
||||
ValueStrLength = AsciiStrLen ((CHAR8 *) Options[Index].ValueStr);
|
||||
|
||||
Status = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Options[Index].OptionStr);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
BufferLength -= (UINT32) (OptionStrLength + 1);
|
||||
Cur += OptionStrLength + 1;
|
||||
|
||||
Status = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Options[Index].ValueStr);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
BufferLength -= (UINT32) (ValueStrLength + 1);
|
||||
Cur += ValueStrLength + 1;
|
||||
|
||||
}
|
||||
|
||||
return Mtftp4SendPacket (Instance, Nbuf);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Build then send an error message.
|
||||
|
||||
@param Instance The MTFTP session
|
||||
@param ErrCode The error code
|
||||
@param ErrInfo The error message
|
||||
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the error packet
|
||||
@retval EFI_SUCCESS The error packet is transmitted.
|
||||
@retval Others Failed to transmit the packet.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4SendError (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN UINT16 ErrCode,
|
||||
IN UINT8 *ErrInfo
|
||||
)
|
||||
{
|
||||
NET_BUF *Packet;
|
||||
EFI_MTFTP4_PACKET *TftpError;
|
||||
UINT32 Len;
|
||||
|
||||
Len = (UINT32) (AsciiStrLen ((CHAR8 *) ErrInfo) + sizeof (EFI_MTFTP4_ERROR_HEADER));
|
||||
Packet = NetbufAlloc (Len);
|
||||
if (Packet == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
TftpError = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (Packet, Len, FALSE);
|
||||
ASSERT (TftpError != NULL);
|
||||
|
||||
TftpError->OpCode = HTONS (EFI_MTFTP4_OPCODE_ERROR);
|
||||
TftpError->Error.ErrorCode = HTONS (ErrCode);
|
||||
|
||||
AsciiStrCpyS ((CHAR8 *) TftpError->Error.ErrorMessage, Len, (CHAR8 *) ErrInfo);
|
||||
|
||||
return Mtftp4SendPacket (Instance, Packet);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
The callback function called when the packet is transmitted.
|
||||
|
||||
It simply frees the packet.
|
||||
|
||||
@param Packet The transmitted (or failed to) packet
|
||||
@param EndPoint The local and remote UDP access point
|
||||
@param IoStatus The result of the transmission
|
||||
@param Context Opaque parameter to the callback
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
Mtftp4OnPacketSent (
|
||||
IN NET_BUF *Packet,
|
||||
IN UDP_END_POINT *EndPoint,
|
||||
IN EFI_STATUS IoStatus,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
NetbufFree (Packet);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Set the timeout for the instance. User a longer time for passive instances.
|
||||
|
||||
@param Instance The Mtftp session to set time out
|
||||
|
||||
**/
|
||||
VOID
|
||||
Mtftp4SetTimeout (
|
||||
IN OUT MTFTP4_PROTOCOL *Instance
|
||||
)
|
||||
{
|
||||
if (Instance->Master) {
|
||||
Instance->PacketToLive = Instance->Timeout;
|
||||
} else {
|
||||
Instance->PacketToLive = Instance->Timeout * 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Send the packet for the instance.
|
||||
|
||||
It will first save a reference to the packet for later retransmission.
|
||||
Then determine the destination port, listen port for requests, and connected
|
||||
port for others. At last, send the packet out.
|
||||
|
||||
@param Instance The Mtftp instance
|
||||
@param Packet The packet to send
|
||||
|
||||
@retval EFI_SUCCESS The packet is sent out
|
||||
@retval Others Failed to transmit the packet.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4SendPacket (
|
||||
IN OUT MTFTP4_PROTOCOL *Instance,
|
||||
IN OUT NET_BUF *Packet
|
||||
)
|
||||
{
|
||||
UDP_END_POINT UdpPoint;
|
||||
EFI_STATUS Status;
|
||||
UINT16 OpCode;
|
||||
UINT8 *Buffer;
|
||||
|
||||
//
|
||||
// Save the packet for retransmission
|
||||
//
|
||||
if (Instance->LastPacket != NULL) {
|
||||
NetbufFree (Instance->LastPacket);
|
||||
}
|
||||
|
||||
Instance->LastPacket = Packet;
|
||||
|
||||
Instance->CurRetry = 0;
|
||||
Mtftp4SetTimeout (Instance);
|
||||
|
||||
ZeroMem (&UdpPoint, sizeof (UdpPoint));
|
||||
UdpPoint.RemoteAddr.Addr[0] = Instance->ServerIp;
|
||||
|
||||
//
|
||||
// Send the requests to the listening port, other packets
|
||||
// to the connected port
|
||||
//
|
||||
Buffer = NetbufGetByte (Packet, 0, NULL);
|
||||
ASSERT (Buffer != NULL);
|
||||
OpCode = NTOHS (*(UINT16 *)Buffer);
|
||||
|
||||
if ((OpCode == EFI_MTFTP4_OPCODE_RRQ) ||
|
||||
(OpCode == EFI_MTFTP4_OPCODE_DIR) ||
|
||||
(OpCode == EFI_MTFTP4_OPCODE_WRQ)) {
|
||||
UdpPoint.RemotePort = Instance->ListeningPort;
|
||||
} else {
|
||||
UdpPoint.RemotePort = Instance->ConnectedPort;
|
||||
}
|
||||
|
||||
NET_GET_REF (Packet);
|
||||
|
||||
Status = UdpIoSendDatagram (
|
||||
Instance->UnicastPort,
|
||||
Packet,
|
||||
&UdpPoint,
|
||||
NULL,
|
||||
Mtftp4OnPacketSent,
|
||||
Instance
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
NET_PUT_REF (Packet);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Retransmit the last packet for the instance.
|
||||
|
||||
@param Instance The Mtftp instance
|
||||
|
||||
@retval EFI_SUCCESS The last packet is retransmitted.
|
||||
@retval Others Failed to retransmit.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4Retransmit (
|
||||
IN MTFTP4_PROTOCOL *Instance
|
||||
)
|
||||
{
|
||||
UDP_END_POINT UdpPoint;
|
||||
EFI_STATUS Status;
|
||||
UINT16 OpCode;
|
||||
UINT8 *Buffer;
|
||||
|
||||
ASSERT (Instance->LastPacket != NULL);
|
||||
|
||||
ZeroMem (&UdpPoint, sizeof (UdpPoint));
|
||||
UdpPoint.RemoteAddr.Addr[0] = Instance->ServerIp;
|
||||
|
||||
//
|
||||
// Set the requests to the listening port, other packets to the connected port
|
||||
//
|
||||
Buffer = NetbufGetByte (Instance->LastPacket, 0, NULL);
|
||||
ASSERT (Buffer != NULL);
|
||||
OpCode = NTOHS (*(UINT16 *) Buffer);
|
||||
|
||||
if ((OpCode == EFI_MTFTP4_OPCODE_RRQ) || (OpCode == EFI_MTFTP4_OPCODE_DIR) ||
|
||||
(OpCode == EFI_MTFTP4_OPCODE_WRQ)) {
|
||||
UdpPoint.RemotePort = Instance->ListeningPort;
|
||||
} else {
|
||||
UdpPoint.RemotePort = Instance->ConnectedPort;
|
||||
}
|
||||
|
||||
NET_GET_REF (Instance->LastPacket);
|
||||
|
||||
Status = UdpIoSendDatagram (
|
||||
Instance->UnicastPort,
|
||||
Instance->LastPacket,
|
||||
&UdpPoint,
|
||||
NULL,
|
||||
Mtftp4OnPacketSent,
|
||||
Instance
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
NET_PUT_REF (Instance->LastPacket);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
The timer ticking function in TPL_NOTIFY level for the Mtftp service instance.
|
||||
|
||||
@param Event The ticking event
|
||||
@param Context The Mtftp service instance
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
Mtftp4OnTimerTickNotifyLevel (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
MTFTP4_SERVICE *MtftpSb;
|
||||
LIST_ENTRY *Entry;
|
||||
LIST_ENTRY *Next;
|
||||
MTFTP4_PROTOCOL *Instance;
|
||||
|
||||
MtftpSb = (MTFTP4_SERVICE *) Context;
|
||||
|
||||
//
|
||||
// Iterate through all the children of the Mtftp service instance. Time
|
||||
// out the current packet transmit.
|
||||
//
|
||||
NET_LIST_FOR_EACH_SAFE (Entry, Next, &MtftpSb->Children) {
|
||||
Instance = NET_LIST_USER_STRUCT (Entry, MTFTP4_PROTOCOL, Link);
|
||||
if ((Instance->PacketToLive == 0) || (--Instance->PacketToLive > 0)) {
|
||||
Instance->HasTimeout = FALSE;
|
||||
} else {
|
||||
Instance->HasTimeout = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
The timer ticking function for the Mtftp service instance.
|
||||
|
||||
@param Event The ticking event
|
||||
@param Context The Mtftp service instance
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
Mtftp4OnTimerTick (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
MTFTP4_SERVICE *MtftpSb;
|
||||
LIST_ENTRY *Entry;
|
||||
LIST_ENTRY *Next;
|
||||
MTFTP4_PROTOCOL *Instance;
|
||||
EFI_MTFTP4_TOKEN *Token;
|
||||
|
||||
MtftpSb = (MTFTP4_SERVICE *) Context;
|
||||
|
||||
//
|
||||
// Iterate through all the children of the Mtftp service instance.
|
||||
//
|
||||
NET_LIST_FOR_EACH_SAFE (Entry, Next, &MtftpSb->Children) {
|
||||
Instance = NET_LIST_USER_STRUCT (Entry, MTFTP4_PROTOCOL, Link);
|
||||
if (!Instance->HasTimeout) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Instance->HasTimeout = FALSE;
|
||||
|
||||
//
|
||||
// Call the user's time out handler
|
||||
//
|
||||
Token = Instance->Token;
|
||||
|
||||
if (Token != NULL && Token->TimeoutCallback != NULL &&
|
||||
EFI_ERROR (Token->TimeoutCallback (&Instance->Mtftp4, Token))) {
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,
|
||||
(UINT8 *) "User aborted the transfer in time out"
|
||||
);
|
||||
|
||||
Mtftp4CleanOperation (Instance, EFI_ABORTED);
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// Retransmit the packet if haven't reach the maxmium retry count,
|
||||
// otherwise exit the transfer.
|
||||
//
|
||||
if (++Instance->CurRetry < Instance->MaxRetry) {
|
||||
Mtftp4Retransmit (Instance);
|
||||
Mtftp4SetTimeout (Instance);
|
||||
} else {
|
||||
Mtftp4CleanOperation (Instance, EFI_TIMEOUT);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
198
NetworkPkg/Mtftp4Dxe/Mtftp4Support.h
Normal file
198
NetworkPkg/Mtftp4Dxe/Mtftp4Support.h
Normal file
@@ -0,0 +1,198 @@
|
||||
/** @file
|
||||
Support routines for MTFTP.
|
||||
|
||||
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#ifndef __EFI_MTFTP4_SUPPORT_H__
|
||||
#define __EFI_MTFTP4_SUPPORT_H__
|
||||
|
||||
//
|
||||
// The structure representing a range of block numbers, [Start, End].
|
||||
// It is used to remember the holes in the MTFTP block space. If all
|
||||
// the holes are filled in, then the download or upload has completed.
|
||||
//
|
||||
typedef struct {
|
||||
LIST_ENTRY Link;
|
||||
INTN Start;
|
||||
INTN End;
|
||||
INTN Round;
|
||||
INTN Bound;
|
||||
} MTFTP4_BLOCK_RANGE;
|
||||
|
||||
|
||||
/**
|
||||
Initialize the block range for either RRQ or WRQ.
|
||||
|
||||
RRQ and WRQ have different requirements for Start and End.
|
||||
For example, during start up, WRQ initializes its whole valid block range
|
||||
to [0, 0xffff]. This is bacause the server will send us a ACK0 to inform us
|
||||
to start the upload. When the client received ACK0, it will remove 0 from the
|
||||
range, get the next block number, which is 1, then upload the BLOCK1. For RRQ
|
||||
without option negotiation, the server will directly send us the BLOCK1 in
|
||||
response to the client's RRQ. When received BLOCK1, the client will remove
|
||||
it from the block range and send an ACK. It also works if there is option
|
||||
negotiation.
|
||||
|
||||
@param Head The block range head to initialize
|
||||
@param Start The Start block number.
|
||||
@param End The last block number.
|
||||
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory for initial block range
|
||||
@retval EFI_SUCCESS The initial block range is created.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4InitBlockRange (
|
||||
IN LIST_ENTRY *Head,
|
||||
IN UINT16 Start,
|
||||
IN UINT16 End
|
||||
);
|
||||
|
||||
/**
|
||||
Get the first valid block number on the range list.
|
||||
|
||||
@param Head The block range head
|
||||
|
||||
@return The first valid block number, -1 if the block range is empty.
|
||||
|
||||
**/
|
||||
INTN
|
||||
Mtftp4GetNextBlockNum (
|
||||
IN LIST_ENTRY *Head
|
||||
);
|
||||
|
||||
/**
|
||||
Set the last block number of the block range list.
|
||||
|
||||
It will remove all the blocks after the Last. MTFTP initialize the block range
|
||||
to the maximum possible range, such as [0, 0xffff] for WRQ. When it gets the
|
||||
last block number, it will call this function to set the last block number.
|
||||
|
||||
@param Head The block range list
|
||||
@param Last The last block number
|
||||
|
||||
**/
|
||||
VOID
|
||||
Mtftp4SetLastBlockNum (
|
||||
IN LIST_ENTRY *Head,
|
||||
IN UINT16 Last
|
||||
);
|
||||
|
||||
/**
|
||||
Remove the block number from the block range list.
|
||||
|
||||
@param Head The block range list to remove from
|
||||
@param Num The block number to remove
|
||||
@param Completed Whether Num is the last block number.
|
||||
@param BlockCounter The continuous block counter instead of the value after roll-over.
|
||||
|
||||
@retval EFI_NOT_FOUND The block number isn't in the block range list
|
||||
@retval EFI_SUCCESS The block number has been removed from the list
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4RemoveBlockNum (
|
||||
IN LIST_ENTRY *Head,
|
||||
IN UINT16 Num,
|
||||
IN BOOLEAN Completed,
|
||||
OUT UINT64 *BlockCounter
|
||||
);
|
||||
|
||||
/**
|
||||
Set the timeout for the instance. User a longer time for passive instances.
|
||||
|
||||
@param Instance The Mtftp session to set time out
|
||||
|
||||
**/
|
||||
VOID
|
||||
Mtftp4SetTimeout (
|
||||
IN OUT MTFTP4_PROTOCOL *Instance
|
||||
);
|
||||
|
||||
/**
|
||||
Send the packet for the instance.
|
||||
|
||||
It will first save a reference to the packet for later retransmission.
|
||||
Then determine the destination port, listen port for requests, and connected
|
||||
port for others. At last, send the packet out.
|
||||
|
||||
@param Instance The Mtftp instance
|
||||
@param Packet The packet to send
|
||||
|
||||
@retval EFI_SUCCESS The packet is sent out
|
||||
@retval Others Failed to transmit the packet.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4SendPacket (
|
||||
IN OUT MTFTP4_PROTOCOL *Instance,
|
||||
IN OUT NET_BUF *Packet
|
||||
);
|
||||
|
||||
/**
|
||||
Build then transmit the request packet for the MTFTP session.
|
||||
|
||||
@param Instance The Mtftp session
|
||||
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the request
|
||||
@retval EFI_SUCCESS The request is built and sent
|
||||
@retval Others Failed to transmit the packet.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4SendRequest (
|
||||
IN MTFTP4_PROTOCOL *Instance
|
||||
);
|
||||
|
||||
/**
|
||||
Build then send an error message.
|
||||
|
||||
@param Instance The MTFTP session
|
||||
@param ErrCode The error code
|
||||
@param ErrInfo The error message
|
||||
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the error packet
|
||||
@retval EFI_SUCCESS The error packet is transmitted.
|
||||
@retval Others Failed to transmit the packet.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4SendError (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN UINT16 ErrCode,
|
||||
IN UINT8 *ErrInfo
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
The timer ticking function in TPL_NOTIFY level for the Mtftp service instance.
|
||||
|
||||
@param Event The ticking event
|
||||
@param Context The Mtftp service instance
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
Mtftp4OnTimerTickNotifyLevel (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
);
|
||||
|
||||
/**
|
||||
The timer ticking function for the Mtftp service instance.
|
||||
|
||||
@param Event The ticking event
|
||||
@param Context The Mtftp service instance
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
Mtftp4OnTimerTick (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
);
|
||||
#endif
|
529
NetworkPkg/Mtftp4Dxe/Mtftp4Wrq.c
Normal file
529
NetworkPkg/Mtftp4Dxe/Mtftp4Wrq.c
Normal file
@@ -0,0 +1,529 @@
|
||||
/** @file
|
||||
Routines to process Wrq (upload).
|
||||
|
||||
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#include "Mtftp4Impl.h"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Build then send a MTFTP data packet for the MTFTP upload session.
|
||||
|
||||
@param Instance The MTFTP upload session.
|
||||
@param BlockNum The block number to send.
|
||||
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to build the packet.
|
||||
@retval EFI_ABORTED The consumer of this child directs to abort the
|
||||
transmission by return an error through PacketNeeded.
|
||||
@retval EFI_SUCCESS The data is sent.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4WrqSendBlock (
|
||||
IN OUT MTFTP4_PROTOCOL *Instance,
|
||||
IN UINT16 BlockNum
|
||||
)
|
||||
{
|
||||
EFI_MTFTP4_PACKET *Packet;
|
||||
EFI_MTFTP4_TOKEN *Token;
|
||||
NET_BUF *UdpPacket;
|
||||
EFI_STATUS Status;
|
||||
UINT16 DataLen;
|
||||
UINT8 *DataBuf;
|
||||
UINT64 Start;
|
||||
|
||||
//
|
||||
// Allocate a buffer to hold the user data
|
||||
//
|
||||
UdpPacket = NetbufAlloc (Instance->BlkSize + MTFTP4_DATA_HEAD_LEN);
|
||||
|
||||
if (UdpPacket == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Packet = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (UdpPacket, MTFTP4_DATA_HEAD_LEN, FALSE);
|
||||
ASSERT (Packet != NULL);
|
||||
|
||||
Packet->Data.OpCode = HTONS (EFI_MTFTP4_OPCODE_DATA);
|
||||
Packet->Data.Block = HTONS (BlockNum);
|
||||
|
||||
//
|
||||
// Read the block from either the buffer or PacketNeeded callback
|
||||
//
|
||||
Token = Instance->Token;
|
||||
DataLen = Instance->BlkSize;
|
||||
|
||||
if (Token->Buffer != NULL) {
|
||||
Start = MultU64x32 (BlockNum - 1, Instance->BlkSize);
|
||||
|
||||
if (Token->BufferSize < Start + Instance->BlkSize) {
|
||||
DataLen = (UINT16) (Token->BufferSize - Start);
|
||||
Instance->LastBlock = BlockNum;
|
||||
Mtftp4SetLastBlockNum (&Instance->Blocks, BlockNum);
|
||||
}
|
||||
|
||||
if (DataLen > 0) {
|
||||
NetbufAllocSpace (UdpPacket, DataLen, FALSE);
|
||||
CopyMem (Packet->Data.Data, (UINT8 *) Token->Buffer + Start, DataLen);
|
||||
}
|
||||
|
||||
} else {
|
||||
//
|
||||
// Get data from PacketNeeded
|
||||
//
|
||||
DataBuf = NULL;
|
||||
Status = Token->PacketNeeded (
|
||||
&Instance->Mtftp4,
|
||||
Token,
|
||||
&DataLen,
|
||||
(VOID **) &DataBuf
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status) || (DataLen > Instance->BlkSize)) {
|
||||
if (DataBuf != NULL) {
|
||||
FreePool (DataBuf);
|
||||
}
|
||||
|
||||
if (UdpPacket != NULL) {
|
||||
NetbufFree (UdpPacket);
|
||||
}
|
||||
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,
|
||||
(UINT8 *) "User aborted the transfer"
|
||||
);
|
||||
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
if (DataLen < Instance->BlkSize) {
|
||||
Instance->LastBlock = BlockNum;
|
||||
Mtftp4SetLastBlockNum (&Instance->Blocks, BlockNum);
|
||||
}
|
||||
|
||||
if (DataLen > 0) {
|
||||
NetbufAllocSpace (UdpPacket, DataLen, FALSE);
|
||||
CopyMem (Packet->Data.Data, DataBuf, DataLen);
|
||||
FreePool (DataBuf);
|
||||
}
|
||||
}
|
||||
|
||||
return Mtftp4SendPacket (Instance, UdpPacket);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Function to handle received ACK packet.
|
||||
|
||||
If the ACK number matches the expected block number, and there are more
|
||||
data pending, send the next block. Otherwise tell the caller that we are done.
|
||||
|
||||
@param Instance The MTFTP upload session
|
||||
@param Packet The MTFTP packet received
|
||||
@param Len The packet length
|
||||
@param Completed Return whether the upload has finished.
|
||||
|
||||
@retval EFI_SUCCESS The ACK is successfully processed.
|
||||
@retval EFI_TFTP_ERROR The block number loops back.
|
||||
@retval Others Failed to transmit the next data packet.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4WrqHandleAck (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN EFI_MTFTP4_PACKET *Packet,
|
||||
IN UINT32 Len,
|
||||
OUT BOOLEAN *Completed
|
||||
)
|
||||
{
|
||||
UINT16 AckNum;
|
||||
INTN Expected;
|
||||
UINT64 BlockCounter;
|
||||
|
||||
*Completed = FALSE;
|
||||
AckNum = NTOHS (Packet->Ack.Block[0]);
|
||||
Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
|
||||
|
||||
ASSERT (Expected >= 0);
|
||||
|
||||
//
|
||||
// Get an unwanted ACK, return EFI_SUCCESS to let Mtftp4WrqInput
|
||||
// restart receive.
|
||||
//
|
||||
if (Expected != AckNum) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// Remove the acked block number, if this is the last block number,
|
||||
// tell the Mtftp4WrqInput to finish the transfer. This is the last
|
||||
// block number if the block range are empty.
|
||||
//
|
||||
Mtftp4RemoveBlockNum (&Instance->Blocks, AckNum, *Completed, &BlockCounter);
|
||||
|
||||
Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
|
||||
|
||||
if (Expected < 0) {
|
||||
|
||||
//
|
||||
// The block range is empty. It may either because the the last
|
||||
// block has been ACKed, or the sequence number just looped back,
|
||||
// that is, there is more than 0xffff blocks.
|
||||
//
|
||||
if (Instance->LastBlock == AckNum) {
|
||||
ASSERT (Instance->LastBlock >= 1);
|
||||
*Completed = TRUE;
|
||||
return EFI_SUCCESS;
|
||||
|
||||
} else {
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,
|
||||
(UINT8 *) "Block number rolls back, not supported, try blksize option"
|
||||
);
|
||||
|
||||
return EFI_TFTP_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return Mtftp4WrqSendBlock (Instance, (UINT16) Expected);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Check whether the received OACK is valid.
|
||||
|
||||
The OACK is valid only if:
|
||||
1. It only include options requested by us
|
||||
2. It can only include a smaller block size
|
||||
3. It can't change the proposed time out value.
|
||||
4. Other requirements of the individal MTFTP options as required.
|
||||
|
||||
@param Reply The options included in the OACK
|
||||
@param Request The options we requested
|
||||
|
||||
@retval TRUE The options included in OACK is valid.
|
||||
@retval FALSE The options included in OACK is invalid.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
Mtftp4WrqOackValid (
|
||||
IN MTFTP4_OPTION *Reply,
|
||||
IN MTFTP4_OPTION *Request
|
||||
)
|
||||
{
|
||||
//
|
||||
// It is invalid for server to return options we don't request
|
||||
//
|
||||
if ((Reply->Exist & ~Request->Exist) != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Server can only specify a smaller block size to be used and
|
||||
// return the timeout matches that requested.
|
||||
//
|
||||
if ((((Reply->Exist & MTFTP4_BLKSIZE_EXIST) != 0) && (Reply->BlkSize > Request->BlkSize)) ||
|
||||
(((Reply->Exist & MTFTP4_TIMEOUT_EXIST) != 0) && (Reply->Timeout != Request->Timeout))) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Function to handle the MTFTP OACK packet.
|
||||
|
||||
It parses the packet's options, and update the internal states of the session.
|
||||
|
||||
@param Instance The MTFTP session
|
||||
@param Packet The received OACK packet
|
||||
@param Len The length of the packet
|
||||
@param Completed Whether the transmisson has completed. NOT used by
|
||||
this function.
|
||||
|
||||
@retval EFI_SUCCESS The OACK process is OK
|
||||
@retval EFI_TFTP_ERROR Some error occured, and the session reset.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4WrqHandleOack (
|
||||
IN OUT MTFTP4_PROTOCOL *Instance,
|
||||
IN EFI_MTFTP4_PACKET *Packet,
|
||||
IN UINT32 Len,
|
||||
OUT BOOLEAN *Completed
|
||||
)
|
||||
{
|
||||
MTFTP4_OPTION Reply;
|
||||
EFI_MTFTP4_PACKET Bogus;
|
||||
EFI_STATUS Status;
|
||||
INTN Expected;
|
||||
|
||||
*Completed = FALSE;
|
||||
|
||||
//
|
||||
// Ignore the OACK if already started the upload
|
||||
//
|
||||
Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
|
||||
|
||||
if (Expected != 0) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// Parse and validate the options from server
|
||||
//
|
||||
ZeroMem (&Reply, sizeof (MTFTP4_OPTION));
|
||||
Status = Mtftp4ParseOptionOack (Packet, Len, Instance->Operation, &Reply);
|
||||
|
||||
if (EFI_ERROR (Status) || !Mtftp4WrqOackValid (&Reply, &Instance->RequestOption)) {
|
||||
//
|
||||
// Don't send a MTFTP error packet when out of resource, it can
|
||||
// only make it worse.
|
||||
//
|
||||
if (Status != EFI_OUT_OF_RESOURCES) {
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,
|
||||
(UINT8 *) "Mal-formated OACK packet"
|
||||
);
|
||||
}
|
||||
|
||||
return EFI_TFTP_ERROR;
|
||||
}
|
||||
|
||||
if (Reply.BlkSize != 0) {
|
||||
Instance->BlkSize = Reply.BlkSize;
|
||||
}
|
||||
|
||||
if (Reply.Timeout != 0) {
|
||||
Instance->Timeout = Reply.Timeout;
|
||||
}
|
||||
|
||||
//
|
||||
// Build a bogus ACK0 packet then pass it to the Mtftp4WrqHandleAck,
|
||||
// which will start the transmission of the first data block.
|
||||
//
|
||||
Bogus.Ack.OpCode = HTONS (EFI_MTFTP4_OPCODE_ACK);
|
||||
Bogus.Ack.Block[0] = 0;
|
||||
|
||||
Status = Mtftp4WrqHandleAck (
|
||||
Instance,
|
||||
&Bogus,
|
||||
sizeof (EFI_MTFTP4_ACK_HEADER),
|
||||
Completed
|
||||
);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
The input process routine for MTFTP upload.
|
||||
|
||||
@param UdpPacket The received MTFTP packet.
|
||||
@param EndPoint The local/remote access point
|
||||
@param IoStatus The result of the packet receiving
|
||||
@param Context Opaque parameter for the callback, which is the
|
||||
MTFTP session.
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
Mtftp4WrqInput (
|
||||
IN NET_BUF *UdpPacket,
|
||||
IN UDP_END_POINT *EndPoint,
|
||||
IN EFI_STATUS IoStatus,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
MTFTP4_PROTOCOL *Instance;
|
||||
EFI_MTFTP4_PACKET *Packet;
|
||||
BOOLEAN Completed;
|
||||
EFI_STATUS Status;
|
||||
UINT32 Len;
|
||||
UINT16 Opcode;
|
||||
|
||||
Instance = (MTFTP4_PROTOCOL *) Context;
|
||||
NET_CHECK_SIGNATURE (Instance, MTFTP4_PROTOCOL_SIGNATURE);
|
||||
|
||||
Completed = FALSE;
|
||||
Packet = NULL;
|
||||
Status = EFI_SUCCESS;
|
||||
|
||||
if (EFI_ERROR (IoStatus)) {
|
||||
Status = IoStatus;
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
ASSERT (UdpPacket != NULL);
|
||||
|
||||
if (UdpPacket->TotalSize < MTFTP4_OPCODE_LEN) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
//
|
||||
// Client send initial request to server's listening port. Server
|
||||
// will select a UDP port to communicate with the client.
|
||||
//
|
||||
if (EndPoint->RemotePort != Instance->ConnectedPort) {
|
||||
if (Instance->ConnectedPort != 0) {
|
||||
goto ON_EXIT;
|
||||
} else {
|
||||
Instance->ConnectedPort = EndPoint->RemotePort;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Copy the MTFTP packet to a continuous buffer if it isn't already so.
|
||||
//
|
||||
Len = UdpPacket->TotalSize;
|
||||
|
||||
if (UdpPacket->BlockOpNum > 1) {
|
||||
Packet = AllocatePool (Len);
|
||||
|
||||
if (Packet == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet);
|
||||
|
||||
} else {
|
||||
Packet = (EFI_MTFTP4_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);
|
||||
ASSERT (Packet != NULL);
|
||||
}
|
||||
|
||||
Opcode = NTOHS (Packet->OpCode);
|
||||
|
||||
//
|
||||
// Call the user's CheckPacket if provided. Abort the transmission
|
||||
// if CheckPacket returns an EFI_ERROR code.
|
||||
//
|
||||
if ((Instance->Token->CheckPacket != NULL) &&
|
||||
((Opcode == EFI_MTFTP4_OPCODE_OACK) || (Opcode == EFI_MTFTP4_OPCODE_ERROR))) {
|
||||
|
||||
Status = Instance->Token->CheckPacket (
|
||||
&Instance->Mtftp4,
|
||||
Instance->Token,
|
||||
(UINT16) Len,
|
||||
Packet
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
//
|
||||
// Send an error message to the server to inform it
|
||||
//
|
||||
if (Opcode != EFI_MTFTP4_OPCODE_ERROR) {
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,
|
||||
(UINT8 *) "User aborted the transfer"
|
||||
);
|
||||
}
|
||||
|
||||
Status = EFI_ABORTED;
|
||||
goto ON_EXIT;
|
||||
}
|
||||
}
|
||||
|
||||
switch (Opcode) {
|
||||
case EFI_MTFTP4_OPCODE_ACK:
|
||||
if (Len != MTFTP4_OPCODE_LEN + MTFTP4_BLKNO_LEN) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
Status = Mtftp4WrqHandleAck (Instance, Packet, Len, &Completed);
|
||||
break;
|
||||
|
||||
case EFI_MTFTP4_OPCODE_OACK:
|
||||
if (Len <= MTFTP4_OPCODE_LEN) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
Status = Mtftp4WrqHandleOack (Instance, Packet, Len, &Completed);
|
||||
break;
|
||||
|
||||
case EFI_MTFTP4_OPCODE_ERROR:
|
||||
Status = EFI_TFTP_ERROR;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ON_EXIT:
|
||||
//
|
||||
// Free the resources, then if !EFI_ERROR (Status) and not completed,
|
||||
// restart the receive, otherwise end the session.
|
||||
//
|
||||
if ((Packet != NULL) && (UdpPacket->BlockOpNum > 1)) {
|
||||
FreePool (Packet);
|
||||
}
|
||||
|
||||
if (UdpPacket != NULL) {
|
||||
NetbufFree (UdpPacket);
|
||||
}
|
||||
|
||||
if (!EFI_ERROR (Status) && !Completed) {
|
||||
Status = UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4WrqInput, Instance, 0);
|
||||
}
|
||||
|
||||
//
|
||||
// Status may have been updated by UdpIoRecvDatagram
|
||||
//
|
||||
if (EFI_ERROR (Status) || Completed) {
|
||||
Mtftp4CleanOperation (Instance, Status);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Start the MTFTP session for upload.
|
||||
|
||||
It will first init some states, then send the WRQ request packet,
|
||||
and start receiving the packet.
|
||||
|
||||
@param Instance The MTFTP session
|
||||
@param Operation Redundant parameter, which is always
|
||||
EFI_MTFTP4_OPCODE_WRQ here.
|
||||
|
||||
@retval EFI_SUCCESS The upload process has been started.
|
||||
@retval Others Failed to start the upload.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4WrqStart (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN UINT16 Operation
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
//
|
||||
// The valid block number range are [0, 0xffff]. For example:
|
||||
// the client sends an WRQ request to the server, the server
|
||||
// ACK with an ACK0 to let client start transfer the first
|
||||
// packet.
|
||||
//
|
||||
Status = Mtftp4InitBlockRange (&Instance->Blocks, 0, 0xffff);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = Mtftp4SendRequest (Instance);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
return UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4WrqInput, Instance, 0);
|
||||
}
|
||||
|
Reference in New Issue
Block a user