]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/UefiPxeBcDxe/PxeBcDriver.c
NetworkPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / NetworkPkg / UefiPxeBcDxe / PxeBcDriver.c
index 4abb6988f51dc125f84f5046b7bdbef04eb1690e..3c1d400d502ca63a08d07cbb96f90c6198498658 100644 (file)
@@ -1,37 +1,33 @@
 /** @file\r
   Driver Binding functions implementationfor for UefiPxeBc Driver.\r
 \r
-  Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.<BR>\r
+  (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
+  Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
 \r
-  This program and the accompanying materials\r
-  are licensed and made available under the terms and conditions of the BSD License\r
-  which accompanies this distribution.  The full text of the license may be found at\r
-  http://opensource.org/licenses/bsd-license.php.\r
-\r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include "PxeBcImpl.h"\r
 \r
 \r
-EFI_DRIVER_BINDING_PROTOCOL gPxeBcDriverBinding = {\r
-  PxeBcDriverBindingSupported,\r
-  PxeBcDriverBindingStart,\r
-  PxeBcDriverBindingStop,\r
+EFI_DRIVER_BINDING_PROTOCOL gPxeBcIp4DriverBinding = {\r
+  PxeBcIp4DriverBindingSupported,\r
+  PxeBcIp4DriverBindingStart,\r
+  PxeBcIp4DriverBindingStop,\r
   0xa,\r
   NULL,\r
   NULL\r
 };\r
 \r
-//\r
-// PXE_PRIVATE_GUID is only used to keep the relationship between \r
-// NIC handle and virtual child handles.\r
-//\r
-EFI_GUID mPxeBcPrivateGuid = PXEBC_PRIVATE_GUID;\r
-\r
-\r
+EFI_DRIVER_BINDING_PROTOCOL gPxeBcIp6DriverBinding = {\r
+  PxeBcIp6DriverBindingSupported,\r
+  PxeBcIp6DriverBindingStart,\r
+  PxeBcIp6DriverBindingStop,\r
+  0xa,\r
+  NULL,\r
+  NULL\r
+};\r
 \r
 /**\r
   Get the Nic handle using any child handle in the IPv4 stack.\r
@@ -237,7 +233,7 @@ PxeBcDestroyIp4Children (
     //\r
     gBS->CloseProtocol (\r
            Private->Controller,\r
-           &mPxeBcPrivateGuid,\r
+           &gEfiCallerIdGuid,\r
            This->DriverBindingHandle,\r
            Private->Ip4Nic->Controller\r
            );\r
@@ -252,8 +248,9 @@ PxeBcDestroyIp4Children (
            &Private->PxeBc,\r
            NULL\r
            );\r
+    FreePool (Private->Ip4Nic->DevicePath);\r
 \r
-    if (Private->Snp != NULL) { \r
+    if (Private->Snp != NULL) {\r
       //\r
       // Close SNP from the child virtual handle\r
       //\r
@@ -263,7 +260,7 @@ PxeBcDestroyIp4Children (
              This->DriverBindingHandle,\r
              Private->Ip4Nic->Controller\r
              );\r
-             \r
+\r
       gBS->UninstallProtocolInterface (\r
              Private->Ip4Nic->Controller,\r
              &gEfiSimpleNetworkProtocolGuid,\r
@@ -397,7 +394,7 @@ PxeBcDestroyIp6Children (
     //\r
     gBS->CloseProtocol (\r
            Private->Controller,\r
-           &mPxeBcPrivateGuid,\r
+           &gEfiCallerIdGuid,\r
            This->DriverBindingHandle,\r
            Private->Ip6Nic->Controller\r
            );\r
@@ -412,6 +409,8 @@ PxeBcDestroyIp6Children (
            &Private->PxeBc,\r
            NULL\r
            );\r
+    FreePool (Private->Ip6Nic->DevicePath);\r
+\r
     if (Private->Snp != NULL) {\r
       //\r
       // Close SNP from the child virtual handle\r
@@ -440,6 +439,103 @@ PxeBcDestroyIp6Children (
   Private->Mode.Ipv6Available = FALSE;\r
 }\r
 \r
+/**\r
+  Check whether UNDI protocol supports IPv6.\r
+\r
+  @param[in]   ControllerHandle  Controller handle.\r
+  @param[in]   Private           Pointer to PXEBC_PRIVATE_DATA.\r
+  @param[out]  Ipv6Support       TRUE if UNDI supports IPv6.\r
+\r
+  @retval EFI_SUCCESS            Get the result whether UNDI supports IPv6 by NII or AIP protocol successfully.\r
+  @retval EFI_NOT_FOUND          Don't know whether UNDI supports IPv6 since NII or AIP is not available.\r
+\r
+**/\r
+EFI_STATUS\r
+PxeBcCheckIpv6Support (\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  PXEBC_PRIVATE_DATA           *Private,\r
+  OUT BOOLEAN                      *Ipv6Support\r
+  )\r
+{\r
+  EFI_HANDLE                       Handle;\r
+  EFI_ADAPTER_INFORMATION_PROTOCOL *Aip;\r
+  EFI_STATUS                       Status;\r
+  EFI_GUID                         *InfoTypesBuffer;\r
+  UINTN                            InfoTypeBufferCount;\r
+  UINTN                            TypeIndex;\r
+  BOOLEAN                          Supported;\r
+  VOID                             *InfoBlock;\r
+  UINTN                            InfoBlockSize;\r
+\r
+  ASSERT (Private != NULL && Ipv6Support != NULL);\r
+\r
+  //\r
+  // Check whether the UNDI supports IPv6 by NII protocol.\r
+  //\r
+  if (Private->Nii != NULL) {\r
+    *Ipv6Support = Private->Nii->Ipv6Supported;\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Check whether the UNDI supports IPv6 by AIP protocol.\r
+  //\r
+\r
+  //\r
+  // Get the NIC handle by SNP protocol.\r
+  //\r
+  Handle = NetLibGetSnpHandle (ControllerHandle, NULL);\r
+  if (Handle == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  Aip    = NULL;\r
+  Status = gBS->HandleProtocol (\r
+                  Handle,\r
+                  &gEfiAdapterInformationProtocolGuid,\r
+                  (VOID *) &Aip\r
+                  );\r
+  if (EFI_ERROR (Status) || Aip == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  InfoTypesBuffer     = NULL;\r
+  InfoTypeBufferCount = 0;\r
+  Status = Aip->GetSupportedTypes (Aip, &InfoTypesBuffer, &InfoTypeBufferCount);\r
+  if (EFI_ERROR (Status) || InfoTypesBuffer == NULL) {\r
+    FreePool (InfoTypesBuffer);\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  Supported = FALSE;\r
+  for (TypeIndex = 0; TypeIndex < InfoTypeBufferCount; TypeIndex++) {\r
+    if (CompareGuid (&InfoTypesBuffer[TypeIndex], &gEfiAdapterInfoUndiIpv6SupportGuid)) {\r
+      Supported = TRUE;\r
+      break;\r
+    }\r
+  }\r
+\r
+  FreePool (InfoTypesBuffer);\r
+  if (!Supported) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // We now have adapter information block.\r
+  //\r
+  InfoBlock     = NULL;\r
+  InfoBlockSize = 0;\r
+  Status = Aip->GetInformation (Aip, &gEfiAdapterInfoUndiIpv6SupportGuid, &InfoBlock, &InfoBlockSize);\r
+  if (EFI_ERROR (Status) || InfoBlock == NULL) {\r
+    FreePool (InfoBlock);\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  *Ipv6Support = ((EFI_ADAPTER_INFO_UNDI_IPV6_SUPPORT *) InfoBlock)->Ipv6Support;\r
+  FreePool (InfoBlock);\r
+  return EFI_SUCCESS;\r
+\r
+}\r
 \r
 /**\r
   Create the opened instances based on IPv4.\r
@@ -643,6 +739,18 @@ PxeBcCreateIp4Children (
   Private->Ip4Nic->Private   = Private;\r
   Private->Ip4Nic->Signature = PXEBC_VIRTUAL_NIC_SIGNATURE;\r
 \r
+   //\r
+  // Locate Ip4->Ip4Config2 and store it for set IPv4 Policy.\r
+  //\r
+  Status = gBS->HandleProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiIp4Config2ProtocolGuid,\r
+                  (VOID **) &Private->Ip4Config2\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
   //\r
   // Create a device path node for Ipv4 virtual nic, and append it.\r
   //\r
@@ -700,7 +808,7 @@ PxeBcCreateIp4Children (
     }\r
 \r
     //\r
-    // Open SNP on the child handle BY_DRIVER. It will prevent any additionally \r
+    // Open SNP on the child handle BY_DRIVER|EXCLUSIVE. It will prevent any additionally\r
     // layering to perform the experiment.\r
     //\r
     Status = gBS->OpenProtocol (\r
@@ -709,7 +817,7 @@ PxeBcCreateIp4Children (
                     (VOID **) &Snp,\r
                     This->DriverBindingHandle,\r
                     Private->Ip4Nic->Controller,\r
-                    EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                    EFI_OPEN_PROTOCOL_BY_DRIVER|EFI_OPEN_PROTOCOL_EXCLUSIVE\r
                     );\r
     if (EFI_ERROR (Status)) {\r
       goto ON_ERROR;\r
@@ -722,7 +830,7 @@ PxeBcCreateIp4Children (
   //\r
   Status = gBS->OpenProtocol (\r
                   ControllerHandle,\r
-                  &mPxeBcPrivateGuid,\r
+                  &gEfiCallerIdGuid,\r
                   (VOID **) &Id,\r
                   This->DriverBindingHandle,\r
                   Private->Ip4Nic->Controller,\r
@@ -739,7 +847,7 @@ PxeBcCreateIp4Children (
   Udp4CfgData                     = &Private->Udp4CfgData;\r
   Ip4CfgData                      = &Private->Ip4CfgData;\r
 \r
-  Udp4CfgData->AcceptBroadcast    = TRUE;\r
+  Udp4CfgData->AcceptBroadcast    = FALSE;\r
   Udp4CfgData->AcceptAnyPort      = TRUE;\r
   Udp4CfgData->AllowDuplicatePort = TRUE;\r
   Udp4CfgData->TypeOfService      = Mode->ToS;\r
@@ -787,6 +895,7 @@ PxeBcCreateIp6Children (
   EFI_IP6_MODE_DATA               Ip6ModeData;\r
   PXEBC_PRIVATE_PROTOCOL          *Id;\r
   EFI_SIMPLE_NETWORK_PROTOCOL     *Snp;\r
+  UINTN                           Index;\r
 \r
   if (Private->Ip6Nic != NULL) {\r
     //\r
@@ -829,6 +938,16 @@ PxeBcCreateIp6Children (
     goto ON_ERROR;\r
   }\r
 \r
+  //\r
+  // Generate a random IAID for the Dhcp6 assigned address.\r
+  //\r
+  Private->IaId = NET_RANDOM (NetRandomInitSeed ());\r
+  if (Private->Snp != NULL) {\r
+    for (Index = 0; Index < Private->Snp->Mode->HwAddressSize; Index++) {\r
+      Private->IaId |= (Private->Snp->Mode->CurrentAddress.Addr[Index] << ((Index << 3) & 31));\r
+    }\r
+  }\r
+\r
   //\r
   // Create Mtftp6 child and open Mtftp6 protocol for PxeBc->Mtftp.\r
   //\r
@@ -939,6 +1058,30 @@ PxeBcCreateIp6Children (
 \r
   Private->Ip6MaxPacketSize = Ip6ModeData.MaxPacketSize;\r
 \r
+  if (Ip6ModeData.AddressList != NULL) {\r
+    FreePool (Ip6ModeData.AddressList);\r
+  }\r
+\r
+  if (Ip6ModeData.GroupTable != NULL) {\r
+    FreePool (Ip6ModeData.GroupTable);\r
+  }\r
+\r
+  if (Ip6ModeData.RouteTable != NULL) {\r
+    FreePool (Ip6ModeData.RouteTable);\r
+  }\r
+\r
+  if (Ip6ModeData.NeighborCache != NULL) {\r
+    FreePool (Ip6ModeData.NeighborCache);\r
+  }\r
+\r
+  if (Ip6ModeData.PrefixTable != NULL) {\r
+    FreePool (Ip6ModeData.PrefixTable);\r
+  }\r
+\r
+  if (Ip6ModeData.IcmpTypeList != NULL) {\r
+    FreePool (Ip6ModeData.IcmpTypeList);\r
+  }\r
+\r
   //\r
   // Locate Ip6->Ip6Config and store it for set IPv6 address.\r
   //\r
@@ -957,7 +1100,7 @@ PxeBcCreateIp6Children (
   ZeroMem (&Ip6Node, sizeof (IPv6_DEVICE_PATH));\r
   Ip6Node.Header.Type     = MESSAGING_DEVICE_PATH;\r
   Ip6Node.Header.SubType  = MSG_IPv6_DP;\r
-  Ip6Node.StaticIpAddress = FALSE;\r
+  Ip6Node.PrefixLength    = IP6_PREFIX_LENGTH;\r
 \r
   SetDevicePathNodeLength (&Ip6Node.Header, sizeof (Ip6Node));\r
 \r
@@ -991,7 +1134,7 @@ PxeBcCreateIp6Children (
   if (EFI_ERROR (Status)) {\r
     goto ON_ERROR;\r
   }\r
-  \r
+\r
   if (Private->Snp != NULL) {\r
     //\r
     // Install SNP protocol on purpose is for some OS loader backward\r
@@ -1008,7 +1151,7 @@ PxeBcCreateIp6Children (
     }\r
 \r
     //\r
-    // Open SNP on the child handle BY_DRIVER. It will prevent any additionally \r
+    // Open SNP on the child handle BY_DRIVER|EXCLUSIVE. It will prevent any additionally\r
     // layering to perform the experiment.\r
     //\r
     Status = gBS->OpenProtocol (\r
@@ -1017,7 +1160,7 @@ PxeBcCreateIp6Children (
                     (VOID **) &Snp,\r
                     This->DriverBindingHandle,\r
                     Private->Ip6Nic->Controller,\r
-                    EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                    EFI_OPEN_PROTOCOL_BY_DRIVER|EFI_OPEN_PROTOCOL_EXCLUSIVE\r
                     );\r
     if (EFI_ERROR (Status)) {\r
       goto ON_ERROR;\r
@@ -1030,7 +1173,7 @@ PxeBcCreateIp6Children (
   //\r
   Status = gBS->OpenProtocol (\r
                   ControllerHandle,\r
-                  &mPxeBcPrivateGuid,\r
+                  &gEfiCallerIdGuid,\r
                   (VOID **) &Id,\r
                   This->DriverBindingHandle,\r
                   Private->Ip6Nic->Controller,\r
@@ -1044,7 +1187,18 @@ PxeBcCreateIp6Children (
   // Set IPv6 avaiable flag and set default configure data for\r
   // Udp6Read and Ip6 instance.\r
   //\r
-  Private->Mode.Ipv6Available     = TRUE;\r
+  Status = PxeBcCheckIpv6Support (ControllerHandle, Private, &Private->Mode.Ipv6Available);\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Fail to get the data whether UNDI supports IPv6. Set default value.\r
+    //\r
+    Private->Mode.Ipv6Available   = TRUE;\r
+  }\r
+\r
+  if (!Private->Mode.Ipv6Available) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
   Udp6CfgData                     = &Private->Udp6CfgData;\r
   Ip6CfgData                      = &Private->Ip6CfgData;\r
 \r
@@ -1086,29 +1240,48 @@ PxeBcDriverEntryPoint (
   IN EFI_SYSTEM_TABLE       *SystemTable\r
   )\r
 {\r
-  return EfiLibInstallDriverBindingComponentName2 (\r
-           ImageHandle,\r
-           SystemTable,\r
-           &gPxeBcDriverBinding,\r
-           ImageHandle,\r
-           &gPxeBcComponentName,\r
-           &gPxeBcComponentName2\r
-           );\r
-}\r
+  EFI_STATUS  Status;\r
+\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gPxeBcIp4DriverBinding,\r
+             ImageHandle,\r
+             &gPxeBcComponentName,\r
+             &gPxeBcComponentName2\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
 \r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gPxeBcIp6DriverBinding,\r
+             NULL,\r
+             &gPxeBcComponentName,\r
+             &gPxeBcComponentName2\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    EfiLibUninstallDriverBindingComponentName2 (\r
+      &gPxeBcIp4DriverBinding,\r
+      &gPxeBcComponentName,\r
+      &gPxeBcComponentName2\r
+      );\r
+  }\r
+\r
+  return Status;\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
+  Test to see if this driver supports ControllerHandle. This is the worker function for\r
+  PxeBcIp4(6)DriverBindingSupported.\r
 \r
   @param[in]  This                The pointer to the driver binding protocol.\r
   @param[in]  ControllerHandle    The handle of device to be tested.\r
   @param[in]  RemainingDevicePath Optional parameter used to pick a specific child\r
                                   device to be started.\r
+  @param[in]  IpVersion           IP_VERSION_4 or IP_VERSION_6.\r
 \r
   @retval EFI_SUCCESS         This driver supports this device.\r
   @retval EFI_UNSUPPORTED     This driver does not support this device.\r
@@ -1116,52 +1289,40 @@ PxeBcDriverEntryPoint (
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-PxeBcDriverBindingSupported (\r
+PxeBcSupported (\r
   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
   IN EFI_HANDLE                   ControllerHandle,\r
-  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL,\r
+  IN UINT8                        IpVersion\r
   )\r
 {\r
-  EFI_STATUS                      Ip4Status;\r
-  EFI_STATUS                      Ip6Status;\r
+  EFI_STATUS                      Status;\r
+  EFI_GUID                        *DhcpServiceBindingGuid;\r
+  EFI_GUID                        *MtftpServiceBindingGuid;\r
 \r
-  //\r
-  // Try to open the Mtftp4 and Dhcp4 protocol to test whether IPv4 stack is ready.\r
-  //\r
-  Ip4Status = gBS->OpenProtocol (\r
-                     ControllerHandle,\r
-                     &gEfiDhcp4ServiceBindingProtocolGuid,\r
-                     NULL,\r
-                     This->DriverBindingHandle,\r
-                     ControllerHandle,\r
-                     EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
-                     );\r
-  if (!EFI_ERROR (Ip4Status)) {\r
-    Ip4Status = gBS->OpenProtocol (\r
-                       ControllerHandle,\r
-                       &gEfiMtftp4ServiceBindingProtocolGuid,\r
-                       NULL,\r
-                       This->DriverBindingHandle,\r
-                       ControllerHandle,\r
-                       EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
-                       );\r
+  if (IpVersion == IP_VERSION_4) {\r
+    DhcpServiceBindingGuid  = &gEfiDhcp4ServiceBindingProtocolGuid;\r
+    MtftpServiceBindingGuid = &gEfiMtftp4ServiceBindingProtocolGuid;\r
+  } else {\r
+    DhcpServiceBindingGuid  = &gEfiDhcp6ServiceBindingProtocolGuid;\r
+    MtftpServiceBindingGuid = &gEfiMtftp6ServiceBindingProtocolGuid;\r
   }\r
 \r
   //\r
-  // Try to open the Mtftp6 and Dhcp6 protocol to test whether IPv4 stack is ready.\r
+  // Try to open the Mtftp and Dhcp protocol to test whether IP stack is ready.\r
   //\r
-  Ip6Status = gBS->OpenProtocol (\r
+  Status = gBS->OpenProtocol (\r
                      ControllerHandle,\r
-                     &gEfiDhcp6ServiceBindingProtocolGuid,\r
+                     DhcpServiceBindingGuid,\r
                      NULL,\r
                      This->DriverBindingHandle,\r
                      ControllerHandle,\r
                      EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
                      );\r
-  if (!EFI_ERROR (Ip6Status)) {\r
-    Ip6Status = gBS->OpenProtocol (\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = gBS->OpenProtocol (\r
                        ControllerHandle,\r
-                       &gEfiMtftp6ServiceBindingProtocolGuid,\r
+                       MtftpServiceBindingGuid,\r
                        NULL,\r
                        This->DriverBindingHandle,\r
                        ControllerHandle,\r
@@ -1170,28 +1331,25 @@ PxeBcDriverBindingSupported (
   }\r
 \r
   //\r
-  // It's unsupported case if both stack are not ready.\r
+  // It's unsupported case if IP stack are not ready.\r
   //\r
-  if (EFI_ERROR (Ip4Status) && EFI_ERROR (Ip6Status)) {\r
+  if (EFI_ERROR (Status)) {\r
     return EFI_UNSUPPORTED;\r
   }\r
 \r
   return EFI_SUCCESS;\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
+  Start this driver on ControllerHandle. This is the worker function for\r
+  PxeBcIp4(6)DriverBindingStart.\r
 \r
   @param[in]  This                 The pointer to the driver binding protocol.\r
   @param[in]  ControllerHandle     The handle of device to be started.\r
   @param[in]  RemainingDevicePath  Optional parameter used to pick a specific child\r
                                    device to be started.\r
+  @param[in]  IpVersion            IP_VERSION_4 or IP_VERSION_6.\r
+\r
 \r
   @retval EFI_SUCCESS          This driver is installed to ControllerHandle.\r
   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle.\r
@@ -1200,21 +1358,22 @@ PxeBcDriverBindingSupported (
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-PxeBcDriverBindingStart (\r
+PxeBcStart (\r
   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
   IN EFI_HANDLE                   ControllerHandle,\r
-  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL,\r
+  IN UINT8                        IpVersion\r
   )\r
 {\r
   PXEBC_PRIVATE_DATA              *Private;\r
   EFI_STATUS                      Status;\r
-  EFI_STATUS                      Ip4Status;\r
-  EFI_STATUS                      Ip6Status;\r
   PXEBC_PRIVATE_PROTOCOL          *Id;\r
+  BOOLEAN                         FirstStart;\r
 \r
+  FirstStart = FALSE;\r
   Status = gBS->OpenProtocol (\r
                   ControllerHandle,\r
-                  &mPxeBcPrivateGuid,\r
+                  &gEfiCallerIdGuid,\r
                   (VOID **) &Id,\r
                   This->DriverBindingHandle,\r
                   ControllerHandle,\r
@@ -1226,6 +1385,7 @@ PxeBcDriverBindingStart (
     //\r
     Private = PXEBC_PRIVATE_DATA_FROM_ID (Id);\r
   } else {\r
+    FirstStart = TRUE;\r
     //\r
     // If the driver has not been started yet, it should do initialization.\r
     //\r
@@ -1282,10 +1442,13 @@ PxeBcDriverBindingStart (
 \r
     //\r
     // Install PxeBaseCodePrivate protocol onto the real NIC handler.\r
+    // PxeBaseCodePrivate protocol is only used to keep the relationship between\r
+    // NIC handle and virtual child handles.\r
+    // gEfiCallerIdGuid will be used as its protocol guid.\r
     //\r
     Status = gBS->InstallProtocolInterface (\r
                     &ControllerHandle,\r
-                    &mPxeBcPrivateGuid,\r
+                    &gEfiCallerIdGuid,\r
                     EFI_NATIVE_INTERFACE,\r
                     &Private->Id\r
                     );\r
@@ -1296,20 +1459,21 @@ PxeBcDriverBindingStart (
     //\r
     // Try to locate SNP protocol.\r
     //\r
-    NetLibGetSnpHandle(ControllerHandle, &Private->Snp);    \r
+    NetLibGetSnpHandle(ControllerHandle, &Private->Snp);\r
   }\r
 \r
-  //\r
-  // Try to create virtual NIC handle for IPv4.\r
-  //\r
-  Ip4Status = PxeBcCreateIp4Children (This, ControllerHandle, Private);\r
-\r
-  //\r
-  // Try to create virtual NIC handle for IPv6.\r
-  //\r
-  Ip6Status = PxeBcCreateIp6Children (This, ControllerHandle, Private);\r
-\r
-  if (EFI_ERROR (Ip4Status) && EFI_ERROR (Ip6Status)) {\r
+  if (IpVersion == IP_VERSION_4) {\r
+    //\r
+    // Try to create virtual NIC handle for IPv4.\r
+    //\r
+    Status = PxeBcCreateIp4Children (This, ControllerHandle, Private);\r
+  } else {\r
+    //\r
+    // Try to create virtual NIC handle for IPv6.\r
+    //\r
+    Status = PxeBcCreateIp6Children (This, ControllerHandle, Private);\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
     //\r
     // Failed to start PXE driver if IPv4 and IPv6 stack are both not available.\r
     //\r
@@ -1320,32 +1484,38 @@ PxeBcDriverBindingStart (
   return EFI_SUCCESS;\r
 \r
 ON_ERROR:\r
-  gBS->UninstallProtocolInterface (\r
-         ControllerHandle,\r
-         &mPxeBcPrivateGuid,\r
-         &Private->Id\r
-         );\r
-  PxeBcDestroyIp4Children (This, Private);\r
-  PxeBcDestroyIp6Children (This, Private);\r
-  FreePool (Private);\r
+  if (FirstStart) {\r
+    gBS->UninstallProtocolInterface (\r
+           ControllerHandle,\r
+           &gEfiCallerIdGuid,\r
+           &Private->Id\r
+           );\r
+  }\r
+\r
+  if (IpVersion == IP_VERSION_4) {\r
+    PxeBcDestroyIp4Children (This, Private);\r
+  } else {\r
+    PxeBcDestroyIp6Children (This, Private);\r
+  }\r
+\r
+  if (FirstStart && Private != NULL) {\r
+    FreePool (Private);\r
+  }\r
 \r
   return Status;\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
+  Stop this driver on ControllerHandle. This is the worker function for\r
+  PxeBcIp4(6)DriverBindingStop.\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
+  @param[in]  IpVersion         IP_VERSION_4 or IP_VERSION_6.\r
 \r
   @retval EFI_SUCCESS           This driver was removed ControllerHandle.\r
   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.\r
@@ -1354,11 +1524,12 @@ ON_ERROR:
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-PxeBcDriverBindingStop (\r
+PxeBcStop (\r
   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
   IN EFI_HANDLE                   ControllerHandle,\r
   IN UINTN                        NumberOfChildren,\r
-  IN EFI_HANDLE                   *ChildHandleBuffer\r
+  IN EFI_HANDLE                   *ChildHandleBuffer,\r
+  IN UINT8                        IpVersion\r
   )\r
 {\r
   PXEBC_PRIVATE_DATA              *Private;\r
@@ -1366,7 +1537,6 @@ PxeBcDriverBindingStop (
   EFI_LOAD_FILE_PROTOCOL          *LoadFile;\r
   EFI_STATUS                      Status;\r
   EFI_HANDLE                      NicHandle;\r
-  BOOLEAN                         IsIpv6;\r
   PXEBC_PRIVATE_PROTOCOL          *Id;\r
 \r
   Private    = NULL;\r
@@ -1374,7 +1544,6 @@ PxeBcDriverBindingStop (
   VirtualNic = NULL;\r
   LoadFile   = NULL;\r
   Id         = NULL;\r
-  IsIpv6     = FALSE;\r
 \r
   Status = gBS->OpenProtocol (\r
                   ControllerHandle,\r
@@ -1388,14 +1557,13 @@ PxeBcDriverBindingStop (
     //\r
     // Get the Nic handle by any pass-over service child handle.\r
     //\r
-    NicHandle = PxeBcGetNicByIp4Children (ControllerHandle);\r
-    if (NicHandle == NULL) {\r
+    if (IpVersion == IP_VERSION_4) {\r
+      NicHandle = PxeBcGetNicByIp4Children (ControllerHandle);\r
+    } else {\r
       NicHandle = PxeBcGetNicByIp6Children (ControllerHandle);\r
-      if (NicHandle == NULL) {\r
-        return EFI_DEVICE_ERROR;\r
-      } else {\r
-        IsIpv6 = TRUE;\r
-      }\r
+    }\r
+    if (NicHandle == NULL) {\r
+      return EFI_SUCCESS;\r
     }\r
 \r
     //\r
@@ -1403,7 +1571,7 @@ PxeBcDriverBindingStop (
     //\r
     Status = gBS->OpenProtocol (\r
                     NicHandle,\r
-                    &mPxeBcPrivateGuid,\r
+                    &gEfiCallerIdGuid,\r
                     (VOID **) &Id,\r
                     This->DriverBindingHandle,\r
                     ControllerHandle,\r
@@ -1433,10 +1601,6 @@ PxeBcDriverBindingStop (
     VirtualNic = PXEBC_VIRTUAL_NIC_FROM_LOADFILE (LoadFile);\r
     Private    = VirtualNic->Private;\r
     NicHandle  = Private->Controller;\r
-\r
-    if (Private->Ip6Nic == VirtualNic) {\r
-      IsIpv6   = TRUE;\r
-    }\r
   }\r
 \r
   //\r
@@ -1448,18 +1612,18 @@ PxeBcDriverBindingStop (
   }\r
 \r
 \r
-  if (Private->Ip4Nic != NULL && !IsIpv6) {\r
+  if (Private->Ip4Nic != NULL && IpVersion == IP_VERSION_4) {\r
     PxeBcDestroyIp4Children (This, Private);\r
   }\r
 \r
-  if (Private->Ip6Nic != NULL && IsIpv6) {\r
+  if (Private->Ip6Nic != NULL && IpVersion == IP_VERSION_6) {\r
     PxeBcDestroyIp6Children (This, Private);\r
   }\r
 \r
   if (Private->Ip4Nic == NULL && Private->Ip6Nic == NULL) {\r
     gBS->UninstallProtocolInterface (\r
            NicHandle,\r
-           &mPxeBcPrivateGuid,\r
+           &gEfiCallerIdGuid,\r
            &Private->Id\r
            );\r
     FreePool (Private);\r
@@ -1467,3 +1631,211 @@ PxeBcDriverBindingStop (
 \r
   return EFI_SUCCESS;\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                The pointer to the driver binding protocol.\r
+  @param[in]  ControllerHandle    The handle of device to be tested.\r
+  @param[in]  RemainingDevicePath Optional parameter used to pick a specific child\r
+                                  device to be started.\r
+\r
+  @retval EFI_SUCCESS         This driver supports this device.\r
+  @retval EFI_UNSUPPORTED     This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PxeBcIp4DriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  )\r
+{\r
+  return PxeBcSupported (\r
+           This,\r
+           ControllerHandle,\r
+           RemainingDevicePath,\r
+           IP_VERSION_4\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                 The pointer to the driver binding protocol.\r
+  @param[in]  ControllerHandle     The handle of device to be started.\r
+  @param[in]  RemainingDevicePath  Optional parameter used to pick a specific child\r
+                                   device to be started.\r
+\r
+  @retval EFI_SUCCESS          This driver is installed 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
+PxeBcIp4DriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  )\r
+{\r
+  return PxeBcStart (\r
+           This,\r
+           ControllerHandle,\r
+           RemainingDevicePath,\r
+           IP_VERSION_4\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 EFI_DEVICE_ERROR      An unexpected system or network error occurred.\r
+  @retval Others                This driver was not removed from this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PxeBcIp4DriverBindingStop (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN UINTN                        NumberOfChildren,\r
+  IN EFI_HANDLE                   *ChildHandleBuffer\r
+  )\r
+{\r
+  return PxeBcStop (\r
+           This,\r
+           ControllerHandle,\r
+           NumberOfChildren,\r
+           ChildHandleBuffer,\r
+           IP_VERSION_4\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                The pointer to the driver binding protocol.\r
+  @param[in]  ControllerHandle    The handle of device to be tested.\r
+  @param[in]  RemainingDevicePath Optional parameter use to pick a specific child\r
+                                  device to be started.\r
+\r
+  @retval EFI_SUCCESS         This driver supports this device.\r
+  @retval EFI_UNSUPPORTED     This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PxeBcIp6DriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  )\r
+{\r
+  return PxeBcSupported (\r
+           This,\r
+           ControllerHandle,\r
+           RemainingDevicePath,\r
+           IP_VERSION_6\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                 The pointer to the driver binding protocol.\r
+  @param[in]  ControllerHandle     The handle of device to be started.\r
+  @param[in]  RemainingDevicePath  Optional parameter used to pick a specific child\r
+                                   device to be started.\r
+\r
+  @retval EFI_SUCCESS          This driver is installed 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
+PxeBcIp6DriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  )\r
+{\r
+  return PxeBcStart (\r
+           This,\r
+           ControllerHandle,\r
+           RemainingDevicePath,\r
+           IP_VERSION_6\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 EFI_DEVICE_ERROR      An unexpected system or network error occurred.\r
+  @retval Others                This driver was not removed from this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PxeBcIp6DriverBindingStop (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN UINTN                        NumberOfChildren,\r
+  IN EFI_HANDLE                   *ChildHandleBuffer\r
+  )\r
+{\r
+  return PxeBcStop (\r
+           This,\r
+           ControllerHandle,\r
+           NumberOfChildren,\r
+           ChildHandleBuffer,\r
+           IP_VERSION_6\r
+           );\r
+}\r