+++ /dev/null
-/** @file\r
-\r
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
-SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-#include "Dhcp4Impl.h"\r
-#include "Dhcp4Driver.h"\r
-\r
-EFI_DRIVER_BINDING_PROTOCOL gDhcp4DriverBinding = {\r
- Dhcp4DriverBindingSupported,\r
- Dhcp4DriverBindingStart,\r
- Dhcp4DriverBindingStop,\r
- 0xa,\r
- NULL,\r
- NULL\r
-};\r
-\r
-EFI_SERVICE_BINDING_PROTOCOL mDhcp4ServiceBindingTemplate = {\r
- Dhcp4ServiceBindingCreateChild,\r
- Dhcp4ServiceBindingDestroyChild\r
-};\r
-\r
-/**\r
- This is the declaration of an EFI image entry point. This entry point is\r
- the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including\r
- both device drivers and bus drivers.\r
-\r
- Entry point of the DHCP driver to install various protocols.\r
-\r
- @param[in] ImageHandle The firmware allocated handle for the UEFI image.\r
- @param[in] SystemTable A pointer to the EFI System Table.\r
-\r
- @retval EFI_SUCCESS The operation completed successfully.\r
- @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-Dhcp4DriverEntryPoint (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-{\r
- return EfiLibInstallDriverBindingComponentName2 (\r
- ImageHandle,\r
- SystemTable,\r
- &gDhcp4DriverBinding,\r
- ImageHandle,\r
- &gDhcp4ComponentName,\r
- &gDhcp4ComponentName2\r
- );\r
-}\r
-\r
-\r
-/**\r
- Test to see if this driver supports ControllerHandle. This service\r
- is called by the EFI boot service ConnectController(). In\r
- order to make drivers as small as possible, there are a few calling\r
- restrictions for this service. ConnectController() must\r
- follow these calling restrictions. If any other agent wishes to call\r
- Supported() it must also follow these calling restrictions.\r
-\r
- @param[in] This Protocol instance pointer.\r
- @param[in] ControllerHandle Handle of device to test\r
- @param[in] RemainingDevicePath Optional parameter use to pick a specific child\r
- device to start.\r
-\r
- @retval EFI_SUCCESS This driver supports this device\r
- @retval EFI_ALREADY_STARTED This driver is already running on this device\r
- @retval other This driver does not support this device\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-Dhcp4DriverBindingSupported (\r
- IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
- IN EFI_HANDLE ControllerHandle,\r
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
- )\r
-{\r
- EFI_STATUS Status;\r
-\r
- Status = gBS->OpenProtocol (\r
- ControllerHandle,\r
- &gEfiUdp4ServiceBindingProtocolGuid,\r
- NULL,\r
- This->DriverBindingHandle,\r
- ControllerHandle,\r
- EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
- );\r
-\r
- return Status;\r
-}\r
-\r
-\r
-\r
-/**\r
- Configure the default UDP child to receive all the DHCP traffics\r
- on this network interface.\r
-\r
- @param[in] UdpIo The UDP IO to configure\r
- @param[in] Context The context to the function\r
-\r
- @retval EFI_SUCCESS The UDP IO is successfully configured.\r
- @retval Others Failed to configure the UDP child.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-DhcpConfigUdpIo (\r
- IN UDP_IO *UdpIo,\r
- IN VOID *Context\r
- )\r
-{\r
- EFI_UDP4_CONFIG_DATA UdpConfigData;\r
-\r
- UdpConfigData.AcceptBroadcast = TRUE;\r
- UdpConfigData.AcceptPromiscuous = FALSE;\r
- UdpConfigData.AcceptAnyPort = FALSE;\r
- UdpConfigData.AllowDuplicatePort = TRUE;\r
- UdpConfigData.TypeOfService = 0;\r
- UdpConfigData.TimeToLive = 64;\r
- UdpConfigData.DoNotFragment = FALSE;\r
- UdpConfigData.ReceiveTimeout = 0;\r
- UdpConfigData.TransmitTimeout = 0;\r
-\r
- UdpConfigData.UseDefaultAddress = FALSE;\r
- UdpConfigData.StationPort = DHCP_CLIENT_PORT;\r
- UdpConfigData.RemotePort = DHCP_SERVER_PORT;\r
-\r
- ZeroMem (&UdpConfigData.StationAddress, sizeof (EFI_IPv4_ADDRESS));\r
- ZeroMem (&UdpConfigData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
- ZeroMem (&UdpConfigData.RemoteAddress, sizeof (EFI_IPv4_ADDRESS));\r
-\r
- return UdpIo->Protocol.Udp4->Configure (UdpIo->Protocol.Udp4, &UdpConfigData);;\r
-}\r
-\r
-\r
-\r
-/**\r
- Destroy the DHCP service. The Dhcp4 service may be partly initialized,\r
- or partly destroyed. If a resource is destroyed, it is marked as so in\r
- case the destroy failed and being called again later.\r
-\r
- @param[in] DhcpSb The DHCP service instance to destroy.\r
-\r
- @retval EFI_SUCCESS Always return success.\r
-\r
-**/\r
-EFI_STATUS\r
-Dhcp4CloseService (\r
- IN DHCP_SERVICE *DhcpSb\r
- )\r
-{\r
- DhcpCleanLease (DhcpSb);\r
-\r
- if (DhcpSb->UdpIo != NULL) {\r
- UdpIoFreeIo (DhcpSb->UdpIo);\r
- DhcpSb->UdpIo = NULL;\r
- }\r
-\r
- if (DhcpSb->Timer != NULL) {\r
- gBS->SetTimer (DhcpSb->Timer, TimerCancel, 0);\r
- gBS->CloseEvent (DhcpSb->Timer);\r
-\r
- DhcpSb->Timer = NULL;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-\r
-/**\r
- Create a new DHCP service binding instance for the controller.\r
-\r
- @param[in] Controller The controller to install DHCP service binding\r
- protocol onto\r
- @param[in] ImageHandle The driver's image handle\r
- @param[out] Service The variable to receive the created DHCP service\r
- instance.\r
-\r
- @retval EFI_OUT_OF_RESOURCES Failed to allocate resource .\r
- @retval EFI_SUCCESS The DHCP service instance is created.\r
- @retval other Other error occurs.\r
-\r
-**/\r
-EFI_STATUS\r
-Dhcp4CreateService (\r
- IN EFI_HANDLE Controller,\r
- IN EFI_HANDLE ImageHandle,\r
- OUT DHCP_SERVICE **Service\r
- )\r
-{\r
- DHCP_SERVICE *DhcpSb;\r
- EFI_STATUS Status;\r
-\r
- *Service = NULL;\r
- DhcpSb = AllocateZeroPool (sizeof (DHCP_SERVICE));\r
-\r
- if (DhcpSb == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- DhcpSb->Signature = DHCP_SERVICE_SIGNATURE;\r
- DhcpSb->ServiceState = DHCP_UNCONFIGED;\r
- DhcpSb->Controller = Controller;\r
- DhcpSb->Image = ImageHandle;\r
- InitializeListHead (&DhcpSb->Children);\r
- DhcpSb->DhcpState = Dhcp4Stopped;\r
- DhcpSb->Xid = NET_RANDOM (NetRandomInitSeed ());\r
- CopyMem (\r
- &DhcpSb->ServiceBinding,\r
- &mDhcp4ServiceBindingTemplate,\r
- sizeof (EFI_SERVICE_BINDING_PROTOCOL)\r
- );\r
- //\r
- // Create various resources, UdpIo, Timer, and get Mac address\r
- //\r
- Status = gBS->CreateEvent (\r
- EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
- TPL_CALLBACK,\r
- DhcpOnTimerTick,\r
- DhcpSb,\r
- &DhcpSb->Timer\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto ON_ERROR;\r
- }\r
-\r
- DhcpSb->UdpIo = UdpIoCreateIo (\r
- Controller,\r
- ImageHandle,\r
- DhcpConfigUdpIo,\r
- UDP_IO_UDP4_VERSION,\r
- NULL\r
- );\r
-\r
- if (DhcpSb->UdpIo == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto ON_ERROR;\r
- }\r
-\r
- DhcpSb->HwLen = (UINT8) DhcpSb->UdpIo->SnpMode.HwAddressSize;\r
- DhcpSb->HwType = DhcpSb->UdpIo->SnpMode.IfType;\r
- CopyMem (&DhcpSb->Mac, &DhcpSb->UdpIo->SnpMode.CurrentAddress, sizeof (DhcpSb->Mac));\r
-\r
- *Service = DhcpSb;\r
- return EFI_SUCCESS;\r
-\r
-ON_ERROR:\r
- Dhcp4CloseService (DhcpSb);\r
- FreePool (DhcpSb);\r
-\r
- return Status;\r
-}\r
-\r
-\r
-/**\r
- Start this driver on ControllerHandle. This service is called by the\r
- EFI boot service ConnectController(). In order to make\r
- drivers as small as possible, there are a few calling restrictions for\r
- this service. ConnectController() must follow these\r
- calling restrictions. If any other agent wishes to call Start() it\r
- must also follow these calling restrictions.\r
-\r
- @param[in] This Protocol instance pointer.\r
- @param[in] ControllerHandle Handle of device to bind driver to\r
- @param[in] RemainingDevicePath Optional parameter use to pick a specific child\r
- device to start.\r
-\r
- @retval EFI_SUCCESS This driver is added to ControllerHandle\r
- @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle\r
- @retval other This driver does not support this device\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-Dhcp4DriverBindingStart (\r
- IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
- IN EFI_HANDLE ControllerHandle,\r
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
- )\r
-{\r
- DHCP_SERVICE *DhcpSb;\r
- EFI_STATUS Status;\r
-\r
- //\r
- // First: test for the DHCP4 Protocol\r
- //\r
- Status = gBS->OpenProtocol (\r
- ControllerHandle,\r
- &gEfiDhcp4ServiceBindingProtocolGuid,\r
- NULL,\r
- This->DriverBindingHandle,\r
- ControllerHandle,\r
- EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
- );\r
-\r
- if (Status == EFI_SUCCESS) {\r
- return EFI_ALREADY_STARTED;\r
- }\r
-\r
- Status = Dhcp4CreateService (ControllerHandle, This->DriverBindingHandle, &DhcpSb);\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- ASSERT (DhcpSb != NULL);\r
-\r
- //\r
- // Start the receiving\r
- //\r
- Status = UdpIoRecvDatagram (DhcpSb->UdpIo, DhcpInput, DhcpSb, 0);\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto ON_ERROR;\r
- }\r
- Status = gBS->SetTimer (DhcpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto ON_ERROR;\r
- }\r
-\r
- //\r
- // Install the Dhcp4ServiceBinding Protocol onto ControlerHandle\r
- //\r
- Status = gBS->InstallMultipleProtocolInterfaces (\r
- &ControllerHandle,\r
- &gEfiDhcp4ServiceBindingProtocolGuid,\r
- &DhcpSb->ServiceBinding,\r
- NULL\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto ON_ERROR;\r
- }\r
-\r
- return Status;\r
-\r
-ON_ERROR:\r
- Dhcp4CloseService (DhcpSb);\r
- FreePool (DhcpSb);\r
- return Status;\r
-}\r
-\r
-/**\r
- Callback function which provided by user to remove one node in NetDestroyLinkList process.\r
-\r
- @param[in] Entry The entry to be removed.\r
- @param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList.\r
-\r
- @retval EFI_SUCCESS The entry has been removed successfully.\r
- @retval Others Fail to remove the entry.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-Dhcp4DestroyChildEntry (\r
- IN LIST_ENTRY *Entry,\r
- IN VOID *Context\r
- )\r
-{\r
- DHCP_PROTOCOL *Instance;\r
- EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;\r
-\r
- if (Entry == NULL || Context == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- Instance = NET_LIST_USER_STRUCT_S (Entry, DHCP_PROTOCOL, Link, DHCP_PROTOCOL_SIGNATURE);\r
- ServiceBinding = (EFI_SERVICE_BINDING_PROTOCOL *) Context;\r
-\r
- return ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);\r
-}\r
-\r
-\r
-/**\r
- Stop this driver on ControllerHandle. This service is called by the\r
- EFI boot service DisconnectController(). In order to\r
- make drivers as small as possible, there are a few calling\r
- restrictions for this service. DisconnectController()\r
- must follow these calling restrictions. If any other agent wishes\r
- to call Stop() it must also follow these calling restrictions.\r
-\r
- @param[in] This Protocol instance pointer.\r
- @param[in] ControllerHandle Handle of device to stop driver on\r
- @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of\r
- children is zero stop the entire bus driver.\r
- @param[in] ChildHandleBuffer List of Child Handles to Stop.\r
-\r
- @retval EFI_SUCCESS This driver is removed ControllerHandle\r
- @retval other This driver was not removed from this device\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-Dhcp4DriverBindingStop (\r
- IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
- IN EFI_HANDLE ControllerHandle,\r
- IN UINTN NumberOfChildren,\r
- IN EFI_HANDLE *ChildHandleBuffer\r
- )\r
-{\r
- EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;\r
- DHCP_SERVICE *DhcpSb;\r
- EFI_HANDLE NicHandle;\r
- EFI_STATUS Status;\r
- LIST_ENTRY *List;\r
- UINTN ListLength;\r
-\r
- //\r
- // DHCP driver opens UDP child, So, the ControllerHandle is the\r
- // UDP child handle. locate the Nic handle first.\r
- //\r
- NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiUdp4ProtocolGuid);\r
-\r
- if (NicHandle == NULL) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- Status = gBS->OpenProtocol (\r
- NicHandle,\r
- &gEfiDhcp4ServiceBindingProtocolGuid,\r
- (VOID **) &ServiceBinding,\r
- This->DriverBindingHandle,\r
- NicHandle,\r
- EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- DhcpSb = DHCP_SERVICE_FROM_THIS (ServiceBinding);\r
- if (!IsListEmpty (&DhcpSb->Children)) {\r
- //\r
- // Destroy all the children instances before destory the service.\r
- //\r
- List = &DhcpSb->Children;\r
- Status = NetDestroyLinkList (\r
- List,\r
- Dhcp4DestroyChildEntry,\r
- ServiceBinding,\r
- &ListLength\r
- );\r
- if (EFI_ERROR (Status) || ListLength != 0) {\r
- Status = EFI_DEVICE_ERROR;\r
- }\r
- }\r
-\r
- if (NumberOfChildren == 0 && !IsListEmpty (&DhcpSb->Children)) {\r
- Status = EFI_DEVICE_ERROR;\r
- }\r
-\r
- if (NumberOfChildren == 0 && IsListEmpty (&DhcpSb->Children)) {\r
- //\r
- // Destroy the service itself if no child instance left.\r
- //\r
- DhcpSb->ServiceState = DHCP_DESTROY;\r
-\r
- gBS->UninstallProtocolInterface (\r
- NicHandle,\r
- &gEfiDhcp4ServiceBindingProtocolGuid,\r
- ServiceBinding\r
- );\r
-\r
- Dhcp4CloseService (DhcpSb);\r
-\r
- if (gDhcpControllerNameTable != NULL) {\r
- FreeUnicodeStringTable (gDhcpControllerNameTable);\r
- gDhcpControllerNameTable = NULL;\r
- }\r
- FreePool (DhcpSb);\r
-\r
- Status = EFI_SUCCESS;\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-\r
-/**\r
- Initialize a new DHCP instance.\r
-\r
- @param DhcpSb The dhcp service instance\r
- @param Instance The dhcp instance to initialize\r
-\r
-**/\r
-VOID\r
-DhcpInitProtocol (\r
- IN DHCP_SERVICE *DhcpSb,\r
- IN OUT DHCP_PROTOCOL *Instance\r
- )\r
-{\r
- Instance->Signature = DHCP_PROTOCOL_SIGNATURE;\r
- CopyMem (&Instance->Dhcp4Protocol, &mDhcp4ProtocolTemplate, sizeof (Instance->Dhcp4Protocol));\r
- InitializeListHead (&Instance->Link);\r
- Instance->Handle = NULL;\r
- Instance->Service = DhcpSb;\r
- Instance->InDestroy = FALSE;\r
- Instance->CompletionEvent = NULL;\r
- Instance->RenewRebindEvent = NULL;\r
- Instance->Token = NULL;\r
- Instance->UdpIo = NULL;\r
- Instance->ElaspedTime = 0;\r
- NetbufQueInit (&Instance->ResponseQueue);\r
-}\r
-\r
-\r
-/**\r
- Creates a child handle and installs a protocol.\r
-\r
- The CreateChild() function installs a protocol on ChildHandle.\r
- If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.\r
- If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.\r
-\r
- @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.\r
- @param ChildHandle Pointer to the handle of the child to create. If it is NULL,\r
- then a new handle is created. If it is a pointer to an existing UEFI handle,\r
- then the protocol is added to the existing UEFI handle.\r
-\r
- @retval EFI_SUCCES The protocol was added to ChildHandle.\r
- @retval EFI_INVALID_PARAMETER ChildHandle is NULL.\r
- @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create\r
- the child\r
- @retval other The child handle was not created\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-Dhcp4ServiceBindingCreateChild (\r
- IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
- IN EFI_HANDLE *ChildHandle\r
- )\r
-{\r
- DHCP_SERVICE *DhcpSb;\r
- DHCP_PROTOCOL *Instance;\r
- EFI_STATUS Status;\r
- EFI_TPL OldTpl;\r
- VOID *Udp4;\r
-\r
- if ((This == NULL) || (ChildHandle == NULL)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- Instance = AllocatePool (sizeof (*Instance));\r
-\r
- if (Instance == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- DhcpSb = DHCP_SERVICE_FROM_THIS (This);\r
- DhcpInitProtocol (DhcpSb, Instance);\r
-\r
- //\r
- // Install DHCP4 onto ChildHandle\r
- //\r
- Status = gBS->InstallMultipleProtocolInterfaces (\r
- ChildHandle,\r
- &gEfiDhcp4ProtocolGuid,\r
- &Instance->Dhcp4Protocol,\r
- NULL\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- FreePool (Instance);\r
- return Status;\r
- }\r
-\r
- Instance->Handle = *ChildHandle;\r
-\r
- //\r
- // Open the Udp4 protocol BY_CHILD.\r
- //\r
- Status = gBS->OpenProtocol (\r
- DhcpSb->UdpIo->UdpHandle,\r
- &gEfiUdp4ProtocolGuid,\r
- (VOID **) &Udp4,\r
- gDhcp4DriverBinding.DriverBindingHandle,\r
- Instance->Handle,\r
- EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
- );\r
- if (EFI_ERROR (Status)) {\r
- gBS->UninstallMultipleProtocolInterfaces (\r
- Instance->Handle,\r
- &gEfiDhcp4ProtocolGuid,\r
- &Instance->Dhcp4Protocol,\r
- NULL\r
- );\r
-\r
- FreePool (Instance);\r
- return Status;\r
- }\r
-\r
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
-\r
- InsertTailList (&DhcpSb->Children, &Instance->Link);\r
- DhcpSb->NumChildren++;\r
-\r
- gBS->RestoreTPL (OldTpl);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Destroys a child handle with a protocol installed on it.\r
-\r
- The DestroyChild() function does the opposite of CreateChild(). It removes a protocol\r
- that was installed by CreateChild() from ChildHandle. If the removed protocol is the\r
- last protocol on ChildHandle, then ChildHandle is destroyed.\r
-\r
- @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.\r
- @param ChildHandle Handle of the child to destroy\r
-\r
- @retval EFI_SUCCES The protocol was removed from ChildHandle.\r
- @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.\r
- @retval EFI_INVALID_PARAMETER Child handle is NULL.\r
- @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle\r
- because its services are being used.\r
- @retval other The child handle was not destroyed\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-Dhcp4ServiceBindingDestroyChild (\r
- IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
- IN EFI_HANDLE ChildHandle\r
- )\r
-{\r
- DHCP_SERVICE *DhcpSb;\r
- DHCP_PROTOCOL *Instance;\r
- EFI_DHCP4_PROTOCOL *Dhcp;\r
- EFI_TPL OldTpl;\r
- EFI_STATUS Status;\r
-\r
- if ((This == NULL) || (ChildHandle == NULL)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Retrieve the private context data structures\r
- //\r
- Status = gBS->OpenProtocol (\r
- ChildHandle,\r
- &gEfiDhcp4ProtocolGuid,\r
- (VOID **) &Dhcp,\r
- gDhcp4DriverBinding.DriverBindingHandle,\r
- ChildHandle,\r
- EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- Instance = DHCP_INSTANCE_FROM_THIS (Dhcp);\r
- DhcpSb = DHCP_SERVICE_FROM_THIS (This);\r
-\r
- if (Instance->Service != DhcpSb) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // A child can be destroyed more than once. For example,\r
- // Dhcp4DriverBindingStop will destroy all of its children.\r
- // when caller driver is being stopped, it will destroy the\r
- // dhcp child it opens.\r
- //\r
- if (Instance->InDestroy) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
- Instance->InDestroy = TRUE;\r
-\r
- //\r
- // Close the Udp4 protocol.\r
- //\r
- gBS->CloseProtocol (\r
- DhcpSb->UdpIo->UdpHandle,\r
- &gEfiUdp4ProtocolGuid,\r
- gDhcp4DriverBinding.DriverBindingHandle,\r
- ChildHandle\r
- );\r
-\r
- //\r
- // Uninstall the DHCP4 protocol first to enable a top down destruction.\r
- //\r
- gBS->RestoreTPL (OldTpl);\r
- Status = gBS->UninstallProtocolInterface (\r
- ChildHandle,\r
- &gEfiDhcp4ProtocolGuid,\r
- Dhcp\r
- );\r
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
- if (EFI_ERROR (Status)) {\r
- Instance->InDestroy = FALSE;\r
-\r
- gBS->RestoreTPL (OldTpl);\r
- return Status;\r
- }\r
-\r
- if (DhcpSb->ActiveChild == Instance) {\r
- DhcpYieldControl (DhcpSb);\r
- }\r
-\r
- RemoveEntryList (&Instance->Link);\r
- DhcpSb->NumChildren--;\r
-\r
- if (Instance->UdpIo != NULL) {\r
- UdpIoCleanIo (Instance->UdpIo);\r
- gBS->CloseProtocol (\r
- Instance->UdpIo->UdpHandle,\r
- &gEfiUdp4ProtocolGuid,\r
- Instance->Service->Image,\r
- Instance->Handle\r
- );\r
- UdpIoFreeIo (Instance->UdpIo);\r
- Instance->UdpIo = NULL;\r
- Instance->Token = NULL;\r
- }\r
-\r
- gBS->RestoreTPL (OldTpl);\r
-\r
- FreePool (Instance);\r
- return EFI_SUCCESS;\r
-}\r