]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Config2Impl.c
BaseTools:Change the path of the file that Binary Cache
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4Dxe / Ip4Config2Impl.c
index 637d7cd65993bec79c332e0703d9eb398a8ecf59..9dca48ddd6458044b089ed6b492ee29b8a365a0d 100644 (file)
@@ -1,15 +1,10 @@
 /** @file\r
   The implementation of EFI IPv4 Configuration II Protocol.\r
 \r
-  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r
+  (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<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
@@ -81,7 +76,7 @@ Ip4Config2DestroyDhcp4 (
 \r
   Instance->Dhcp4Handle = NULL;\r
 \r
-  return Status;  \r
+  return Status;\r
 }\r
 \r
 /**\r
@@ -111,7 +106,7 @@ Ip4Config2OnPolicyChanged (
   if (IpSb->DefaultInterface != NULL) {\r
     if (IpSb->DefaultRouteTable != NULL) {\r
       Ip4FreeRouteTable (IpSb->DefaultRouteTable);\r
-      IpSb->DefaultRouteTable = NULL;    \r
+      IpSb->DefaultRouteTable = NULL;\r
     }\r
 \r
     Ip4CancelReceive (IpSb->DefaultInterface);\r
@@ -124,7 +119,7 @@ Ip4Config2OnPolicyChanged (
 \r
   //\r
   // Create new default interface and route table.\r
-  //    \r
+  //\r
   IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);\r
   if (IpIf == NULL) {\r
     return ;\r
@@ -135,13 +130,13 @@ Ip4Config2OnPolicyChanged (
     Ip4FreeInterface (IpIf, NULL);\r
     return ;\r
   }\r
-  \r
+\r
   IpSb->DefaultInterface  = IpIf;\r
   InsertHeadList (&IpSb->Interfaces, &IpIf->Link);\r
   IpSb->DefaultRouteTable = RouteTable;\r
   Ip4ReceiveFrame (IpIf, NULL, Ip4AccpetFrame, IpSb);\r
 \r
-  if (IpSb->State == IP4_SERVICE_CONFIGED) {\r
+  if (IpSb->State == IP4_SERVICE_CONFIGED || IpSb->State == IP4_SERVICE_STARTED) {\r
     IpSb->State = IP4_SERVICE_UNSTARTED;\r
   }\r
 \r
@@ -149,7 +144,6 @@ Ip4Config2OnPolicyChanged (
   // Start the dhcp configuration.\r
   //\r
   if (NewPolicy == Ip4Config2PolicyDhcp) {\r
-    IpSb->Reconfig = TRUE;\r
     Ip4StartAutoConfig (&IpSb->Ip4Config2Instance);\r
   }\r
 \r
@@ -255,7 +249,7 @@ Ip4Config2ReadConfigData (
       return EFI_NOT_FOUND;\r
     }\r
 \r
\r
+\r
     for (Index = 0; Index < Variable->DataRecordCount; Index++) {\r
 \r
       CopyMem (&DataRecord, &Variable->DataRecord[Index], sizeof (DataRecord));\r
@@ -375,8 +369,8 @@ Ip4Config2WriteConfigData (
 \r
 \r
 /**\r
-  Build a EFI_IP4_ROUTE_TABLE to be returned to the caller of GetModeData. \r
-  The EFI_IP4_ROUTE_TABLE is clumsy to use in the internal operation of the \r
+  Build a EFI_IP4_ROUTE_TABLE to be returned to the caller of GetModeData.\r
+  The EFI_IP4_ROUTE_TABLE is clumsy to use in the internal operation of the\r
   IP4 driver.\r
 \r
   @param[in]   IpSb        The IP4 service binding instance.\r
@@ -392,7 +386,7 @@ Ip4Config2BuildDefaultRouteTable (
   OUT EFI_IP4_ROUTE_TABLE       *Table\r
   )\r
 {\r
-  LIST_ENTRY                *Entry; \r
+  LIST_ENTRY                *Entry;\r
   IP4_ROUTE_ENTRY           *RtEntry;\r
   UINT32                    Count;\r
   INT32                     Index;\r
@@ -415,7 +409,7 @@ Ip4Config2BuildDefaultRouteTable (
   //\r
   Count = 0;\r
 \r
-  for (Index = IP4_MASK_NUM - 1; Index >= 0; Index--) {\r
+  for (Index = IP4_MASK_MAX; Index >= 0; Index--) {\r
 \r
     NET_LIST_FOR_EACH (Entry, &(IpSb->DefaultRouteTable->RouteArea[Index])) {\r
       RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);\r
@@ -468,8 +462,8 @@ Ip4Config2OnDhcp4SbInstalled (
   @param[in]  StationAddress     Ip address to be set.\r
   @param[in]  SubnetMask         Subnet to be set.\r
 \r
-  @retval EFI_SUCCESS   Set default address successful.     \r
-  @retval Others        Some errors occur in setting.     \r
+  @retval EFI_SUCCESS   Set default address successful.\r
+  @retval Others        Some errors occur in setting.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -501,7 +495,7 @@ Ip4Config2SetDefaultAddr (
     //\r
     if (IpSb->DefaultRouteTable != NULL) {\r
       Ip4FreeRouteTable (IpSb->DefaultRouteTable);\r
-      IpSb->DefaultRouteTable = NULL;    \r
+      IpSb->DefaultRouteTable = NULL;\r
     }\r
 \r
     Ip4CancelReceive (IpSb->DefaultInterface);\r
@@ -509,7 +503,7 @@ Ip4Config2SetDefaultAddr (
     IpSb->DefaultInterface = NULL;\r
     //\r
     // Create new default interface and route table.\r
-    //    \r
+    //\r
     IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);\r
     if (IpIf == NULL) {\r
       return EFI_OUT_OF_RESOURCES;\r
@@ -520,7 +514,7 @@ Ip4Config2SetDefaultAddr (
       Ip4FreeInterface (IpIf, NULL);\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
-    \r
+\r
     IpSb->DefaultInterface  = IpIf;\r
     InsertHeadList (&IpSb->Interfaces, &IpIf->Link);\r
     IpSb->DefaultRouteTable = RouteTable;\r
@@ -537,8 +531,8 @@ Ip4Config2SetDefaultAddr (
   }\r
 \r
   if (IpIf->Arp != NULL) {\r
-    //   \r
-    // A non-NULL IpIf->Arp here means a new ARP child is created when setting default address, \r
+    //\r
+    // A non-NULL IpIf->Arp here means a new ARP child is created when setting default address,\r
     // but some IP children may have referenced the default interface before it is configured,\r
     // these IP instances also consume this ARP protocol so they need to open it BY_CHILD_CONTROLLER.\r
     //\r
@@ -559,13 +553,6 @@ Ip4Config2SetDefaultAddr (
     }\r
   }\r
 \r
-  Ip4AddRoute (\r
-    IpSb->DefaultRouteTable,\r
-    StationAddress,\r
-    SubnetMask,\r
-    IP4_ALLZERO_ADDRESS\r
-    );\r
-\r
   //\r
   // Add a route for the connected network.\r
   //\r
@@ -580,20 +567,20 @@ Ip4Config2SetDefaultAddr (
 \r
   IpSb->State = IP4_SERVICE_CONFIGED;\r
   IpSb->Reconfig = FALSE;\r
-  \r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
   Set the station address, subnetmask and gateway address for the default interface.\r
 \r
-  @param[in]  Instance         The pointer to the IP4 config2 instance data.  \r
+  @param[in]  Instance         The pointer to the IP4 config2 instance data.\r
   @param[in]  StationAddress   Ip address to be set.\r
   @param[in]  SubnetMask       Subnet to be set.\r
   @param[in]  GatewayAddress   Gateway to be set.\r
 \r
-  @retval EFI_SUCCESS     Set default If successful.    \r
-  @retval Others          Errors occur as indicated.  \r
+  @retval EFI_SUCCESS     Set default If successful.\r
+  @retval Others          Errors occur as indicated.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -609,6 +596,13 @@ Ip4Config2SetDefaultIf (
 \r
   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);\r
 \r
+  //\r
+  // Check whether the StationAddress/SubnetMask pair is valid.\r
+  //\r
+  if (!Ip4StationAddressValid (StationAddress, SubnetMask)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
   Status = Ip4Config2SetDefaultAddr (IpSb, StationAddress, SubnetMask);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
@@ -623,7 +617,7 @@ Ip4Config2SetDefaultIf (
       IP4_ALLZERO_ADDRESS,\r
       IP4_ALLZERO_ADDRESS,\r
       GatewayAddress\r
-      );        \r
+      );\r
   }\r
 \r
   return EFI_SUCCESS;\r
@@ -677,6 +671,119 @@ Ip4Config2CleanDhcp4 (
   }\r
 }\r
 \r
+/**\r
+  This worker function sets the DNS server list for the EFI IPv4 network\r
+  stack running on the communication device that this EFI_IP4_CONFIG2_PROTOCOL\r
+  manages. The DNS server addresses must be unicast IPv4 addresses.\r
+\r
+  @param[in]     Instance        The pointer to the IP4 config2 instance data.\r
+  @param[in]     DataSize        The size of the buffer pointed to by Data in bytes.\r
+  @param[in]     Data            The data buffer to set, points to an array of\r
+                                 EFI_IPv4_ADDRESS instances.\r
+\r
+  @retval EFI_BAD_BUFFER_SIZE    The DataSize does not match the size of the type.\r
+  @retval EFI_INVALID_PARAMETER  One or more fields in Data is invalid.\r
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate resources to complete the operation.\r
+  @retval EFI_ABORTED            The DNS server addresses to be set equal the current\r
+                                 configuration.\r
+  @retval EFI_SUCCESS            The specified configuration data for the EFI IPv4\r
+                                 network stack was set.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4Config2SetDnsServerWorker (\r
+  IN IP4_CONFIG2_INSTANCE    *Instance,\r
+  IN UINTN                   DataSize,\r
+  IN VOID                    *Data\r
+  )\r
+{\r
+  UINTN                 OldIndex;\r
+  UINTN                 NewIndex;\r
+  EFI_IPv4_ADDRESS      *OldDns;\r
+  EFI_IPv4_ADDRESS      *NewDns;\r
+  UINTN                 OldDnsCount;\r
+  UINTN                 NewDnsCount;\r
+  IP4_CONFIG2_DATA_ITEM *Item;\r
+  BOOLEAN               OneAdded;\r
+  VOID                  *Tmp;\r
+  IP4_ADDR              DnsAddress;\r
+\r
+  if ((DataSize % sizeof (EFI_IPv4_ADDRESS) != 0) || (DataSize == 0)) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  Item        = &Instance->DataItem[Ip4Config2DataTypeDnsServer];\r
+  NewDns      = (EFI_IPv4_ADDRESS *) Data;\r
+  OldDns      = Item->Data.DnsServers;\r
+  NewDnsCount = DataSize / sizeof (EFI_IPv4_ADDRESS);\r
+  OldDnsCount = Item->DataSize / sizeof (EFI_IPv4_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
+\r
+  for (NewIndex = 0; NewIndex < NewDnsCount; NewIndex++) {\r
+    CopyMem (&DnsAddress, NewDns + NewIndex, sizeof (IP4_ADDR));\r
+    if (IP4_IS_UNSPECIFIED (NTOHL (DnsAddress)) || IP4_IS_LOCAL_BROADCAST (NTOHL (DnsAddress))) {\r
+      //\r
+      // The dns server address must be unicast.\r
+      //\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_IP4_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
+  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
+    return EFI_SUCCESS;\r
+  }\r
+}\r
+\r
+\r
 \r
 /**\r
   Callback function when DHCP process finished. It will save the\r
@@ -701,6 +808,9 @@ Ip4Config2OnDhcp4Complete (
   IP4_ADDR                  StationAddress;\r
   IP4_ADDR                  SubnetMask;\r
   IP4_ADDR                  GatewayAddress;\r
+  UINT32                    Index;\r
+  UINT32                    OptionCount;\r
+  EFI_DHCP4_PACKET_OPTION   **OptionList;\r
 \r
   Instance = (IP4_CONFIG2_INSTANCE *) Context;\r
   ASSERT (Instance->Dhcp4 != NULL);\r
@@ -723,7 +833,45 @@ Ip4Config2OnDhcp4Complete (
     if (EFI_ERROR (Status)) {\r
       goto Exit;\r
     }\r
-  \r
+\r
+    //\r
+    // Parse the ACK to get required DNS server information.\r
+    //\r
+    OptionCount = 0;\r
+    OptionList  = NULL;\r
+\r
+    Status      = Instance->Dhcp4->Parse (Instance->Dhcp4, Dhcp4Mode.ReplyPacket, &OptionCount, OptionList);\r
+    if (Status != EFI_BUFFER_TOO_SMALL) {\r
+      goto Exit;\r
+    }\r
+\r
+    OptionList = AllocateZeroPool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));\r
+    if (OptionList == NULL) {\r
+      goto Exit;\r
+    }\r
+\r
+    Status = Instance->Dhcp4->Parse (Instance->Dhcp4, Dhcp4Mode.ReplyPacket, &OptionCount, OptionList);\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (OptionList);\r
+      goto Exit;\r
+    }\r
+\r
+    for (Index = 0; Index < OptionCount; Index++) {\r
+      //\r
+      // Look for DNS Server opcode (6).\r
+      //\r
+      if (OptionList[Index]->OpCode == DHCP4_TAG_DNS_SERVER) {\r
+        if (((OptionList[Index]->Length & 0x3) != 0) || (OptionList[Index]->Length == 0)) {\r
+          break;\r
+        }\r
+\r
+        Ip4Config2SetDnsServerWorker (Instance, OptionList[Index]->Length, &OptionList[Index]->Data[0]);\r
+        break;\r
+      }\r
+    }\r
+\r
+    FreePool (OptionList);\r
+\r
     Instance->DhcpSuccess = TRUE;\r
   }\r
 \r
@@ -740,7 +888,7 @@ Exit:
 \r
   @param[in]  Instance           The IP4 config2 instance to configure\r
 \r
-  @retval EFI_SUCCESS            The auto configuration is successfull started\r
+  @retval EFI_SUCCESS            The auto configuration is successfully started\r
   @retval Others                 Failed to start auto configuration.\r
 \r
 **/\r
@@ -755,7 +903,6 @@ Ip4StartAutoConfig (
   EFI_DHCP4_PACKET_OPTION        *OptionList[1];\r
   IP4_CONFIG2_DHCP4_OPTION       ParaList;\r
   EFI_STATUS                     Status;\r
\r
 \r
   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);\r
 \r
@@ -809,8 +956,18 @@ Ip4StartAutoConfig (
                   IpSb->Controller,\r
                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
                   );\r
-  ASSERT_EFI_ERROR (Status);\r
+  if (EFI_ERROR (Status)) {\r
+    NetLibDestroyServiceChild (\r
+      IpSb->Controller,\r
+      IpSb->Image,\r
+      &gEfiDhcp4ServiceBindingProtocolGuid,\r
+      Instance->Dhcp4Handle\r
+      );\r
 \r
+    Instance->Dhcp4Handle = NULL;\r
+\r
+    return Status;\r
+  }\r
 \r
   //\r
   // Check the current DHCP status, if the DHCP process has\r
@@ -818,11 +975,10 @@ Ip4StartAutoConfig (
   //\r
   Dhcp4  = Instance->Dhcp4;\r
   Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4Mode);\r
-\r
   if (Dhcp4Mode.State == Dhcp4Bound) {\r
     Ip4Config2OnDhcp4Complete (NULL, Instance);\r
-    return EFI_SUCCESS;\r
 \r
+    return EFI_SUCCESS;\r
   }\r
 \r
   //\r
@@ -830,20 +986,38 @@ Ip4StartAutoConfig (
   // DHCP configuration to avoid problems if some DHCP client\r
   // yields the control of this DHCP service to us.\r
   //\r
-  ParaList.Head.OpCode             = DHCP_TAG_PARA_LIST;\r
-  ParaList.Head.Length             = 2;\r
-  ParaList.Head.Data[0]            = DHCP_TAG_NETMASK;\r
-  ParaList.Route                   = DHCP_TAG_ROUTER;\r
+  ParaList.Head.OpCode             = DHCP4_TAG_PARA_LIST;\r
+  ParaList.Head.Length             = 3;\r
+  ParaList.Head.Data[0]            = DHCP4_TAG_NETMASK;\r
+  ParaList.Route                   = DHCP4_TAG_ROUTER;\r
+  ParaList.Dns                     = DHCP4_TAG_DNS_SERVER;\r
   OptionList[0]                    = &ParaList.Head;\r
   Dhcp4Mode.ConfigData.OptionCount = 1;\r
   Dhcp4Mode.ConfigData.OptionList  = OptionList;\r
 \r
   Status = Dhcp4->Configure (Dhcp4, &Dhcp4Mode.ConfigData);\r
-\r
   if (EFI_ERROR (Status)) {\r
+    gBS->CloseProtocol (\r
+           Instance->Dhcp4Handle,\r
+           &gEfiDhcp4ProtocolGuid,\r
+           IpSb->Image,\r
+           IpSb->Controller\r
+           );\r
+\r
+    NetLibDestroyServiceChild (\r
+      IpSb->Controller,\r
+      IpSb->Image,\r
+      &gEfiDhcp4ServiceBindingProtocolGuid,\r
+      Instance->Dhcp4Handle\r
+      );\r
+\r
+    Instance->Dhcp4 = NULL;\r
+\r
+    Instance->Dhcp4Handle = NULL;\r
+\r
     return Status;\r
   }\r
-  \r
+\r
   //\r
   // Start the DHCP process\r
   //\r
@@ -854,27 +1028,30 @@ Ip4StartAutoConfig (
                   Instance,\r
                   &Instance->Dhcp4Event\r
                   );\r
-\r
   if (EFI_ERROR (Status)) {\r
+    Ip4Config2DestroyDhcp4 (Instance);\r
     return Status;\r
   }\r
 \r
   Status = Dhcp4->Start (Dhcp4, Instance->Dhcp4Event);\r
-\r
   if (EFI_ERROR (Status)) {\r
+    Ip4Config2DestroyDhcp4 (Instance);\r
+    gBS->CloseEvent (Instance->Dhcp4Event);\r
+    Instance->Dhcp4Event = NULL;\r
+\r
     return Status;\r
   }\r
\r
-  IpSb->State     = IP4_SERVICE_STARTED;\r
+\r
+  IpSb->State = IP4_SERVICE_STARTED;\r
   DispatchDpc ();\r
-  return EFI_SUCCESS;\r
 \r
+  return EFI_SUCCESS;\r
 }\r
 \r
 \r
 \r
 /**\r
-  The work function is to get the interface information of the communication \r
+  The work function is to get the interface information of the communication\r
   device this IP4_CONFIG2_INSTANCE manages.\r
 \r
   @param[in]      Instance Pointer to the IP4 config2 instance data.\r
@@ -897,7 +1074,6 @@ Ip4Config2GetIfInfo (
   IN VOID                 *Data      OPTIONAL\r
   )\r
 {\r
-\r
   IP4_SERVICE                    *IpSb;\r
   UINTN                          Length;\r
   IP4_CONFIG2_DATA_ITEM          *Item;\r
@@ -910,7 +1086,7 @@ Ip4Config2GetIfInfo (
   if (IpSb->DefaultRouteTable != NULL) {\r
     Length += IpSb->DefaultRouteTable->TotalNum * sizeof (EFI_IP4_ROUTE_TABLE);\r
   }\r
-  \r
+\r
   if (*DataSize < Length) {\r
     *DataSize = Length;\r
     return EFI_BUFFER_TOO_SMALL;\r
@@ -937,14 +1113,14 @@ Ip4Config2GetIfInfo (
     IfInfo->RouteTableSize = IpSb->DefaultRouteTable->TotalNum;\r
     IfInfo->RouteTable   = (EFI_IP4_ROUTE_TABLE *) ((UINT8 *) Data + sizeof (EFI_IP4_CONFIG2_INTERFACE_INFO));\r
 \r
-    Ip4Config2BuildDefaultRouteTable (IpSb, IfInfo->RouteTable);  \r
+    Ip4Config2BuildDefaultRouteTable (IpSb, IfInfo->RouteTable);\r
   }\r
-  \r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
-  The work function is to set the general configuration policy for the EFI IPv4 network \r
+  The work function is to set the general configuration policy for the EFI IPv4 network\r
   stack that is running on the communication device managed by this IP4_CONFIG2_INSTANCE.\r
   The policy will affect other configuration settings.\r
 \r
@@ -981,40 +1157,43 @@ Ip4Config2SetPolicy (
   }\r
 \r
   if (NewPolicy == Instance->Policy) {\r
-     return EFI_ABORTED;\r
+    if (NewPolicy != Ip4Config2PolicyDhcp || Instance->DhcpSuccess) {\r
+      return EFI_ABORTED;\r
+    }\r
   } else {\r
-    if (NewPolicy == Ip4Config2PolicyDhcp) {\r
-      //\r
-      // The policy is changed from static to dhcp:\r
-      // Clean the ManualAddress, Gateway and DnsServers, shrink the variable\r
-      // data size, and fire up all the related events.\r
-      //\r
-      DataItem           = &Instance->DataItem[Ip4Config2DataTypeManualAddress];\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
-      NetMapIterate (&DataItem->EventMap, Ip4Config2SignalEvent, NULL);\r
+    //\r
+    // The policy is changed. Clean the ManualAddress, Gateway and DnsServers,\r
+    // shrink the variable data size, and fire up all the related events.\r
+    //\r
+    DataItem           = &Instance->DataItem[Ip4Config2DataTypeManualAddress];\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
+    NetMapIterate (&DataItem->EventMap, Ip4Config2SignalEvent, NULL);\r
 \r
-      DataItem           = &Instance->DataItem[Ip4Config2DataTypeGateway];\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
-      NetMapIterate (&DataItem->EventMap, Ip4Config2SignalEvent, NULL);\r
+    DataItem           = &Instance->DataItem[Ip4Config2DataTypeGateway];\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
+    NetMapIterate (&DataItem->EventMap, Ip4Config2SignalEvent, NULL);\r
 \r
-      DataItem           = &Instance->DataItem[Ip4Config2DataTypeDnsServer];\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
-      NetMapIterate (&DataItem->EventMap, Ip4Config2SignalEvent, NULL);\r
+    DataItem           = &Instance->DataItem[Ip4Config2DataTypeDnsServer];\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
+    NetMapIterate (&DataItem->EventMap, Ip4Config2SignalEvent, NULL);\r
+\r
+    if (NewPolicy == Ip4Config2PolicyDhcp) {\r
+      SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_VOLATILE);\r
     } else {\r
       //\r
       // The policy is changed from dhcp to static. Stop the DHCPv4 process\r
@@ -1023,12 +1202,13 @@ Ip4Config2SetPolicy (
       if (Instance->Dhcp4Handle != NULL) {\r
         Ip4Config2DestroyDhcp4 (Instance);\r
       }\r
-      \r
+\r
       //\r
       // Close the event.\r
       //\r
       if (Instance->Dhcp4Event != NULL) {\r
         gBS->CloseEvent (Instance->Dhcp4Event);\r
+        Instance->Dhcp4Event = NULL;\r
       }\r
     }\r
   }\r
@@ -1042,7 +1222,7 @@ Ip4Config2SetPolicy (
 }\r
 \r
 /**\r
-  The work function is to set the station addresses manually for the EFI IPv4 \r
+  The work function is to set the station addresses manually for the EFI IPv4\r
   network stack. It is only configurable when the policy is Ip4Config2PolicyStatic.\r
 \r
   @param[in]     Instance Pointer to the IP4 config2 instance data.\r
@@ -1063,7 +1243,7 @@ Ip4Config2SetPolicy (
 \r
 **/\r
 EFI_STATUS\r
-Ip4Config2SetMaunualAddress (\r
+Ip4Config2SetManualAddress (\r
   IN IP4_CONFIG2_INSTANCE *Instance,\r
   IN UINTN                DataSize,\r
   IN VOID                 *Data\r
@@ -1076,12 +1256,20 @@ Ip4Config2SetMaunualAddress (
   IP4_ADDR                       SubnetMask;\r
   VOID                           *Ptr;\r
   IP4_SERVICE                    *IpSb;\r
+  IP4_INTERFACE                  *IpIf;\r
+  IP4_ROUTE_TABLE                *RouteTable;\r
+\r
+  DataItem   = NULL;\r
+  Status     = EFI_SUCCESS;\r
+  Ptr        = NULL;\r
+  IpIf       = NULL;\r
+  RouteTable = NULL;\r
 \r
   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);\r
 \r
   ASSERT (Instance->DataItem[Ip4Config2DataTypeManualAddress].Status != EFI_NOT_READY);\r
 \r
-  if (((DataSize % sizeof (EFI_IP4_CONFIG2_MANUAL_ADDRESS)) != 0) || (DataSize == 0)) {\r
+  if ((DataSize != 0) && ((DataSize % sizeof (EFI_IP4_CONFIG2_MANUAL_ADDRESS)) != 0)) {\r
     return EFI_BAD_BUFFER_SIZE;\r
   }\r
 \r
@@ -1089,51 +1277,110 @@ Ip4Config2SetMaunualAddress (
     return EFI_WRITE_PROTECTED;\r
   }\r
 \r
-  NewAddress = *((EFI_IP4_CONFIG2_MANUAL_ADDRESS *) Data);\r
+  DataItem = &Instance->DataItem[Ip4Config2DataTypeManualAddress];\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
-  Ptr = AllocateCopyPool (DataSize, Data);\r
-  if (Ptr == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
+  if (Data != NULL && DataSize != 0) {\r
+    NewAddress = *((EFI_IP4_CONFIG2_MANUAL_ADDRESS *) Data);\r
 \r
-  DataItem = &Instance->DataItem[Ip4Config2DataTypeManualAddress];\r
-  if (DataItem->Data.Ptr != NULL) {\r
-    FreePool (DataItem->Data.Ptr);\r
-  }\r
-  \r
-  DataItem->Data.Ptr = Ptr;\r
-  DataItem->DataSize = DataSize;\r
-  DataItem->Status   = EFI_NOT_READY;\r
+    StationAddress = EFI_NTOHL (NewAddress.Address);\r
+    SubnetMask = EFI_NTOHL (NewAddress.SubnetMask);\r
 \r
-  StationAddress = EFI_NTOHL (NewAddress.Address);\r
-  SubnetMask = EFI_NTOHL (NewAddress.SubnetMask);\r
+    //\r
+    // Check whether the StationAddress/SubnetMask pair is valid.\r
+    //\r
+    if (!Ip4StationAddressValid (StationAddress, SubnetMask)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
 \r
-  IpSb->Reconfig = TRUE;\r
-  Status = Ip4Config2SetDefaultAddr (IpSb, StationAddress, SubnetMask);\r
-  if (EFI_ERROR (Status)) {\r
-    goto ON_EXIT;\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
+    Ptr = AllocateCopyPool (DataSize, Data);\r
+    if (Ptr == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    if (DataItem->Data.Ptr != NULL) {\r
+      FreePool (DataItem->Data.Ptr);\r
+    }\r
+\r
+    DataItem->Data.Ptr = Ptr;\r
+    DataItem->DataSize = DataSize;\r
+    DataItem->Status   = EFI_NOT_READY;\r
+\r
+    IpSb->Reconfig = TRUE;\r
+    Status = Ip4Config2SetDefaultAddr (IpSb, StationAddress, SubnetMask);\r
+\r
+    DataItem->Status = Status;\r
+\r
+    if (EFI_ERROR (DataItem->Status) && DataItem->Status != EFI_NOT_READY) {\r
+      if (Ptr != NULL) {\r
+        FreePool (Ptr);\r
+      }\r
+      DataItem->Data.Ptr = NULL;\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
+    // Free the default router table and Interface, clean up the assemble table.\r
+    //\r
+    if (IpSb->DefaultInterface != NULL) {\r
+      if (IpSb->DefaultRouteTable != NULL) {\r
+        Ip4FreeRouteTable (IpSb->DefaultRouteTable);\r
+        IpSb->DefaultRouteTable = NULL;\r
+      }\r
+\r
+      Ip4CancelReceive (IpSb->DefaultInterface);\r
+\r
+      Ip4FreeInterface (IpSb->DefaultInterface, NULL);\r
+      IpSb->DefaultInterface = NULL;\r
+    }\r
 \r
-  DataItem->Status = EFI_SUCCESS;   \r
+    Ip4CleanAssembleTable (&IpSb->Assemble);\r
 \r
-ON_EXIT:\r
-  if (EFI_ERROR (DataItem->Status)) {\r
-    if (Ptr != NULL) {\r
-      FreePool (Ptr);\r
+    //\r
+    // Create new default interface and route table.\r
+    //\r
+    IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);\r
+    if (IpIf == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    RouteTable = Ip4CreateRouteTable ();\r
+    if (RouteTable == NULL) {\r
+      Ip4FreeInterface (IpIf, NULL);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    IpSb->DefaultInterface  = IpIf;\r
+    InsertHeadList (&IpSb->Interfaces, &IpIf->Link);\r
+    IpSb->DefaultRouteTable = RouteTable;\r
+    Ip4ReceiveFrame (IpIf, NULL, Ip4AccpetFrame, IpSb);\r
+\r
+    //\r
+    // Reset the State to unstarted.\r
+    //\r
+    if (IpSb->State == IP4_SERVICE_CONFIGED || IpSb->State == IP4_SERVICE_STARTED) {\r
+      IpSb->State = IP4_SERVICE_UNSTARTED;\r
     }\r
-    DataItem->Data.Ptr = NULL; \r
   }\r
 \r
-  return EFI_SUCCESS;\r
+  return Status;\r
 }\r
 \r
 /**\r
-  The work function is to set the gateway addresses manually for the EFI IPv4 \r
-  network stack that is running on the communication device that this EFI IPv4 \r
+  The work function is to set the gateway addresses manually for the EFI IPv4\r
+  network stack that is running on the communication device that this EFI IPv4\r
   Configuration Protocol manages. It is not configurable when the policy is\r
   Ip4Config2PolicyDhcp. The gateway addresses must be unicast IPv4 addresses.\r
 \r
@@ -1174,7 +1421,13 @@ Ip4Config2SetGateway (
   BOOLEAN               OneAdded;\r
   VOID                  *Tmp;\r
 \r
-  if ((DataSize % sizeof (EFI_IPv4_ADDRESS) != 0) || (DataSize == 0)) {\r
+  OldGateway      = NULL;\r
+  NewGateway      = NULL;\r
+  OneRemoved      = FALSE;\r
+  OneAdded        = FALSE;\r
+  Tmp             = NULL;\r
+\r
+  if ((DataSize != 0) && (DataSize % sizeof (EFI_IPv4_ADDRESS) != 0)) {\r
     return EFI_BAD_BUFFER_SIZE;\r
   }\r
 \r
@@ -1182,43 +1435,15 @@ Ip4Config2SetGateway (
     return EFI_WRITE_PROTECTED;\r
   }\r
 \r
-\r
-  NewGateway      = (EFI_IPv4_ADDRESS *) Data;\r
-  NewGatewayCount = DataSize / sizeof (EFI_IPv4_ADDRESS);\r
-  for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {\r
-    CopyMem (&Gateway, NewGateway + Index1, sizeof (IP4_ADDR));\r
-    \r
-    if (!NetIp4IsUnicast (NTOHL (Gateway), 0)) {\r
-\r
-      return EFI_INVALID_PARAMETER;\r
-    }\r
-\r
-    for (Index2 = Index1 + 1; Index2 < NewGatewayCount; Index2++) {\r
-      if (EFI_IP4_EQUAL (NewGateway + Index1, NewGateway + Index2)) {\r
-        return EFI_INVALID_PARAMETER;\r
-      }\r
-    }\r
-  }\r
\r
   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);\r
-  DataItem = &Instance->DataItem[Ip4Config2DataTypeGateway];\r
+\r
+  DataItem        = &Instance->DataItem[Ip4Config2DataTypeGateway];\r
   OldGateway      = DataItem->Data.Gateway;\r
   OldGatewayCount = DataItem->DataSize / sizeof (EFI_IPv4_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
-    // Remove this route entry.\r
+    // Remove the old route entry.\r
     //\r
     CopyMem (&Gateway, OldGateway + Index1, sizeof (IP4_ADDR));\r
     Ip4DelRoute (\r
@@ -1228,46 +1453,84 @@ Ip4Config2SetGateway (
       NTOHL (Gateway)\r
       );\r
     OneRemoved = TRUE;\r
-\r
   }\r
 \r
-  for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {\r
-    CopyMem (&Gateway, NewGateway + Index1, sizeof (IP4_ADDR));\r
-    Ip4AddRoute (\r
-      IpSb->DefaultRouteTable,\r
-      IP4_ALLZERO_ADDRESS,\r
-      IP4_ALLZERO_ADDRESS,\r
-      NTOHL (Gateway)\r
-      );    \r
-\r
-    OneAdded = TRUE;\r
-  }\r
+  if (Data != NULL && DataSize != 0) {\r
+    NewGateway      = (EFI_IPv4_ADDRESS *) Data;\r
+    NewGatewayCount = DataSize / sizeof (EFI_IPv4_ADDRESS);\r
+    for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {\r
+      CopyMem (&Gateway, NewGateway + Index1, sizeof (IP4_ADDR));\r
 \r
+      if ((IpSb->DefaultInterface->SubnetMask != 0) &&\r
+          !NetIp4IsUnicast (NTOHL (Gateway), IpSb->DefaultInterface->SubnetMask)) {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
 \r
-  if (!OneRemoved && !OneAdded) {\r
-    DataItem->Status = EFI_SUCCESS;\r
-    return EFI_ABORTED;\r
-  } else {\r
+      for (Index2 = Index1 + 1; Index2 < NewGatewayCount; Index2++) {\r
+        if (EFI_IP4_EQUAL (NewGateway + Index1, NewGateway + Index2)) {\r
+          return EFI_INVALID_PARAMETER;\r
+        }\r
+      }\r
+    }\r
 \r
-    if (Tmp != NULL) {\r
-      if (DataItem->Data.Ptr != NULL) {\r
-        FreePool (DataItem->Data.Ptr);\r
+    if (NewGatewayCount != OldGatewayCount) {\r
+      Tmp = AllocatePool (DataSize);\r
+      if (Tmp == NULL) {\r
+        return EFI_OUT_OF_RESOURCES;\r
       }\r
-      DataItem->Data.Ptr = Tmp;\r
+    } else {\r
+      Tmp = NULL;\r
     }\r
 \r
-    CopyMem (DataItem->Data.Ptr, Data, DataSize);\r
-    DataItem->DataSize = DataSize;\r
-    DataItem->Status   = EFI_SUCCESS;\r
-    return EFI_SUCCESS;\r
+    for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {\r
+      //\r
+      // Add the new route entry.\r
+      //\r
+      CopyMem (&Gateway, NewGateway + Index1, sizeof (IP4_ADDR));\r
+      Ip4AddRoute (\r
+        IpSb->DefaultRouteTable,\r
+        IP4_ALLZERO_ADDRESS,\r
+        IP4_ALLZERO_ADDRESS,\r
+        NTOHL (Gateway)\r
+        );\r
+\r
+      OneAdded = TRUE;\r
+    }\r
+\r
+    if (!OneRemoved && !OneAdded) {\r
+      DataItem->Status = EFI_SUCCESS;\r
+      return EFI_ABORTED;\r
+    } else {\r
+      if (Tmp != NULL) {\r
+        if (DataItem->Data.Ptr != NULL) {\r
+          FreePool (DataItem->Data.Ptr);\r
+        }\r
+        DataItem->Data.Ptr = Tmp;\r
+      }\r
+\r
+      CopyMem (DataItem->Data.Ptr, Data, DataSize);\r
+      DataItem->DataSize = DataSize;\r
+      DataItem->Status   = EFI_SUCCESS;\r
+    }\r
+  } else {\r
+    //\r
+    // DataSize is 0 and Data is NULL, clean up the Gateway 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
+  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
-  The work function is to set the DNS server list for the EFI IPv4 network \r
-  stack running on the communication device that this EFI_IP4_CONFIG2_PROTOCOL \r
-  manages. It is not configurable when the policy is Ip4Config2PolicyDhcp. \r
+  The work function is to set the DNS server list for the EFI IPv4 network\r
+  stack running on the communication device that this EFI_IP4_CONFIG2_PROTOCOL\r
+  manages. It is not configurable when the policy is Ip4Config2PolicyDhcp.\r
   The DNS server addresses must be unicast IPv4 addresses.\r
 \r
   @param[in]     Instance The pointer to the IP4 config2 instance data.\r
@@ -1293,102 +1556,37 @@ Ip4Config2SetDnsServer (
   IN VOID                 *Data\r
   )\r
 {\r
-  UINTN                 OldIndex;\r
-  UINTN                 NewIndex;\r
-  UINTN                 Index1;\r
-  EFI_IPv4_ADDRESS      *OldDns;\r
-  EFI_IPv4_ADDRESS      *NewDns;\r
-  UINTN                 OldDnsCount;\r
-  UINTN                 NewDnsCount;\r
-  IP4_CONFIG2_DATA_ITEM *Item;\r
-  BOOLEAN               OneAdded;\r
-  VOID                  *Tmp;\r
-  IP4_ADDR              DnsAddress;\r
+  EFI_STATUS                     Status;\r
+  IP4_CONFIG2_DATA_ITEM          *Item;\r
 \r
-  if ((DataSize % sizeof (EFI_IPv4_ADDRESS) != 0) || (DataSize == 0)) {\r
-    return EFI_BAD_BUFFER_SIZE;\r
-  }\r
+  Status = EFI_SUCCESS;\r
+  Item   = NULL;\r
 \r
   if (Instance->Policy != Ip4Config2PolicyStatic) {\r
     return EFI_WRITE_PROTECTED;\r
   }\r
 \r
-  Item        = &Instance->DataItem[Ip4Config2DataTypeDnsServer];\r
-  NewDns      = (EFI_IPv4_ADDRESS *) Data;\r
-  OldDns      = Item->Data.DnsServers;\r
-  NewDnsCount = DataSize / sizeof (EFI_IPv4_ADDRESS);\r
-  OldDnsCount = Item->DataSize / sizeof (EFI_IPv4_ADDRESS);\r
-  OneAdded    = FALSE;\r
+  Item = &Instance->DataItem[Ip4Config2DataTypeDnsServer];\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
+  if (DATA_ATTRIB_SET (Item->Attribute, DATA_ATTRIB_VOLATILE)) {\r
+    REMOVE_DATA_ATTRIB (Item->Attribute, DATA_ATTRIB_VOLATILE);\r
   }\r
 \r
-  for (NewIndex = 0; NewIndex < NewDnsCount; NewIndex++) {\r
-    CopyMem (&DnsAddress, NewDns + NewIndex, sizeof (IP4_ADDR));\r
-\r
-    if (!NetIp4IsUnicast (NTOHL (DnsAddress), 0)) {\r
-      //\r
-      // The dns server address must be unicast.\r
-      //\r
-      FreePool (Tmp);\r
-      return EFI_INVALID_PARAMETER;\r
-    }\r
-\r
-    for (Index1 = NewIndex + 1; Index1 < NewDnsCount; Index1++) {\r
-      if (EFI_IP4_EQUAL (NewDns + NewIndex, NewDns + Index1)) {\r
-        FreePool (Tmp);\r
-        return EFI_INVALID_PARAMETER;\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
-\r
-    for (OldIndex = 0; OldIndex < OldDnsCount; OldIndex++) {\r
-      if (EFI_IP4_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
-  if (!OneAdded && (DataSize == Item->DataSize)) {\r
+  if (Data != NULL && DataSize != 0) {\r
+    Status = Ip4Config2SetDnsServerWorker (Instance, DataSize, Data);\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 Status;\r
 }\r
 \r
 /**\r
@@ -1405,33 +1603,18 @@ Ip4Config2InitIfInfo (
   OUT EFI_IP4_CONFIG2_INTERFACE_INFO *IfInfo\r
   )\r
 {\r
-  IfInfo->Name[0] = L'e';\r
-  IfInfo->Name[1] = L't';\r
-  IfInfo->Name[2] = L'h';\r
-  IfInfo->Name[3] = (CHAR16) (L'0' + IpSb->Ip4Config2Instance.IfIndex);\r
-  IfInfo->Name[4] = 0;\r
+  UnicodeSPrint (\r
+    IfInfo->Name,\r
+    EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE,\r
+    L"eth%d",\r
+    IpSb->Ip4Config2Instance.IfIndex\r
+  );\r
 \r
   IfInfo->IfType        = IpSb->SnpMode.IfType;\r
   IfInfo->HwAddressSize = IpSb->SnpMode.HwAddressSize;\r
   CopyMem (&IfInfo->HwAddress, &IpSb->SnpMode.CurrentAddress, IfInfo->HwAddressSize);\r
 }\r
 \r
-/**\r
-  The event handle routine when DHCPv4 process is finished or is updated.\r
-\r
-  @param[in]     Event         Not used.\r
-  @param[in]     Context       The pointer to the IP4 configuration instance data.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-Ip4Config2OnDhcp4Event (\r
-  IN EFI_EVENT  Event,\r
-  IN VOID       *Context\r
-  )\r
-{\r
-  return ;\r
-}\r
 \r
 \r
 /**\r
@@ -1466,9 +1649,8 @@ Ip4Config2OnDhcp4Event (
                                 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 DataSize do 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
@@ -1496,7 +1678,7 @@ EfiIp4Config2SetData (
   IP4_CONFIG2_INSTANCE *Instance;\r
   IP4_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
@@ -1820,7 +2002,7 @@ Ip4Config2InitInstance (
     NetMapInit (&Instance->DataItem[Index].EventMap);\r
   }\r
 \r
-  \r
+\r
   //\r
   // Initialize each data type: associate storage and set data size for the\r
   // fixed size data types, hook the SetData function, set the data attribute.\r
@@ -1836,11 +2018,11 @@ Ip4Config2InitInstance (
   DataItem->SetData  = Ip4Config2SetPolicy;\r
   DataItem->Data.Ptr = &Instance->Policy;\r
   DataItem->DataSize = sizeof (Instance->Policy);\r
-  Instance->Policy   = Ip4Config2PolicyDhcp;\r
+  Instance->Policy   = Ip4Config2PolicyStatic;\r
   SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);\r
 \r
   DataItem           = &Instance->DataItem[Ip4Config2DataTypeManualAddress];\r
-  DataItem->SetData  = Ip4Config2SetMaunualAddress;\r
+  DataItem->SetData  = Ip4Config2SetManualAddress;\r
   DataItem->Status   = EFI_NOT_FOUND;\r
 \r
   DataItem           = &Instance->DataItem[Ip4Config2DataTypeGateway];\r
@@ -1851,22 +2033,12 @@ Ip4Config2InitInstance (
   DataItem->SetData  = Ip4Config2SetDnsServer;\r
   DataItem->Status   = EFI_NOT_FOUND;\r
 \r
-  //\r
-  // Create the event used for DHCP.\r
-  //\r
-  Status = gBS->CreateEvent (\r
-                  EVT_NOTIFY_SIGNAL,\r
-                  TPL_CALLBACK,\r
-                  Ip4Config2OnDhcp4Event,\r
-                  Instance,\r
-                  &Instance->Dhcp4Event\r
-                  );\r
-  ASSERT_EFI_ERROR (Status);\r
-\r
   Instance->Configured  = TRUE;\r
 \r
   //\r
   // Try to read the config data from NV variable.\r
+  // If not found, write initialized config data into NV variable\r
+  // as a default config data.\r
   //\r
   Status = Ip4Config2ReadConfigData (IpSb->MacString, Instance);\r
   if (Status == EFI_NOT_FOUND) {\r
@@ -1877,20 +2049,6 @@ Ip4Config2InitInstance (
     return Status;\r
   }\r
 \r
-  //\r
-  // Try to set the configured parameter.\r
-  //\r
-  for (Index = Ip4Config2DataTypePolicy; Index < Ip4Config2DataTypeMaximum; Index++) {\r
-    DataItem = &IpSb->Ip4Config2Instance.DataItem[Index];\r
-    if (DataItem->Data.Ptr != NULL) {\r
-      DataItem->SetData (\r
-                  &IpSb->Ip4Config2Instance,\r
-                  DataItem->DataSize,\r
-                  DataItem->Data.Ptr\r
-                  );\r
-    }\r
-  }\r
-\r
   Instance->Ip4Config2.SetData              = EfiIp4Config2SetData;\r
   Instance->Ip4Config2.GetData              = EfiIp4Config2GetData;\r
   Instance->Ip4Config2.RegisterDataNotify   = EfiIp4Config2RegisterDataNotify;\r
@@ -1935,6 +2093,7 @@ Ip4Config2CleanInstance (
   //\r
   if (Instance->Dhcp4Event != NULL) {\r
     gBS->CloseEvent (Instance->Dhcp4Event);\r
+    Instance->Dhcp4Event = NULL;\r
   }\r
 \r
   for (Index = 0; Index < Ip4Config2DataTypeMaximum; Index++) {\r
@@ -1957,3 +2116,53 @@ Ip4Config2CleanInstance (
   RemoveEntryList (&Instance->Link);\r
 }\r
 \r
+/**\r
+  The event handle for IP4 auto reconfiguration. The original default\r
+  interface and route table will be removed as the default.\r
+\r
+  @param[in]  Context                The IP4 service binding instance.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+Ip4AutoReconfigCallBackDpc (\r
+  IN VOID                   *Context\r
+  )\r
+{\r
+  IP4_SERVICE               *IpSb;\r
+\r
+  IpSb      = (IP4_SERVICE *) Context;\r
+  NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);\r
+\r
+  if (IpSb->State > IP4_SERVICE_UNSTARTED) {\r
+    IpSb->State = IP4_SERVICE_UNSTARTED;\r
+  }\r
+\r
+  IpSb->Reconfig = TRUE;\r
+\r
+  Ip4StartAutoConfig (&IpSb->Ip4Config2Instance);\r
+\r
+  return ;\r
+}\r
+\r
+\r
+/**\r
+  Request Ip4AutoReconfigCallBackDpc as a DPC at TPL_CALLBACK.\r
+\r
+  @param Event     The event that is signalled.\r
+  @param Context   The IP4 service binding instance.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+Ip4AutoReconfigCallBack (\r
+  IN EFI_EVENT              Event,\r
+  IN VOID                   *Context\r
+  )\r
+{\r
+  //\r
+  // Request Ip4AutoReconfigCallBackDpc as a DPC at TPL_CALLBACK\r
+  //\r
+  QueueDpc (TPL_CALLBACK, Ip4AutoReconfigCallBackDpc, Context);\r
+}\r
+\r