]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/HttpBootDxe/HttpBootDxe.c
NetworkPkg/HttpBootDxe: Avoid the potential memory leak when eror happen.
[mirror_edk2.git] / NetworkPkg / HttpBootDxe / HttpBootDxe.c
index a7fc8a8e2e634505f82035d43c47b21ec3e4d8bd..8a61f51cc87b5fc5a5294946bb385b4f6072373b 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Driver Binding functions implementation for UEFI HTTP boot.\r
 \r
-Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials are licensed and made available under \r
 the terms and conditions of the BSD License that accompanies this distribution.  \r
 The full text of the license may be found at\r
@@ -35,6 +35,100 @@ EFI_DRIVER_BINDING_PROTOCOL gHttpBootIp6DxeDriverBinding = {
   NULL\r
 };\r
 \r
+\r
+\r
+/**\r
+  Check whether UNDI protocol supports IPv6.\r
+\r
+  @param[in]   Private           Pointer to HTTP_BOOT_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
+HttpBootCheckIpv6Support (\r
+  IN  HTTP_BOOT_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
+  // Get the NIC handle by SNP protocol.\r
+  //  \r
+  Handle = NetLibGetSnpHandle (Private->Controller, 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
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
 /**\r
   Destroy the HTTP child based on IPv4 stack.\r
 \r
@@ -50,7 +144,6 @@ HttpBootDestroyIp4Children (
 {\r
   ASSERT (This != NULL);\r
   ASSERT (Private != NULL);\r
-  ASSERT (Private->UsingIpv6 == FALSE);\r
 \r
   if (Private->Dhcp4Child != NULL) {\r
     gBS->CloseProtocol (\r
@@ -68,7 +161,7 @@ HttpBootDestroyIp4Children (
       );\r
   }\r
 \r
-  if (Private->HttpCreated) {\r
+  if (Private->Ip6Nic == NULL && Private->HttpCreated) {\r
     HttpIoDestroyIo (&Private->HttpIo);\r
     Private->HttpCreated = FALSE;\r
   }\r
@@ -111,7 +204,6 @@ HttpBootDestroyIp6Children (
 {\r
   ASSERT (This != NULL);\r
   ASSERT (Private != NULL);\r
-  ASSERT (Private->UsingIpv6 == TRUE);\r
   \r
   if (Private->Ip6Child != NULL) {\r
     gBS->CloseProtocol (\r
@@ -145,7 +237,7 @@ HttpBootDestroyIp6Children (
       );\r
   }\r
 \r
-  if (Private->HttpCreated) {\r
+  if (Private->Ip4Nic == NULL && Private->HttpCreated) {\r
     HttpIoDestroyIo(&Private->HttpIo);\r
     Private->HttpCreated = FALSE;\r
   }\r
@@ -312,6 +404,9 @@ HttpBootIp4DxeDriverBindingStart (
   EFI_DEV_PATH               *Node;\r
   EFI_DEVICE_PATH_PROTOCOL   *DevicePath;\r
   UINT32                     *Id;\r
+  BOOLEAN                    FirstStart;\r
+\r
+  FirstStart = FALSE;\r
 \r
   Status = gBS->OpenProtocol (\r
                   ControllerHandle,\r
@@ -323,8 +418,10 @@ HttpBootIp4DxeDriverBindingStart (
                   );\r
 \r
   if (!EFI_ERROR (Status)) {\r
-      Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID(Id);\r
+    Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID(Id);\r
   } else {\r
+    FirstStart = TRUE;\r
+  \r
     //\r
     // Initialize the private data structure.\r
     //\r
@@ -334,7 +431,6 @@ HttpBootIp4DxeDriverBindingStart (
     }\r
     Private->Signature = HTTP_BOOT_PRIVATE_DATA_SIGNATURE;\r
     Private->Controller = ControllerHandle;\r
-    Private->Image = This->ImageHandle;\r
     InitializeListHead (&Private->CacheList);\r
     //\r
     // Get the NII interface if it exists, it's not required.\r
@@ -366,6 +462,14 @@ HttpBootIp4DxeDriverBindingStart (
       goto ON_ERROR;\r
     }\r
 \r
+    //\r
+    // Initialize the HII configuration form.\r
+    //\r
+    Status = HttpBootConfigFormInit (Private);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_ERROR;\r
+    }\r
+\r
     //\r
     // Install a protocol with Caller Id Guid to the NIC, this is just to build the relationship between\r
     // NIC handle and the private data.\r
@@ -391,10 +495,12 @@ HttpBootIp4DxeDriverBindingStart (
   \r
   Private->Ip4Nic = AllocateZeroPool (sizeof (HTTP_BOOT_VIRTUAL_NIC));\r
   if (Private->Ip4Nic == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_ERROR;\r
   }\r
-  Private->Ip4Nic->Private   = Private;\r
-  Private->Ip4Nic->Signature = HTTP_BOOT_VIRTUAL_NIC_SIGNATURE;\r
+  Private->Ip4Nic->Private     = Private;\r
+  Private->Ip4Nic->ImageHandle = This->DriverBindingHandle;\r
+  Private->Ip4Nic->Signature   = HTTP_BOOT_VIRTUAL_NIC_SIGNATURE;\r
   \r
   //\r
   // Create DHCP4 child instance.\r
@@ -507,12 +613,24 @@ HttpBootIp4DxeDriverBindingStart (
   }\r
   \r
   return EFI_SUCCESS;\r
-\r
     \r
 ON_ERROR:\r
-  \r
-  HttpBootDestroyIp4Children (This, Private);\r
-  FreePool (Private);\r
+  if (Private != NULL) {\r
+    if (FirstStart) {\r
+      gBS->UninstallProtocolInterface (\r
+             ControllerHandle,\r
+             &gEfiCallerIdGuid,\r
+             &Private->Id\r
+             );\r
+    }\r
+    \r
+    HttpBootDestroyIp4Children (This, Private);\r
+    HttpBootConfigFormUnload (Private);\r
+\r
+    if (FirstStart) {\r
+      FreePool (Private);\r
+    }\r
+  }\r
 \r
   return Status;\r
 }\r
@@ -617,6 +735,11 @@ HttpBootIp4DxeDriverBindingStop (
     // Release the cached data.\r
     //\r
     HttpBootFreeCacheList (Private);\r
+\r
+    //\r
+    // Unload the config form.\r
+    //\r
+    HttpBootConfigFormUnload (Private);\r
     \r
     gBS->UninstallProtocolInterface (\r
            NicHandle,\r
@@ -770,6 +893,10 @@ HttpBootIp6DxeDriverBindingStart (
   EFI_DEV_PATH               *Node;\r
   EFI_DEVICE_PATH_PROTOCOL   *DevicePath;\r
   UINT32                     *Id;\r
+  BOOLEAN                    Ipv6Available;\r
+  BOOLEAN                    FirstStart;\r
+\r
+  FirstStart = FALSE;\r
   \r
   Status = gBS->OpenProtocol (\r
                   ControllerHandle,\r
@@ -781,8 +908,10 @@ HttpBootIp6DxeDriverBindingStart (
                   );\r
   \r
   if (!EFI_ERROR (Status)) {\r
-      Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID(Id);\r
+    Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID(Id);\r
   } else {\r
+    FirstStart = TRUE;\r
+    \r
     //\r
     // Initialize the private data structure.\r
     //\r
@@ -792,7 +921,6 @@ HttpBootIp6DxeDriverBindingStart (
     }\r
     Private->Signature = HTTP_BOOT_PRIVATE_DATA_SIGNATURE;\r
     Private->Controller = ControllerHandle;\r
-    Private->Image = This->ImageHandle;\r
     InitializeListHead (&Private->CacheList);\r
     //\r
     // Get the NII interface if it exists, it's not required.\r
@@ -824,6 +952,14 @@ HttpBootIp6DxeDriverBindingStart (
       goto ON_ERROR;\r
     }\r
 \r
+    //\r
+    // Initialize the HII configuration form.\r
+    //\r
+    Status = HttpBootConfigFormInit (Private);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_ERROR;\r
+    }\r
+\r
     //\r
     // Install a protocol with Caller Id Guid to the NIC, this is just to build the relationship between\r
     // NIC handle and the private data.\r
@@ -839,6 +975,23 @@ HttpBootIp6DxeDriverBindingStart (
     }\r
       \r
   }\r
+\r
+  //\r
+  // Set IPv6 available flag.\r
+  // \r
+  Status = HttpBootCheckIpv6Support (Private, &Ipv6Available);\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Fail to get the data whether UNDI supports IPv6. \r
+    // Set default value to TRUE.\r
+    //\r
+    Ipv6Available = TRUE;\r
+  }\r
+\r
+  if (!Ipv6Available) {\r
+    Status = EFI_UNSUPPORTED;\r
+    goto ON_ERROR;\r
+  }\r
   \r
   if (Private->Ip6Nic != NULL) {\r
     //\r
@@ -849,11 +1002,13 @@ HttpBootIp6DxeDriverBindingStart (
   \r
   Private->Ip6Nic = AllocateZeroPool (sizeof (HTTP_BOOT_VIRTUAL_NIC));\r
   if (Private->Ip6Nic == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_ERROR;\r
   }\r
-  Private->Ip6Nic->Private   = Private;\r
-  Private->Ip6Nic->Signature = HTTP_BOOT_VIRTUAL_NIC_SIGNATURE;\r
-\r
+  Private->Ip6Nic->Private     = Private;\r
+  Private->Ip6Nic->ImageHandle = This->DriverBindingHandle;\r
+  Private->Ip6Nic->Signature   = HTTP_BOOT_VIRTUAL_NIC_SIGNATURE;\r
+  \r
   //\r
   // Create Dhcp6 child and open Dhcp6 protocol\r
   Status = NetLibCreateServiceChild (\r
@@ -991,12 +1146,24 @@ HttpBootIp6DxeDriverBindingStart (
   return EFI_SUCCESS;\r
    \r
 ON_ERROR:\r
-  \r
- HttpBootDestroyIp6Children(This, Private);\r
- FreePool (Private);\r
+  if (Private != NULL) {\r
+    if (FirstStart) {\r
+      gBS->UninstallProtocolInterface (\r
+             ControllerHandle,\r
+             &gEfiCallerIdGuid,\r
+             &Private->Id\r
+             );\r
+    }\r
+\r
+    HttpBootDestroyIp6Children(This, Private);\r
+    HttpBootConfigFormUnload (Private);\r
+\r
+    if (FirstStart) {\r
+      FreePool (Private);\r
+    }\r
+  }\r
 \r
- return Status;\r
\r
+  return Status;\r
 }\r
 \r
 /**\r
@@ -1098,7 +1265,12 @@ HttpBootIp6DxeDriverBindingStop (
     // Release the cached data.\r
     //\r
     HttpBootFreeCacheList (Private);\r
-        \r
+\r
+    //\r
+    // Unload the config form.\r
+    //\r
+    HttpBootConfigFormUnload (Private);\r
+\r
     gBS->UninstallProtocolInterface (\r
            NicHandle,\r
            &gEfiCallerIdGuid,\r
@@ -1130,6 +1302,7 @@ HttpBootDxeDriverEntryPoint (
   )\r
 {\r
   EFI_STATUS   Status;\r
+\r
   //\r
   // Install UEFI Driver Model protocol(s).\r
   //\r