]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c
MdePkg/SmmMemLib: Check for untested memory in GCD
[mirror_edk2.git] / NetworkPkg / Ip6Dxe / Ip6ConfigImpl.c
index 7c7acc72d5576665ab053069212eb52dd8e31301..6ec87716a2de404f42c74f313bca3b0653cc061a 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   The implementation of EFI IPv6 Configuration Protocol.\r
 \r
 /** @file\r
   The implementation of EFI IPv6 Configuration Protocol.\r
 \r
-  Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2009 - 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
 \r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
@@ -47,13 +47,18 @@ Ip6ConfigOnPolicyChanged (
   IN EFI_IP6_CONFIG_POLICY  NewPolicy\r
   )\r
 {\r
   IN EFI_IP6_CONFIG_POLICY  NewPolicy\r
   )\r
 {\r
-  LIST_ENTRY      *Entry;\r
-  LIST_ENTRY      *Entry2;\r
-  LIST_ENTRY      *Next;\r
-  IP6_INTERFACE   *IpIf;\r
-  IP6_DAD_ENTRY   *DadEntry;\r
-  IP6_DELAY_JOIN_LIST       *DelayNode;\r
-  \r
+  LIST_ENTRY          *Entry;\r
+  LIST_ENTRY          *Entry2;\r
+  LIST_ENTRY          *Next;\r
+  IP6_INTERFACE       *IpIf;\r
+  IP6_DAD_ENTRY       *DadEntry;\r
+  IP6_DELAY_JOIN_LIST *DelayNode;\r
+  IP6_ADDRESS_INFO    *AddrInfo;\r
+  IP6_PROTOCOL        *Instance;\r
+  BOOLEAN             Recovery;\r
+\r
+  Recovery = FALSE;\r
+\r
   //\r
   // Currently there are only two policies: Manual and Automatic. Regardless of\r
   // what transition is going on, i.e., Manual -> Automatic and Automatic ->\r
   //\r
   // Currently there are only two policies: Manual and Automatic. Regardless of\r
   // what transition is going on, i.e., Manual -> Automatic and Automatic ->\r
@@ -80,18 +85,48 @@ Ip6ConfigOnPolicyChanged (
       );\r
   }\r
 \r
       );\r
   }\r
 \r
-  //\r
-  // All IPv6 children that use global unicast address as it's source address\r
-  // should be destryoed now. The survivers are those use the link-local address\r
-  // or the unspecified address as the source address.\r
-  // TODO: Conduct a check here.\r
-  Ip6RemoveAddr (\r
-    IpSb,\r
-    &IpSb->DefaultInterface->AddressList,\r
-    &IpSb->DefaultInterface->AddressCount,\r
-    NULL,\r
-    0\r
-    );\r
+  if (!IsListEmpty (&IpSb->DefaultInterface->AddressList) && IpSb->DefaultInterface->AddressCount > 0) {\r
+    //\r
+    // If any IPv6 children (Instance) in configured state and use global unicast address, it will be\r
+    // destroyed in Ip6RemoveAddr() function later. Then, the upper layer driver's Stop() function will be\r
+    // called, which may break the upper layer network stacks. So, the driver should take the responsibility\r
+    // for the recovery by using ConnectController() after Ip6RemoveAddr().\r
+    // Here, just check whether need to recover the upper layer network stacks later.\r
+    //\r
+    NET_LIST_FOR_EACH (Entry, &IpSb->DefaultInterface->AddressList) {\r
+      AddrInfo = NET_LIST_USER_STRUCT_S (Entry, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);\r
+      if (!IsListEmpty (&IpSb->Children)) {\r
+        NET_LIST_FOR_EACH (Entry2, &IpSb->Children) {\r
+          Instance = NET_LIST_USER_STRUCT_S (Entry2, IP6_PROTOCOL, Link, IP6_PROTOCOL_SIGNATURE);\r
+          if ((Instance->State == IP6_STATE_CONFIGED) && EFI_IP6_EQUAL (&Instance->ConfigData.StationAddress, &AddrInfo->Address)) {\r
+            Recovery = TRUE;\r
+            break;\r
+          }\r
+        }\r
+      }\r
+    }\r
+\r
+    //\r
+    // All IPv6 children that use global unicast address as it's source address\r
+    // should be destroyed now. The survivers are those use the link-local address\r
+    // or the unspecified address as the source address.\r
+    // TODO: Conduct a check here.\r
+    Ip6RemoveAddr (\r
+      IpSb,\r
+      &IpSb->DefaultInterface->AddressList,\r
+      &IpSb->DefaultInterface->AddressCount,\r
+      NULL,\r
+      0\r
+      );\r
+\r
+    if (IpSb->Controller != NULL && Recovery) {\r
+      //\r
+      // ConnectController() to recover the upper layer network stacks.\r
+      //\r
+      gBS->ConnectController (IpSb->Controller, NULL, NULL, TRUE);\r
+    }\r
+  }\r
+\r
 \r
   NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
     //\r
 \r
   NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
     //\r
@@ -130,7 +165,6 @@ Ip6ConfigOnPolicyChanged (
     //\r
     IpSb->Ticks                   = (UINT32) IP6_GET_TICKS (IP6_ONE_SECOND_IN_MS);\r
   }\r
     //\r
     IpSb->Ticks                   = (UINT32) IP6_GET_TICKS (IP6_ONE_SECOND_IN_MS);\r
   }\r
-\r
 }\r
 \r
 /**\r
 }\r
 \r
 /**\r
@@ -692,7 +726,7 @@ Ip6ConfigSetPolicy (
     DataItem->DataSize = 0;\r
     DataItem->Status   = EFI_NOT_FOUND;\r
     NetMapIterate (&DataItem->EventMap, Ip6ConfigSignalEvent, NULL);\r
     DataItem->DataSize = 0;\r
     DataItem->Status   = EFI_NOT_FOUND;\r
     NetMapIterate (&DataItem->EventMap, Ip6ConfigSignalEvent, NULL);\r
-    \r
+\r
     if (NewPolicy == Ip6ConfigPolicyManual) {\r
       //\r
       // The policy is changed from automatic to manual. Stop the DHCPv6 process\r
     if (NewPolicy == Ip6ConfigPolicyManual) {\r
       //\r
       // The policy is changed from automatic to manual. Stop the DHCPv6 process\r
@@ -919,10 +953,26 @@ Ip6ConfigSetManualAddress (
   IP6_PREFIX_LIST_ENTRY          *PrefixEntry;\r
   EFI_STATUS                     Status;\r
   BOOLEAN                        IsUpdated;\r
   IP6_PREFIX_LIST_ENTRY          *PrefixEntry;\r
   EFI_STATUS                     Status;\r
   BOOLEAN                        IsUpdated;\r
+  LIST_ENTRY                     *Next;\r
+  IP6_DAD_ENTRY                  *DadEntry;\r
+  IP6_DELAY_JOIN_LIST            *DelayNode;\r
+\r
+  NewAddress      = NULL;\r
+  TmpAddress      = NULL;\r
+  CurrentAddrInfo = NULL;\r
+  Copy            = NULL;\r
+  Entry           = NULL;\r
+  Entry2          = NULL;\r
+  IpIf            = NULL;\r
+  PrefixEntry     = NULL;\r
+  Next            = NULL;\r
+  DadEntry        = NULL;\r
+  DelayNode       = NULL;\r
+  Status          = EFI_SUCCESS;\r
 \r
   ASSERT (Instance->DataItem[Ip6ConfigDataTypeManualAddress].Status != EFI_NOT_READY);\r
 \r
 \r
   ASSERT (Instance->DataItem[Ip6ConfigDataTypeManualAddress].Status != EFI_NOT_READY);\r
 \r
-  if (((DataSize % sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS)) != 0) || (DataSize == 0)) {\r
+  if ((DataSize != 0) && ((DataSize % sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS)) != 0)) {\r
     return EFI_BAD_BUFFER_SIZE;\r
   }\r
 \r
     return EFI_BAD_BUFFER_SIZE;\r
   }\r
 \r
@@ -930,239 +980,302 @@ Ip6ConfigSetManualAddress (
     return EFI_WRITE_PROTECTED;\r
   }\r
 \r
     return EFI_WRITE_PROTECTED;\r
   }\r
 \r
-  NewAddressCount = DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS);\r
-  NewAddress      = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) Data;\r
+  IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
 \r
 \r
-  for (Index1 = 0; Index1 < NewAddressCount; Index1++, NewAddress++) {\r
+  DataItem = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];\r
 \r
 \r
-    if (NetIp6IsLinkLocalAddr (&NewAddress->Address)    ||\r
-        !NetIp6IsValidUnicast (&NewAddress->Address)    ||\r
-        (NewAddress->PrefixLength > 128)\r
-        ) {\r
-      //\r
-      // make sure the IPv6 address is unicast and not link-local address &&\r
-      // the prefix length is valid.\r
-      //\r
-      return EFI_INVALID_PARAMETER;\r
-    }\r
+  if (Data != NULL && DataSize != 0) {\r
+    NewAddressCount = DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS);\r
+    NewAddress      = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) Data;\r
 \r
 \r
-    TmpAddress = NewAddress + 1;\r
-    for (Index2 = Index1 + 1; Index2 < NewAddressCount; Index2++, TmpAddress++) {\r
-      //\r
-      // Any two addresses in the array can't be equal.\r
-      //\r
-      if (EFI_IP6_EQUAL (&TmpAddress->Address, &NewAddress->Address)) {\r
+    for (Index1 = 0; Index1 < NewAddressCount; Index1++, NewAddress++) {\r
 \r
 \r
+      if (NetIp6IsLinkLocalAddr (&NewAddress->Address)    ||\r
+          !NetIp6IsValidUnicast (&NewAddress->Address)    ||\r
+          (NewAddress->PrefixLength > 128)\r
+          ) {\r
+        //\r
+        // make sure the IPv6 address is unicast and not link-local address &&\r
+        // the prefix length is valid.\r
+        //\r
         return EFI_INVALID_PARAMETER;\r
       }\r
         return EFI_INVALID_PARAMETER;\r
       }\r
+\r
+      TmpAddress = NewAddress + 1;\r
+      for (Index2 = Index1 + 1; Index2 < NewAddressCount; Index2++, TmpAddress++) {\r
+        //\r
+        // Any two addresses in the array can't be equal.\r
+        //\r
+        if (EFI_IP6_EQUAL (&TmpAddress->Address, &NewAddress->Address)) {\r
+\r
+          return EFI_INVALID_PARAMETER;\r
+        }\r
+      }\r
     }\r
     }\r
-  }\r
 \r
 \r
-  IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
+    //\r
+    // Build the current source address list.\r
+    //\r
+    InitializeListHead (&CurrentSourceList);\r
+    CurrentSourceCount = 0;\r
 \r
 \r
-  //\r
-  // Build the current source address list.\r
-  //\r
-  InitializeListHead (&CurrentSourceList);\r
-  CurrentSourceCount = 0;\r
+    NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
+      IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);\r
 \r
 \r
-  NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
-    IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);\r
+      NET_LIST_FOR_EACH (Entry2, &IpIf->AddressList) {\r
+        CurrentAddrInfo = NET_LIST_USER_STRUCT_S (Entry2, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);\r
 \r
 \r
-    NET_LIST_FOR_EACH (Entry2, &IpIf->AddressList) {\r
-      CurrentAddrInfo = NET_LIST_USER_STRUCT_S (Entry2, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);\r
+        Copy            = AllocateCopyPool (sizeof (IP6_ADDRESS_INFO), CurrentAddrInfo);\r
+        if (Copy == NULL) {\r
+          break;\r
+        }\r
 \r
 \r
-      Copy            = AllocateCopyPool (sizeof (IP6_ADDRESS_INFO), CurrentAddrInfo);\r
-      if (Copy == NULL) {\r
-        break;\r
+        InsertTailList (&CurrentSourceList, &Copy->Link);\r
+        CurrentSourceCount++;\r
       }\r
       }\r
+    }\r
+\r
+    //\r
+    // Update the value... a long journey starts\r
+    //\r
+    NewAddress = AllocateCopyPool (DataSize, Data);\r
+    if (NewAddress == NULL) {\r
+      Ip6RemoveAddr (NULL, &CurrentSourceList, &CurrentSourceCount, NULL, 0);\r
 \r
 \r
-      InsertTailList (&CurrentSourceList, &Copy->Link);\r
-      CurrentSourceCount++;\r
+      return EFI_OUT_OF_RESOURCES;\r
     }\r
     }\r
-  }\r
 \r
 \r
-  //\r
-  // Update the value... a long journey starts\r
-  //\r
-  NewAddress = AllocateCopyPool (DataSize, Data);\r
-  if (NewAddress == NULL) {\r
-    Ip6RemoveAddr (NULL, &CurrentSourceList, &CurrentSourceCount, NULL, 0);\r
+    //\r
+    // Store the new data, and init the DataItem status to EFI_NOT_READY because\r
+    // we may have an asynchronous configuration process.\r
+    //\r
+    if (DataItem->Data.Ptr != NULL) {\r
+      FreePool (DataItem->Data.Ptr);\r
+    }\r
+    DataItem->Data.Ptr = NewAddress;\r
+    DataItem->DataSize = DataSize;\r
+    DataItem->Status   = EFI_NOT_READY;\r
 \r
 \r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
+    //\r
+    // Trigger DAD, it's an asynchronous process.\r
+    //\r
+    IsUpdated  = FALSE;\r
 \r
 \r
-  //\r
-  // Store the new data, and init the DataItem status to EFI_NOT_READY because\r
-  // we may have an asynchronous configuration process.\r
-  //\r
-  DataItem = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];\r
-  if (DataItem->Data.Ptr != NULL) {\r
-    FreePool (DataItem->Data.Ptr);\r
-  }\r
-  DataItem->Data.Ptr = NewAddress;\r
-  DataItem->DataSize = DataSize;\r
-  DataItem->Status   = EFI_NOT_READY;\r
+    for (Index1 = 0; Index1 < NewAddressCount; Index1++, NewAddress++) {\r
+      if (Ip6IsOneOfSetAddress (IpSb, &NewAddress->Address, NULL, &CurrentAddrInfo)) {\r
+        ASSERT (CurrentAddrInfo != NULL);\r
+        //\r
+        // Remove this already existing source address from the CurrentSourceList\r
+        // built before.\r
+        //\r
+        Ip6RemoveAddr (\r
+          NULL,\r
+          &CurrentSourceList,\r
+          &CurrentSourceCount,\r
+          &CurrentAddrInfo->Address,\r
+          128\r
+          );\r
 \r
 \r
-  //\r
-  // Trigger DAD, it's an asynchronous process.\r
-  //\r
-  IsUpdated  = FALSE;\r
+        //\r
+        // If the new address's prefix length is not specified, just use the previous configured\r
+        // prefix length for this address.\r
+        //\r
+        if (NewAddress->PrefixLength == 0) {\r
+          NewAddress->PrefixLength = CurrentAddrInfo->PrefixLength;\r
+        }\r
 \r
 \r
-  for (Index1 = 0; Index1 < NewAddressCount; Index1++, NewAddress++) {\r
-    if (Ip6IsOneOfSetAddress (IpSb, &NewAddress->Address, NULL, &CurrentAddrInfo)) {\r
-      ASSERT (CurrentAddrInfo != NULL);\r
-      //\r
-      // Remove this already existing source address from the CurrentSourceList\r
-      // built before.\r
-      //\r
-      Ip6RemoveAddr (\r
-        NULL,\r
-        &CurrentSourceList,\r
-        &CurrentSourceCount,\r
-        &CurrentAddrInfo->Address,\r
-        128\r
-        );\r
+        //\r
+        // This manual address is already in use, see whether prefix length is changed.\r
+        //\r
+        if (NewAddress->PrefixLength != CurrentAddrInfo->PrefixLength) {\r
+          //\r
+          // Remove the on-link prefix table, the route entry will be removed\r
+          // implicitly.\r
+          //\r
+          PrefixEntry = Ip6FindPrefixListEntry (\r
+                          IpSb,\r
+                          TRUE,\r
+                          CurrentAddrInfo->PrefixLength,\r
+                          &CurrentAddrInfo->Address\r
+                          );\r
+          if (PrefixEntry != NULL) {\r
+            Ip6DestroyPrefixListEntry (IpSb, PrefixEntry, TRUE, FALSE);\r
+          }\r
 \r
 \r
-      //\r
-      // If the new address's prefix length is not specified, just use the previous configured\r
-      // prefix length for this address.\r
-      //\r
-      if (NewAddress->PrefixLength == 0) {\r
-        NewAddress->PrefixLength = CurrentAddrInfo->PrefixLength;\r
-      }\r
+          //\r
+          // Save the prefix length.\r
+          //\r
+          CurrentAddrInfo->PrefixLength = NewAddress->PrefixLength;\r
+          IsUpdated = TRUE;\r
+        }\r
 \r
 \r
-      //\r
-      // This manual address is already in use, see whether prefix length is changed.\r
-      //\r
-      if (NewAddress->PrefixLength != CurrentAddrInfo->PrefixLength) {\r
         //\r
         //\r
-        // Remove the on-link prefix table, the route entry will be removed\r
-        // implicitly.\r
+        // create a new on-link prefix entry.\r
         //\r
         PrefixEntry = Ip6FindPrefixListEntry (\r
                         IpSb,\r
                         TRUE,\r
         //\r
         PrefixEntry = Ip6FindPrefixListEntry (\r
                         IpSb,\r
                         TRUE,\r
-                        CurrentAddrInfo->PrefixLength,\r
-                        &CurrentAddrInfo->Address\r
+                        NewAddress->PrefixLength,\r
+                        &NewAddress->Address\r
                         );\r
                         );\r
-        if (PrefixEntry != NULL) {\r
-          Ip6DestroyPrefixListEntry (IpSb, PrefixEntry, TRUE, FALSE);\r
+        if (PrefixEntry == NULL) {\r
+          Ip6CreatePrefixListEntry (\r
+            IpSb,\r
+            TRUE,\r
+            (UINT32) IP6_INFINIT_LIFETIME,\r
+            (UINT32) IP6_INFINIT_LIFETIME,\r
+            NewAddress->PrefixLength,\r
+            &NewAddress->Address\r
+            );\r
         }\r
 \r
         }\r
 \r
+        CurrentAddrInfo->IsAnycast = NewAddress->IsAnycast;\r
         //\r
         //\r
-        // Save the prefix length.\r
+        // Artificially mark this address passed DAD be'coz it is already in use.\r
+        //\r
+        Ip6ManualAddrDadCallback (TRUE, &NewAddress->Address, Instance);\r
+      } else {\r
+        //\r
+        // A new address.\r
         //\r
         //\r
-        CurrentAddrInfo->PrefixLength = NewAddress->PrefixLength;\r
         IsUpdated = TRUE;\r
         IsUpdated = TRUE;\r
+\r
+        //\r
+        // Set the new address, this will trigger DAD and activate the address if\r
+        // DAD succeeds.\r
+        //\r
+        Ip6SetAddress (\r
+          IpSb->DefaultInterface,\r
+          &NewAddress->Address,\r
+          NewAddress->IsAnycast,\r
+          NewAddress->PrefixLength,\r
+          (UINT32) IP6_INFINIT_LIFETIME,\r
+          (UINT32) IP6_INFINIT_LIFETIME,\r
+          Ip6ManualAddrDadCallback,\r
+          Instance\r
+          );\r
       }\r
       }\r
+    }\r
+\r
+    //\r
+    // Check the CurrentSourceList, it now contains those addresses currently in\r
+    // use and will be removed.\r
+    //\r
+    IpIf = IpSb->DefaultInterface;\r
+\r
+    while (!IsListEmpty (&CurrentSourceList)) {\r
+      IsUpdated = TRUE;\r
+\r
+      CurrentAddrInfo = NET_LIST_HEAD (&CurrentSourceList, IP6_ADDRESS_INFO, Link);\r
+\r
+      //\r
+      // This local address is going to be removed, the IP instances that are\r
+      // currently using it will be destroyed.\r
+      //\r
+      Ip6RemoveAddr (\r
+        IpSb,\r
+        &IpIf->AddressList,\r
+        &IpIf->AddressCount,\r
+        &CurrentAddrInfo->Address,\r
+        128\r
+        );\r
 \r
       //\r
 \r
       //\r
-      // create a new on-link prefix entry.\r
+      // Remove the on-link prefix table, the route entry will be removed\r
+      // implicitly.\r
       //\r
       PrefixEntry = Ip6FindPrefixListEntry (\r
                       IpSb,\r
                       TRUE,\r
       //\r
       PrefixEntry = Ip6FindPrefixListEntry (\r
                       IpSb,\r
                       TRUE,\r
-                      NewAddress->PrefixLength,\r
-                      &NewAddress->Address\r
+                      CurrentAddrInfo->PrefixLength,\r
+                      &CurrentAddrInfo->Address\r
                       );\r
                       );\r
-      if (PrefixEntry == NULL) {\r
-        Ip6CreatePrefixListEntry (\r
-          IpSb,\r
-          TRUE,\r
-          (UINT32) IP6_INFINIT_LIFETIME,\r
-          (UINT32) IP6_INFINIT_LIFETIME,\r
-          NewAddress->PrefixLength,\r
-          &NewAddress->Address\r
-          );\r
+      if (PrefixEntry != NULL) {\r
+        Ip6DestroyPrefixListEntry (IpSb, PrefixEntry, TRUE, FALSE);\r
       }\r
 \r
       }\r
 \r
-      CurrentAddrInfo->IsAnycast = NewAddress->IsAnycast;\r
-      //\r
-      // Artificially mark this address passed DAD be'coz it is already in use.\r
-      //\r
-      Ip6ManualAddrDadCallback (TRUE, &NewAddress->Address, Instance);\r
+      RemoveEntryList (&CurrentAddrInfo->Link);\r
+      FreePool (CurrentAddrInfo);\r
+    }\r
+\r
+    if (IsUpdated) {\r
+      if (DataItem->Status == EFI_NOT_READY) {\r
+        //\r
+        // If DAD is disabled on this interface, the configuration process is\r
+        // actually synchronous, and the data item's status will be changed to\r
+        // the final status before we reach here, just check it.\r
+        //\r
+        Status = EFI_NOT_READY;\r
+      } else {\r
+        Status = EFI_SUCCESS;\r
+      }\r
     } else {\r
       //\r
     } else {\r
       //\r
-      // A new address.\r
+      // No update is taken, reset the status to success and return EFI_ABORTED.\r
       //\r
       //\r
-      IsUpdated = TRUE;\r
+      DataItem->Status = EFI_SUCCESS;\r
+      Status           = EFI_ABORTED;\r
+    }\r
+  } else {\r
+    //\r
+    // DataSize is 0 and Data is NULL, clean up the manual address.\r
+    //\r
+    if (DataItem->Data.Ptr != NULL) {\r
+      FreePool (DataItem->Data.Ptr);\r
+    }\r
+    DataItem->Data.Ptr = NULL;\r
+    DataItem->DataSize = 0;\r
+    DataItem->Status   = EFI_NOT_FOUND;\r
 \r
 \r
-      //\r
-      // Set the new address, this will trigger DAD and activate the address if\r
-      // DAD succeeds.\r
-      //\r
-      Ip6SetAddress (\r
-        IpSb->DefaultInterface,\r
-        &NewAddress->Address,\r
-        NewAddress->IsAnycast,\r
-        NewAddress->PrefixLength,\r
+    Ip6CleanDefaultRouterList (IpSb);\r
+    Ip6CleanPrefixListTable (IpSb, &IpSb->OnlinkPrefix);\r
+    Ip6CleanPrefixListTable (IpSb, &IpSb->AutonomousPrefix);\r
+    Ip6CleanAssembleTable (&IpSb->Assemble);\r
+\r
+    if (IpSb->LinkLocalOk) {\r
+      Ip6CreatePrefixListEntry (\r
+        IpSb,\r
+        TRUE,\r
         (UINT32) IP6_INFINIT_LIFETIME,\r
         (UINT32) IP6_INFINIT_LIFETIME,\r
         (UINT32) IP6_INFINIT_LIFETIME,\r
         (UINT32) IP6_INFINIT_LIFETIME,\r
-        Ip6ManualAddrDadCallback,\r
-        Instance\r
+        IP6_LINK_LOCAL_PREFIX_LENGTH,\r
+        &IpSb->LinkLocalAddr\r
         );\r
     }\r
         );\r
     }\r
-  }\r
-\r
-  //\r
-  // Check the CurrentSourceList, it now contains those addresses currently in\r
-  // use and will be removed.\r
-  //\r
-  IpIf = IpSb->DefaultInterface;\r
-\r
-  while (!IsListEmpty (&CurrentSourceList)) {\r
-    IsUpdated = TRUE;\r
 \r
 \r
-    CurrentAddrInfo = NET_LIST_HEAD (&CurrentSourceList, IP6_ADDRESS_INFO, Link);\r
-\r
-    //\r
-    // This local address is going to be removed, the IP instances that are\r
-    // currently using it will be destroyed.\r
-    //\r
     Ip6RemoveAddr (\r
       IpSb,\r
     Ip6RemoveAddr (\r
       IpSb,\r
-      &IpIf->AddressList,\r
-      &IpIf->AddressCount,\r
-      &CurrentAddrInfo->Address,\r
-      128\r
+      &IpSb->DefaultInterface->AddressList,\r
+      &IpSb->DefaultInterface->AddressCount,\r
+      NULL,\r
+      0\r
       );\r
 \r
       );\r
 \r
-    //\r
-    // Remove the on-link prefix table, the route entry will be removed\r
-    // implicitly.\r
-    //\r
-    PrefixEntry = Ip6FindPrefixListEntry (\r
-                    IpSb,\r
-                    TRUE,\r
-                    CurrentAddrInfo->PrefixLength,\r
-                    &CurrentAddrInfo->Address\r
-                    );\r
-    if (PrefixEntry != NULL) {\r
-      Ip6DestroyPrefixListEntry (IpSb, PrefixEntry, TRUE, FALSE);\r
-    }\r
-\r
-    RemoveEntryList (&CurrentAddrInfo->Link);\r
-    FreePool (CurrentAddrInfo);\r
-  }\r
-\r
-  if (IsUpdated) {\r
-    if (DataItem->Status == EFI_NOT_READY) {\r
+    NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
       //\r
       //\r
-      // If DAD is disabled on this interface, the configuration process is\r
-      // actually synchronous, and the data item's status will be changed to\r
-      // the final status before we reach here, just check it.\r
+      // Remove all pending delay node and DAD entries for the global addresses.\r
       //\r
       //\r
-      Status = EFI_NOT_READY;\r
-    } else {\r
-      Status = EFI_SUCCESS;\r
+      IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);\r
+\r
+      NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DelayJoinList) {\r
+        DelayNode = NET_LIST_USER_STRUCT (Entry2, IP6_DELAY_JOIN_LIST, Link);\r
+        if (!NetIp6IsLinkLocalAddr (&DelayNode->AddressInfo->Address)) {\r
+          RemoveEntryList (&DelayNode->Link);\r
+          FreePool (DelayNode);\r
+        }\r
+      }\r
+\r
+      NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DupAddrDetectList) {\r
+        DadEntry = NET_LIST_USER_STRUCT_S (Entry2, IP6_DAD_ENTRY, Link, IP6_DAD_ENTRY_SIGNATURE);\r
+\r
+        if (!NetIp6IsLinkLocalAddr (&DadEntry->AddressInfo->Address)) {\r
+          //\r
+          // Fail this DAD entry if the address is not link-local.\r
+          //\r
+          Ip6OnDADFinished (FALSE, IpIf, DadEntry);\r
+        }\r
+      }\r
     }\r
     }\r
-  } else {\r
-    //\r
-    // No update is taken, reset the status to success and return EFI_ABORTED.\r
-    //\r
-    DataItem->Status = EFI_SUCCESS;\r
-    Status           = EFI_ABORTED;\r
   }\r
 \r
   return Status;\r
   }\r
 \r
   return Status;\r
@@ -1210,7 +1323,15 @@ Ip6ConfigSetGateway (
   IP6_DEFAULT_ROUTER    *DefaultRouter;\r
   VOID                  *Tmp;\r
 \r
   IP6_DEFAULT_ROUTER    *DefaultRouter;\r
   VOID                  *Tmp;\r
 \r
-  if ((DataSize % sizeof (EFI_IPv6_ADDRESS) != 0) || (DataSize == 0)) {\r
+  OldGateway      = NULL;\r
+  NewGateway      = NULL;\r
+  Item            = NULL;\r
+  DefaultRouter   = NULL;\r
+  Tmp             = NULL;\r
+  OneRemoved      = FALSE;\r
+  OneAdded        = FALSE;\r
+\r
+  if ((DataSize != 0) && (DataSize % sizeof (EFI_IPv6_ADDRESS) != 0)) {\r
     return EFI_BAD_BUFFER_SIZE;\r
   }\r
 \r
     return EFI_BAD_BUFFER_SIZE;\r
   }\r
 \r
@@ -1218,86 +1339,87 @@ Ip6ConfigSetGateway (
     return EFI_WRITE_PROTECTED;\r
   }\r
 \r
     return EFI_WRITE_PROTECTED;\r
   }\r
 \r
-  NewGateway      = (EFI_IPv6_ADDRESS *) Data;\r
-  NewGatewayCount = DataSize / sizeof (EFI_IPv6_ADDRESS);\r
-  for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {\r
-\r
-    if (!NetIp6IsValidUnicast (NewGateway + Index1)) {\r
-\r
-      return EFI_INVALID_PARAMETER;\r
-    }\r
-\r
-    for (Index2 = Index1 + 1; Index2 < NewGatewayCount; Index2++) {\r
-      if (EFI_IP6_EQUAL (NewGateway + Index1, NewGateway + Index2)) {\r
-        return EFI_INVALID_PARAMETER;\r
-      }\r
-    }\r
-  }\r
-\r
   IpSb            = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
   Item            = &Instance->DataItem[Ip6ConfigDataTypeGateway];\r
   OldGateway      = Item->Data.Gateway;\r
   OldGatewayCount = Item->DataSize / sizeof (EFI_IPv6_ADDRESS);\r
   IpSb            = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
   Item            = &Instance->DataItem[Ip6ConfigDataTypeGateway];\r
   OldGateway      = Item->Data.Gateway;\r
   OldGatewayCount = Item->DataSize / sizeof (EFI_IPv6_ADDRESS);\r
-  OneRemoved      = FALSE;\r
-  OneAdded        = FALSE;\r
-\r
-  if (NewGatewayCount != OldGatewayCount) {\r
-    Tmp = AllocatePool (DataSize);\r
-    if (Tmp == NULL) {\r
-      return EFI_OUT_OF_RESOURCES;\r
-    }\r
-  } else {\r
-    Tmp = NULL;\r
-  }\r
 \r
   for (Index1 = 0; Index1 < OldGatewayCount; Index1++) {\r
     //\r
 \r
   for (Index1 = 0; Index1 < OldGatewayCount; Index1++) {\r
     //\r
-    // Find the gateways that are no long in the new setting and remove them.\r
+    // Remove this default router.\r
     //\r
     //\r
-    for (Index2 = 0; Index2 < NewGatewayCount; Index2++) {\r
-      if (EFI_IP6_EQUAL (OldGateway + Index1, NewGateway + Index2)) {\r
-        OneRemoved = TRUE;\r
-        break;\r
+    DefaultRouter = Ip6FindDefaultRouter (IpSb, OldGateway + Index1);\r
+    if (DefaultRouter != NULL) {\r
+      Ip6DestroyDefaultRouter (IpSb, DefaultRouter);\r
+      OneRemoved = TRUE;\r
+    }\r
+  }\r
+\r
+  if (Data != NULL && DataSize != 0) {\r
+    NewGateway      = (EFI_IPv6_ADDRESS *) Data;\r
+    NewGatewayCount = DataSize / sizeof (EFI_IPv6_ADDRESS);\r
+    for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {\r
+\r
+      if (!NetIp6IsValidUnicast (NewGateway + Index1)) {\r
+\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+\r
+      for (Index2 = Index1 + 1; Index2 < NewGatewayCount; Index2++) {\r
+        if (EFI_IP6_EQUAL (NewGateway + Index1, NewGateway + Index2)) {\r
+          return EFI_INVALID_PARAMETER;\r
+        }\r
       }\r
     }\r
 \r
       }\r
     }\r
 \r
-    if (Index2 == NewGatewayCount) {\r
-      //\r
-      // Remove this default router.\r
-      //\r
-      DefaultRouter = Ip6FindDefaultRouter (IpSb, OldGateway + Index1);\r
-      if (DefaultRouter != NULL) {\r
-        Ip6DestroyDefaultRouter (IpSb, DefaultRouter);\r
+    if (NewGatewayCount != OldGatewayCount) {\r
+      Tmp = AllocatePool (DataSize);\r
+      if (Tmp == NULL) {\r
+        return EFI_OUT_OF_RESOURCES;\r
       }\r
       }\r
+    } else {\r
+      Tmp = NULL;\r
     }\r
     }\r
-  }\r
 \r
 \r
-  for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {\r
+    for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {\r
 \r
 \r
-    DefaultRouter = Ip6FindDefaultRouter (IpSb, NewGateway + Index1);\r
-    if (DefaultRouter == NULL) {\r
-      Ip6CreateDefaultRouter (IpSb, NewGateway + Index1, IP6_INF_ROUTER_LIFETIME);\r
-      OneAdded = TRUE;\r
+      DefaultRouter = Ip6FindDefaultRouter (IpSb, NewGateway + Index1);\r
+      if (DefaultRouter == NULL) {\r
+        Ip6CreateDefaultRouter (IpSb, NewGateway + Index1, IP6_INF_ROUTER_LIFETIME);\r
+        OneAdded = TRUE;\r
+      }\r
     }\r
     }\r
-  }\r
 \r
 \r
-  if (!OneRemoved && !OneAdded) {\r
-    Item->Status = EFI_SUCCESS;\r
-    return EFI_ABORTED;\r
-  } else {\r
+    if (!OneRemoved && !OneAdded) {\r
+      Item->Status = EFI_SUCCESS;\r
+      return EFI_ABORTED;\r
+    } else {\r
 \r
 \r
-    if (Tmp != NULL) {\r
-      if (Item->Data.Ptr != NULL) {\r
-        FreePool (Item->Data.Ptr);\r
+      if (Tmp != NULL) {\r
+        if (Item->Data.Ptr != NULL) {\r
+          FreePool (Item->Data.Ptr);\r
+        }\r
+        Item->Data.Ptr = Tmp;\r
       }\r
       }\r
-      Item->Data.Ptr = Tmp;\r
-    }\r
 \r
 \r
-    CopyMem (Item->Data.Ptr, Data, DataSize);\r
-    Item->DataSize = DataSize;\r
-    Item->Status   = EFI_SUCCESS;\r
-    return EFI_SUCCESS;\r
+      CopyMem (Item->Data.Ptr, Data, DataSize);\r
+      Item->DataSize = DataSize;\r
+      Item->Status   = EFI_SUCCESS;\r
+      return EFI_SUCCESS;\r
+    }\r
+  } else {\r
+    //\r
+    // DataSize is 0 and Data is NULL, clean up the Gateway address.\r
+    //\r
+    if (Item->Data.Ptr != NULL) {\r
+      FreePool (Item->Data.Ptr);\r
+    }\r
+    Item->Data.Ptr = NULL;\r
+    Item->DataSize = 0;\r
+    Item->Status   = EFI_NOT_FOUND;\r
   }\r
   }\r
+\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
 }\r
 \r
 /**\r
@@ -1339,7 +1461,12 @@ Ip6ConfigSetDnsServer (
   BOOLEAN               OneAdded;\r
   VOID                  *Tmp;\r
 \r
   BOOLEAN               OneAdded;\r
   VOID                  *Tmp;\r
 \r
-  if ((DataSize % sizeof (EFI_IPv6_ADDRESS) != 0) || (DataSize == 0)) {\r
+  OldDns = NULL;\r
+  NewDns = NULL;\r
+  Item   = NULL;\r
+  Tmp    = NULL;\r
+\r
+  if ((DataSize != 0) && (DataSize % sizeof (EFI_IPv6_ADDRESS) != 0)) {\r
     return EFI_BAD_BUFFER_SIZE;\r
   }\r
 \r
     return EFI_BAD_BUFFER_SIZE;\r
   }\r
 \r
@@ -1347,75 +1474,89 @@ Ip6ConfigSetDnsServer (
     return EFI_WRITE_PROTECTED;\r
   }\r
 \r
     return EFI_WRITE_PROTECTED;\r
   }\r
 \r
-  Item        = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];\r
-  NewDns      = (EFI_IPv6_ADDRESS *) Data;\r
-  OldDns      = Item->Data.DnsServers;\r
-  NewDnsCount = DataSize / sizeof (EFI_IPv6_ADDRESS);\r
-  OldDnsCount = Item->DataSize / sizeof (EFI_IPv6_ADDRESS);\r
-  OneAdded    = FALSE;\r
-\r
-  if (NewDnsCount != OldDnsCount) {\r
-    Tmp = AllocatePool (DataSize);\r
-    if (Tmp == NULL) {\r
-      return EFI_OUT_OF_RESOURCES;\r
-    }\r
-  } else {\r
-    Tmp = NULL;\r
-  }\r
+  Item = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];\r
 \r
 \r
-  for (NewIndex = 0; NewIndex < NewDnsCount; NewIndex++) {\r
+  if (Data != NULL && DataSize != 0) {\r
+    NewDns      = (EFI_IPv6_ADDRESS *) Data;\r
+    OldDns      = Item->Data.DnsServers;\r
+    NewDnsCount = DataSize / sizeof (EFI_IPv6_ADDRESS);\r
+    OldDnsCount = Item->DataSize / sizeof (EFI_IPv6_ADDRESS);\r
+    OneAdded    = FALSE;\r
 \r
 \r
-    if (!NetIp6IsValidUnicast (NewDns + NewIndex)) {\r
-      //\r
-      // The dns server address must be unicast.\r
-      //\r
-      if (Tmp != NULL) {\r
-        FreePool (Tmp);\r
+    if (NewDnsCount != OldDnsCount) {\r
+      Tmp = AllocatePool (DataSize);\r
+      if (Tmp == NULL) {\r
+        return EFI_OUT_OF_RESOURCES;\r
       }\r
       }\r
-      return EFI_INVALID_PARAMETER;\r
+    } else {\r
+      Tmp = NULL;\r
     }\r
 \r
     }\r
 \r
-    if (OneAdded) {\r
-      //\r
-      // If any address in the new setting is not in the old settings, skip the\r
-      // comparision below.\r
-      //\r
-      continue;\r
-    }\r
+    for (NewIndex = 0; NewIndex < NewDnsCount; NewIndex++) {\r
 \r
 \r
-    for (OldIndex = 0; OldIndex < OldDnsCount; OldIndex++) {\r
-      if (EFI_IP6_EQUAL (NewDns + NewIndex, OldDns + OldIndex)) {\r
+      if (!NetIp6IsValidUnicast (NewDns + NewIndex)) {\r
         //\r
         //\r
-        // If found break out.\r
+        // The dns server address must be unicast.\r
         //\r
         //\r
-        break;\r
+        if (Tmp != NULL) {\r
+          FreePool (Tmp);\r
+        }\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+\r
+      if (OneAdded) {\r
+        //\r
+        // If any address in the new setting is not in the old settings, skip the\r
+        // comparision below.\r
+        //\r
+        continue;\r
+      }\r
+\r
+      for (OldIndex = 0; OldIndex < OldDnsCount; OldIndex++) {\r
+        if (EFI_IP6_EQUAL (NewDns + NewIndex, OldDns + OldIndex)) {\r
+          //\r
+          // If found break out.\r
+          //\r
+          break;\r
+        }\r
       }\r
       }\r
-    }\r
 \r
 \r
-    if (OldIndex == OldDnsCount) {\r
-      OneAdded = TRUE;\r
+      if (OldIndex == OldDnsCount) {\r
+        OneAdded = TRUE;\r
+      }\r
     }\r
     }\r
-  }\r
 \r
 \r
-  if (!OneAdded && (DataSize == Item->DataSize)) {\r
+    if (!OneAdded && (DataSize == Item->DataSize)) {\r
+      //\r
+      // No new item is added and the size is the same.\r
+      //\r
+      Item->Status = EFI_SUCCESS;\r
+      return EFI_ABORTED;\r
+    } else {\r
+      if (Tmp != NULL) {\r
+        if (Item->Data.Ptr != NULL) {\r
+          FreePool (Item->Data.Ptr);\r
+        }\r
+        Item->Data.Ptr = Tmp;\r
+      }\r
+\r
+      CopyMem (Item->Data.Ptr, Data, DataSize);\r
+      Item->DataSize = DataSize;\r
+      Item->Status   = EFI_SUCCESS;\r
+    }\r
+  } else  {\r
     //\r
     //\r
-    // No new item is added and the size is the same.\r
+    // DataSize is 0 and Data is NULL, clean up the DnsServer address.\r
     //\r
     //\r
-    Item->Status = EFI_SUCCESS;\r
-    return EFI_ABORTED;\r
-  } else {\r
-    if (Tmp != NULL) {\r
-      if (Item->Data.Ptr != NULL) {\r
-        FreePool (Item->Data.Ptr);\r
-      }\r
-      Item->Data.Ptr = Tmp;\r
+    if (Item->Data.Ptr != NULL) {\r
+      FreePool (Item->Data.Ptr);\r
     }\r
     }\r
-\r
-    CopyMem (Item->Data.Ptr, Data, DataSize);\r
-    Item->DataSize = DataSize;\r
-    Item->Status   = EFI_SUCCESS;\r
-    return EFI_SUCCESS;\r
+    Item->Data.Ptr = NULL;\r
+    Item->DataSize = 0;\r
+    Item->Status   = EFI_NOT_FOUND;\r
   }\r
   }\r
+\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
 }\r
 \r
 /**\r
@@ -1824,9 +1965,8 @@ Ip6ConfigOnDhcp6SbInstalled (
                                 network stack was set successfully.\r
   @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:\r
                                 - This is NULL.\r
                                 network stack was set successfully.\r
   @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:\r
                                 - This is NULL.\r
-                                - Data is NULL.\r
-                                - One or more fields in Data do not match the requirement of the\r
-                                  data type indicated by DataType.\r
+                                - One or more fields in Data and DataSizedo not match the\r
+                                  requirement of the data type indicated by DataType.\r
   @retval EFI_WRITE_PROTECTED   The specified configuration data is read-only or the specified\r
                                 configuration data cannot be set under the current policy.\r
   @retval EFI_ACCESS_DENIED     Another set operation on the specified configuration\r
   @retval EFI_WRITE_PROTECTED   The specified configuration data is read-only or the specified\r
                                 configuration data cannot be set under the current policy.\r
   @retval EFI_ACCESS_DENIED     Another set operation on the specified configuration\r
@@ -1854,7 +1994,7 @@ EfiIp6ConfigSetData (
   IP6_CONFIG_INSTANCE  *Instance;\r
   IP6_SERVICE          *IpSb;\r
 \r
   IP6_CONFIG_INSTANCE  *Instance;\r
   IP6_SERVICE          *IpSb;\r
 \r
-  if ((This == NULL) || (Data == NULL)) {\r
+  if ((This == NULL) || (Data == NULL && DataSize != 0) || (Data != NULL && DataSize == 0)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r