mirror of https://github.com/acidanthera/audk.git
724 lines
20 KiB
C
724 lines
20 KiB
C
/** @file
|
|
Implementation of Mtftp drivers.
|
|
|
|
Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php<BR>
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
**/
|
|
|
|
#include "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->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;
|
|
}
|
|
|
|
//
|
|
// 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->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->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->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;
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
}
|