]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg Ip4Dxe: Ip4Config2 to request DHCP Option6 DNS server IP
authorSamer El-Haj-Mahmoud <samer.el-haj-mahmoud@hpe.com>
Wed, 30 Sep 2015 03:01:13 +0000 (03:01 +0000)
committersfu5 <sfu5@Edk2>
Wed, 30 Sep 2015 03:01:13 +0000 (03:01 +0000)
Ip4Config2 protocol implementation must request for DNS server info when the
policy is set to DHCP. And when a DHCP server responds to it with a list of
DNS server addresses, it must parse it and set it for the instance. Without
this, nobody can do a Ip4Config->GetData for DNS server IPs before calling
Dns->Configure(). This will mean a DHCP is initiated when calling
Dns->Configure(), thus causing serious performance issues. This patch
attempts to address this issue.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Samer El-Haj-Mahmoud <samer.el-haj-mahmoud@hpe.com>
Reviewed-by: Ye Ting <ting.ye@intel.com>
Reviewed-by: Samer El-Haj-Mahmoud <elhaj@hpe.com>
Reviewed-by: Fu Siyuan <siyuan.fu@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18560 6f19259b-4bc3-4df7-8a09-765794883524

MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Config2Impl.c
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Config2Impl.h

index 637d7cd65993bec79c332e0703d9eb398a8ecf59..edbddba02118d70f8a226371232226095df61b27 100644 (file)
@@ -2,6 +2,7 @@
   The implementation of EFI IPv4 Configuration II Protocol.\r
 \r
   Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  (C) Copyright 2015 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
@@ -677,6 +678,126 @@ 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
+  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
+\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
+\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
+    //\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 +822,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
@@ -724,6 +848,44 @@ Ip4Config2OnDhcp4Complete (
       goto Exit;\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 == DHCP_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
@@ -831,9 +993,10 @@ Ip4StartAutoConfig (
   // 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.Length             = 3;\r
   ParaList.Head.Data[0]            = DHCP_TAG_NETMASK;\r
   ParaList.Route                   = DHCP_TAG_ROUTER;\r
+  ParaList.Dns                     = DHCP_TAG_DNS_SERVER;\r
   OptionList[0]                    = &ParaList.Head;\r
   Dhcp4Mode.ConfigData.OptionCount = 1;\r
   Dhcp4Mode.ConfigData.OptionList  = OptionList;\r
@@ -1293,102 +1456,11 @@ 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
-\r
-  if ((DataSize % sizeof (EFI_IPv4_ADDRESS) != 0) || (DataSize == 0)) {\r
-    return EFI_BAD_BUFFER_SIZE;\r
-  }\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
-\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
-\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
-    //\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
+  return Ip4Config2SetDnsServerWorker (Instance, DataSize, Data);\r
 }\r
 \r
 /**\r
index e74b9ae407440e35739ae90ab8e78c7cbef19fdb..ab72525646772388e92ee05d2fce8a861b1b02e0 100644 (file)
@@ -2,6 +2,7 @@
   Definitions for EFI IPv4 Configuration II Protocol implementation.\r
 \r
   Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  (C) Copyright 2015 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
@@ -27,7 +28,7 @@
 #define DHCP_TAG_PARA_LIST             55\r
 #define DHCP_TAG_NETMASK               1\r
 #define DHCP_TAG_ROUTER                3\r
-\r
+#define DHCP_TAG_DNS_SERVER            6\r
 \r
 #define DATA_ATTRIB_SET(Attrib, Bits)       (BOOLEAN)((Attrib) & (Bits))\r
 #define SET_DATA_ATTRIB(Attrib, Bits)       ((Attrib) |= (Bits))\r
@@ -207,6 +208,7 @@ struct _IP4_CONFIG2_INSTANCE {
 typedef struct {\r
   EFI_DHCP4_PACKET_OPTION Head;\r
   UINT8                   Route;\r
+  UINT8                   Dns;\r
 } IP4_CONFIG2_DHCP4_OPTION;\r
 #pragma pack()\r
 \r