NetworkPkg/Ip6Dxe: Support SetData interface to clear specific configuration
authorJiaxin Wu <jiaxin.wu@intel.com>
Tue, 28 Feb 2017 00:35:26 +0000 (08:35 +0800)
committerJiaxin Wu <jiaxin.wu@intel.com>
Fri, 11 Aug 2017 04:58:12 +0000 (12:58 +0800)
UEFI Spec 2.7 adds the clarification on SetData interface usage to clear specific
individual data types. This patch is to support this feature.

Cc: Ye Ting <ting.ye@intel.com>
Cc: Fu Siyuan <siyuan.fu@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Wu Jiaxin <jiaxin.wu@intel.com>
Reviewed-by: Ye Ting <ting.ye@intel.com>
NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c

index f170716..61418e2 100644 (file)
@@ -953,10 +953,26 @@ Ip6ConfigSetManualAddress (
   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
-  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
@@ -964,239 +980,302 @@ Ip6ConfigSetManualAddress (
     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
-  for (Index1 = 0; Index1 < NewAddressCount; Index1++, NewAddress++) {\r
+  DataItem = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];\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
-    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
+      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
+\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
-  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
-  // 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
-  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
-    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
-      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
+    // 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
-      InsertTailList (&CurrentSourceList, &Copy->Link);\r
-      CurrentSourceCount++;\r
+      return EFI_OUT_OF_RESOURCES;\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
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
+    //\r
+    // Trigger DAD, it's an asynchronous process.\r
+    //\r
+    IsUpdated  = FALSE;\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
-  // 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
-  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
-      // 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
-      // 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
+        // create a new on-link prefix entry.\r
         //\r
         PrefixEntry = Ip6FindPrefixListEntry (\r
                         IpSb,\r
                         TRUE,\r
-                        CurrentAddrInfo->PrefixLength,\r
-                        &CurrentAddrInfo->Address\r
+                        NewAddress->PrefixLength,\r
+                        &NewAddress->Address\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
+        CurrentAddrInfo->IsAnycast = NewAddress->IsAnycast;\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
-        CurrentAddrInfo->PrefixLength = NewAddress->PrefixLength;\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
+    // 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
-      // create a new on-link prefix entry.\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
+      // Remove the on-link prefix table, the route entry will be removed\r
+      // implicitly.\r
       //\r
       PrefixEntry = Ip6FindPrefixListEntry (\r
                       IpSb,\r
                       TRUE,\r
-                      NewAddress->PrefixLength,\r
-                      &NewAddress->Address\r
+                      CurrentAddrInfo->PrefixLength,\r
+                      &CurrentAddrInfo->Address\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
-      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
-      // A new address.\r
+      // No update is taken, reset the status to success and return EFI_ABORTED.\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
-      // 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
-        Ip6ManualAddrDadCallback,\r
-        Instance\r
+        IP6_LINK_LOCAL_PREFIX_LENGTH,\r
+        &IpSb->LinkLocalAddr\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
+      &IpSb->DefaultInterface->AddressList,\r
+      &IpSb->DefaultInterface->AddressCount,\r
+      NULL,\r
+      0\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
-      // 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
-      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
-  } 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
@@ -1244,7 +1323,15 @@ Ip6ConfigSetGateway (
   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
@@ -1252,86 +1339,87 @@ Ip6ConfigSetGateway (
     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
-  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
-    // Find the gateways that are no long in the new setting and remove them.\r
+    // Remove this default router.\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
-    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
+    } else {\r
+      Tmp = NULL;\r
     }\r
-  }\r
 \r
-  for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {\r
+    for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {\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
-  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
-    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
-      Item->Data.Ptr = Tmp;\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
+  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
@@ -1373,7 +1461,12 @@ Ip6ConfigSetDnsServer (
   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
@@ -1381,75 +1474,89 @@ Ip6ConfigSetDnsServer (
     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
-  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
-    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
-      return EFI_INVALID_PARAMETER;\r
+    } else {\r
+      Tmp = NULL;\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
-    for (OldIndex = 0; OldIndex < OldDnsCount; OldIndex++) {\r
-      if (EFI_IP6_EQUAL (NewDns + NewIndex, OldDns + OldIndex)) {\r
+      if (!NetIp6IsValidUnicast (NewDns + NewIndex)) {\r
         //\r
-        // If found break out.\r
+        // The dns server address must be unicast.\r
         //\r
-        break;\r
+        if (Tmp != NULL) {\r
+          FreePool (Tmp);\r
+        }\r
+        return EFI_INVALID_PARAMETER;\r
       }\r
-    }\r
 \r
-    if (OldIndex == OldDnsCount) {\r
-      OneAdded = TRUE;\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
+      if (OldIndex == OldDnsCount) {\r
+        OneAdded = TRUE;\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
-    // 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
-    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
-    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
+  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
@@ -1858,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
-                                - 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
@@ -1888,7 +1994,7 @@ EfiIp6ConfigSetData (
   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