mirror of https://github.com/acidanthera/audk.git
653 lines
18 KiB
C
653 lines
18 KiB
C
/** @file
|
|
|
|
Copyright (c) 2006 - 2008, Intel Corporation
|
|
All rights reserved. This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
|
|
Module Name:
|
|
|
|
Dhcp4Driver.c
|
|
|
|
Abstract:
|
|
|
|
|
|
**/
|
|
|
|
#include "Dhcp4Impl.h"
|
|
#include "Dhcp4Driver.h"
|
|
|
|
EFI_DRIVER_BINDING_PROTOCOL gDhcp4DriverBinding = {
|
|
Dhcp4DriverBindingSupported,
|
|
Dhcp4DriverBindingStart,
|
|
Dhcp4DriverBindingStop,
|
|
0xa,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
EFI_SERVICE_BINDING_PROTOCOL mDhcp4ServiceBindingTemplete = {
|
|
Dhcp4ServiceBindingCreateChild,
|
|
Dhcp4ServiceBindingDestroyChild
|
|
};
|
|
|
|
/**
|
|
Entry point of the DHCP driver to install various protocols.
|
|
|
|
@param ImageHandle The image handle of the driver.
|
|
@param SystemTable The system table.
|
|
|
|
@retval EFI_SUCCES if the driver binding and component name protocols are successfully
|
|
@retval Others Failed to install the protocols.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Dhcp4DriverEntryPoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
return EfiLibInstallDriverBindingComponentName2 (
|
|
ImageHandle,
|
|
SystemTable,
|
|
&gDhcp4DriverBinding,
|
|
ImageHandle,
|
|
&gDhcp4ComponentName,
|
|
&gDhcp4ComponentName2
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
Test to see if DHCP driver supports the ControllerHandle.
|
|
|
|
@param This Protocol instance pointer.
|
|
@param ControllerHandle Handle of device to test
|
|
@param RemainingDevicePath Optional parameter use to pick a specific child
|
|
device to start.
|
|
|
|
@retval EFI_SUCCES This driver supports this device
|
|
@retval other This driver does not support this device
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Dhcp4DriverBindingSupported (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = gBS->OpenProtocol (
|
|
ControllerHandle,
|
|
&gEfiUdp4ServiceBindingProtocolGuid,
|
|
NULL,
|
|
This->DriverBindingHandle,
|
|
ControllerHandle,
|
|
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
Configure the default UDP child to receive all the DHCP traffics
|
|
on this network interface.
|
|
|
|
@param UdpIo The UDP IO port to configure
|
|
@param Context The context to the function
|
|
|
|
@retval EFI_SUCCESS The UDP IO port is successfully configured.
|
|
@retval Others Failed to configure the UDP child.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
DhcpConfigUdpIo (
|
|
IN UDP_IO_PORT *UdpIo,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_UDP4_CONFIG_DATA UdpConfigData;
|
|
|
|
UdpConfigData.AcceptBroadcast = TRUE;
|
|
UdpConfigData.AcceptPromiscuous = FALSE;
|
|
UdpConfigData.AcceptAnyPort = FALSE;
|
|
UdpConfigData.AllowDuplicatePort = TRUE;
|
|
UdpConfigData.TypeOfService = 0;
|
|
UdpConfigData.TimeToLive = 64;
|
|
UdpConfigData.DoNotFragment = FALSE;
|
|
UdpConfigData.ReceiveTimeout = 0;
|
|
UdpConfigData.TransmitTimeout = 0;
|
|
|
|
UdpConfigData.UseDefaultAddress = FALSE;
|
|
UdpConfigData.StationPort = DHCP_CLIENT_PORT;
|
|
UdpConfigData.RemotePort = DHCP_SERVER_PORT;
|
|
|
|
ZeroMem (&UdpConfigData.StationAddress, sizeof (EFI_IPv4_ADDRESS));
|
|
ZeroMem (&UdpConfigData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
|
|
ZeroMem (&UdpConfigData.RemoteAddress, sizeof (EFI_IPv4_ADDRESS));
|
|
|
|
return UdpIo->Udp->Configure (UdpIo->Udp, &UdpConfigData);;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
Destory the DHCP service. The Dhcp4 service may be partly initialized,
|
|
or partly destoried. If a resource is destoried, it is marked as so in
|
|
case the destory failed and being called again later.
|
|
|
|
@param DhcpSb The DHCP service instance to destory.
|
|
|
|
@retval EFI_SUCCESS The DHCP service is successfully closed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Dhcp4CloseService (
|
|
IN DHCP_SERVICE *DhcpSb
|
|
)
|
|
{
|
|
DhcpCleanLease (DhcpSb);
|
|
|
|
if (DhcpSb->UdpIo != NULL) {
|
|
UdpIoFreePort (DhcpSb->UdpIo);
|
|
DhcpSb->UdpIo = NULL;
|
|
}
|
|
|
|
if (DhcpSb->Timer != NULL) {
|
|
gBS->SetTimer (DhcpSb->Timer, TimerCancel, 0);
|
|
gBS->CloseEvent (DhcpSb->Timer);
|
|
|
|
DhcpSb->Timer = NULL;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
Create a new DHCP service binding instance for the controller.
|
|
|
|
@param Controller The controller to install DHCP service binding
|
|
protocol onto
|
|
@param ImageHandle The driver's image handle
|
|
@param Service The variable to receive the created DHCP service
|
|
instance.
|
|
|
|
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource .
|
|
@retval EFI_SUCCESS The DHCP service instance is created.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Dhcp4CreateService (
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_HANDLE ImageHandle,
|
|
OUT DHCP_SERVICE **Service
|
|
)
|
|
{
|
|
DHCP_SERVICE *DhcpSb;
|
|
EFI_STATUS Status;
|
|
|
|
*Service = NULL;
|
|
DhcpSb = AllocateZeroPool (sizeof (DHCP_SERVICE));
|
|
|
|
if (DhcpSb == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
DhcpSb->Signature = DHCP_SERVICE_SIGNATURE;
|
|
DhcpSb->ServiceBinding = mDhcp4ServiceBindingTemplete;
|
|
DhcpSb->ServiceState = DHCP_UNCONFIGED;
|
|
DhcpSb->InDestory = FALSE;
|
|
DhcpSb->Controller = Controller;
|
|
DhcpSb->Image = ImageHandle;
|
|
InitializeListHead (&DhcpSb->Children);
|
|
DhcpSb->DhcpState = Dhcp4Stopped;
|
|
DhcpSb->Xid = NET_RANDOM (NetRandomInitSeed ());
|
|
|
|
//
|
|
// Create various resources, UdpIo, Timer, and get Mac address
|
|
//
|
|
Status = gBS->CreateEvent (
|
|
EVT_NOTIFY_SIGNAL | EVT_TIMER,
|
|
TPL_CALLBACK,
|
|
DhcpOnTimerTick,
|
|
DhcpSb,
|
|
&DhcpSb->Timer
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
goto ON_ERROR;
|
|
}
|
|
|
|
DhcpSb->UdpIo = UdpIoCreatePort (Controller, ImageHandle, DhcpConfigUdpIo, NULL);
|
|
|
|
if (DhcpSb->UdpIo == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto ON_ERROR;
|
|
}
|
|
|
|
DhcpSb->HwLen = (UINT8) DhcpSb->UdpIo->SnpMode.HwAddressSize;
|
|
DhcpSb->HwType = DhcpSb->UdpIo->SnpMode.IfType;
|
|
CopyMem (&DhcpSb->Mac, &DhcpSb->UdpIo->SnpMode.CurrentAddress, sizeof (DhcpSb->Mac));
|
|
|
|
*Service = DhcpSb;
|
|
return EFI_SUCCESS;
|
|
|
|
ON_ERROR:
|
|
Dhcp4CloseService (DhcpSb);
|
|
gBS->FreePool (DhcpSb);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Start this driver on ControllerHandle.
|
|
|
|
@param This Protocol instance pointer.
|
|
@param ControllerHandle Handle of device to bind driver to
|
|
@param RemainingDevicePath Optional parameter use to pick a specific child
|
|
device to start.
|
|
|
|
@retval EFI_SUCCES This driver is added to ControllerHandle
|
|
@retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
|
|
@retval other This driver does not support this device
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Dhcp4DriverBindingStart (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
|
|
)
|
|
{
|
|
DHCP_SERVICE *DhcpSb;
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// First: test for the DHCP4 Protocol
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
ControllerHandle,
|
|
&gEfiDhcp4ServiceBindingProtocolGuid,
|
|
NULL,
|
|
This->DriverBindingHandle,
|
|
ControllerHandle,
|
|
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
|
|
);
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
return EFI_ALREADY_STARTED;
|
|
}
|
|
|
|
Status = Dhcp4CreateService (ControllerHandle, This->DriverBindingHandle, &DhcpSb);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = gBS->SetTimer (DhcpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
goto ON_ERROR;
|
|
}
|
|
|
|
//
|
|
// Install the Dhcp4ServiceBinding Protocol onto ControlerHandle
|
|
//
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&ControllerHandle,
|
|
&gEfiDhcp4ServiceBindingProtocolGuid,
|
|
&DhcpSb->ServiceBinding,
|
|
NULL
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
goto ON_ERROR;
|
|
}
|
|
|
|
return Status;
|
|
|
|
ON_ERROR:
|
|
Dhcp4CloseService (DhcpSb);
|
|
gBS->FreePool (DhcpSb);
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Stop this driver on ControllerHandle.
|
|
|
|
@param This Protocol instance pointer.
|
|
@param ControllerHandle Handle of device to stop driver on
|
|
@param NumberOfChildren Number of Handles in ChildHandleBuffer. If number
|
|
of children is zero stop the entire bus driver.
|
|
@param ChildHandleBuffer List of Child Handles to Stop.
|
|
|
|
@retval EFI_SUCCES This driver is removed ControllerHandle
|
|
@retval other This driver was not removed from this device
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Dhcp4DriverBindingStop (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN UINTN NumberOfChildren,
|
|
IN EFI_HANDLE *ChildHandleBuffer
|
|
)
|
|
{
|
|
EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
|
|
DHCP_SERVICE *DhcpSb;
|
|
DHCP_PROTOCOL *Instance;
|
|
EFI_HANDLE NicHandle;
|
|
EFI_STATUS Status;
|
|
EFI_TPL OldTpl;
|
|
|
|
//
|
|
// DHCP driver opens UDP child, So, the ControllerHandle is the
|
|
// UDP child handle. locate the Nic handle first.
|
|
//
|
|
NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiUdp4ProtocolGuid);
|
|
|
|
if (NicHandle == NULL) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
Status = gBS->OpenProtocol (
|
|
NicHandle,
|
|
&gEfiDhcp4ServiceBindingProtocolGuid,
|
|
(VOID **) &ServiceBinding,
|
|
This->DriverBindingHandle,
|
|
NicHandle,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
DhcpSb = DHCP_SERVICE_FROM_THIS (ServiceBinding);
|
|
|
|
if (DhcpSb->InDestory) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
|
|
|
if (NumberOfChildren == 0) {
|
|
|
|
DhcpSb->InDestory = TRUE;
|
|
DhcpSb->ServiceState = DHCP_DESTORY;
|
|
|
|
gBS->UninstallProtocolInterface (
|
|
NicHandle,
|
|
&gEfiDhcp4ServiceBindingProtocolGuid,
|
|
ServiceBinding
|
|
);
|
|
|
|
Dhcp4CloseService (DhcpSb);
|
|
|
|
gBS->FreePool (DhcpSb);
|
|
} else {
|
|
//
|
|
// Don't use NET_LIST_FOR_EACH_SAFE here, Dhcp4ServiceBindingDestoryChild
|
|
// may cause other child to be deleted.
|
|
//
|
|
while (!IsListEmpty (&DhcpSb->Children)) {
|
|
Instance = NET_LIST_HEAD (&DhcpSb->Children, DHCP_PROTOCOL, Link);
|
|
ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);
|
|
}
|
|
|
|
if (DhcpSb->NumChildren != 0) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
}
|
|
}
|
|
|
|
gBS->RestoreTPL (OldTpl);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Initialize a new DHCP child.
|
|
|
|
@param DhcpSb The dhcp service instance
|
|
@param Instance The dhcp instance to initialize
|
|
|
|
@return None
|
|
|
|
**/
|
|
VOID
|
|
DhcpInitProtocol (
|
|
IN DHCP_SERVICE *DhcpSb,
|
|
IN DHCP_PROTOCOL *Instance
|
|
)
|
|
{
|
|
Instance->Signature = DHCP_PROTOCOL_SIGNATURE;
|
|
CopyMem (&Instance->Dhcp4Protocol, &mDhcp4ProtocolTemplate, sizeof (Instance->Dhcp4Protocol));
|
|
InitializeListHead (&Instance->Link);
|
|
Instance->Handle = NULL;
|
|
Instance->Service = DhcpSb;
|
|
Instance->InDestory = FALSE;
|
|
Instance->CompletionEvent = NULL;
|
|
Instance->RenewRebindEvent = NULL;
|
|
Instance->Token = NULL;
|
|
Instance->UdpIo = NULL;
|
|
NetbufQueInit (&Instance->ResponseQueue);
|
|
}
|
|
|
|
|
|
/**
|
|
Creates a child handle with a set of DHCP4 services.
|
|
|
|
@param This Protocol instance pointer.
|
|
@param ChildHandle Pointer to the handle of the child to create. If
|
|
it is NULL, then a new handle is created. If it
|
|
is not NULL, then the DHCP4 services are added to
|
|
the existing child handle.
|
|
|
|
@retval EFI_SUCCES The child handle was created with the DHCP4
|
|
services
|
|
@retval EFI_OUT_OF_RESOURCES There are not enough resources to create the child
|
|
@retval other The child handle was not created
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Dhcp4ServiceBindingCreateChild (
|
|
IN EFI_SERVICE_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE *ChildHandle
|
|
)
|
|
{
|
|
DHCP_SERVICE *DhcpSb;
|
|
DHCP_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;
|
|
}
|
|
|
|
DhcpSb = DHCP_SERVICE_FROM_THIS (This);
|
|
DhcpInitProtocol (DhcpSb, Instance);
|
|
|
|
//
|
|
// Install DHCP4 onto ChildHandle
|
|
//
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
ChildHandle,
|
|
&gEfiDhcp4ProtocolGuid,
|
|
&Instance->Dhcp4Protocol,
|
|
NULL
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->FreePool (Instance);
|
|
return Status;
|
|
}
|
|
|
|
Instance->Handle = *ChildHandle;
|
|
|
|
//
|
|
// Open the Udp4 protocol BY_CHILD.
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
DhcpSb->UdpIo->UdpHandle,
|
|
&gEfiUdp4ProtocolGuid,
|
|
(VOID **) &Udp4,
|
|
gDhcp4DriverBinding.DriverBindingHandle,
|
|
Instance->Handle,
|
|
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->UninstallMultipleProtocolInterfaces (
|
|
Instance->Handle,
|
|
&gEfiDhcp4ProtocolGuid,
|
|
&Instance->Dhcp4Protocol,
|
|
NULL
|
|
);
|
|
|
|
gBS->FreePool (Instance);
|
|
return Status;
|
|
}
|
|
|
|
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
|
|
|
InsertTailList (&DhcpSb->Children, &Instance->Link);
|
|
DhcpSb->NumChildren++;
|
|
|
|
gBS->RestoreTPL (OldTpl);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Destroys a child handle with a set of DHCP4 services.
|
|
|
|
@param This Protocol instance pointer.
|
|
@param ChildHandle Handle of the child to destroy
|
|
|
|
@retval EFI_SUCCES The DHCP4 service is removed from the child handle
|
|
@retval EFI_UNSUPPORTED The child handle does not support the DHCP4
|
|
service
|
|
@retval EFI_INVALID_PARAMETER Child handle is not a valid EFI Handle.
|
|
@retval EFI_ACCESS_DENIED The child handle could not be destroyed because
|
|
its DHCP4 services are being used.
|
|
@retval other The child handle was not destroyed
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Dhcp4ServiceBindingDestroyChild (
|
|
IN EFI_SERVICE_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE ChildHandle
|
|
)
|
|
{
|
|
DHCP_SERVICE *DhcpSb;
|
|
DHCP_PROTOCOL *Instance;
|
|
EFI_DHCP4_PROTOCOL *Dhcp;
|
|
EFI_TPL OldTpl;
|
|
EFI_STATUS Status;
|
|
|
|
if ((This == NULL) || (ChildHandle == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Retrieve the private context data structures
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
ChildHandle,
|
|
&gEfiDhcp4ProtocolGuid,
|
|
(VOID **) &Dhcp,
|
|
gDhcp4DriverBinding.DriverBindingHandle,
|
|
ChildHandle,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Instance = DHCP_INSTANCE_FROM_THIS (Dhcp);
|
|
DhcpSb = DHCP_SERVICE_FROM_THIS (This);
|
|
|
|
if (Instance->Service != DhcpSb) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// A child can be destoried more than once. For example,
|
|
// Dhcp4DriverBindingStop will destory all of its children.
|
|
// when caller driver is being stopped, it will destory the
|
|
// dhcp child it opens.
|
|
//
|
|
if (Instance->InDestory) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
|
Instance->InDestory = TRUE;
|
|
|
|
//
|
|
// Close the Udp4 protocol.
|
|
//
|
|
gBS->CloseProtocol (
|
|
DhcpSb->UdpIo->UdpHandle,
|
|
&gEfiUdp4ProtocolGuid,
|
|
gDhcp4DriverBinding.DriverBindingHandle,
|
|
ChildHandle
|
|
);
|
|
|
|
//
|
|
// Uninstall the DHCP4 protocol first to enable a top down destruction.
|
|
//
|
|
Status = gBS->UninstallProtocolInterface (
|
|
ChildHandle,
|
|
&gEfiDhcp4ProtocolGuid,
|
|
Dhcp
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
Instance->InDestory = FALSE;
|
|
|
|
gBS->RestoreTPL (OldTpl);
|
|
return Status;
|
|
}
|
|
|
|
if (DhcpSb->ActiveChild == Instance) {
|
|
DhcpYieldControl (DhcpSb);
|
|
}
|
|
|
|
RemoveEntryList (&Instance->Link);
|
|
DhcpSb->NumChildren--;
|
|
|
|
gBS->RestoreTPL (OldTpl);
|
|
|
|
gBS->FreePool (Instance);
|
|
return EFI_SUCCESS;
|
|
}
|