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-mahm...@hpe.com>
---
Index: MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Config2Impl.c
===================================================================
--- MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Config2Impl.c      (revision 18557)
+++ MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Config2Impl.c      (working copy)
@@ -2,6 +2,7 @@
   The implementation of EFI IPv4 Configuration II Protocol.
 
   Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+  (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
 
   This program and the accompanying materials
   are licensed and made available under the terms and conditions of the BSD 
License
@@ -677,7 +678,125 @@
   }
 }
 
+/**
+  This worker function sets the DNS server list for the EFI IPv4 network 
+  stack running on the communication device that this EFI_IP4_CONFIG2_PROTOCOL 
+  manages. The DNS server addresses must be unicast IPv4 addresses. 
 
+  @param[in]     Instance The pointer to the IP4 config2 instance data.
+  @param[in]     DataSize The size of the buffer pointed to by Data in bytes.
+  @param[in]     Data     The data buffer to set, points to an array of
+                          EFI_IPv4_ADDRESS instances.
+
+  @retval EFI_BAD_BUFFER_SIZE   The DataSize does not match the size of the 
type.
+  @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resources to complete the 
operation.
+  @retval EFI_ABORTED           The DNS server addresses to be set equal the 
current
+                                configuration.
+  @retval EFI_SUCCESS           The specified configuration data for the EFI 
IPv4
+                                network stack was set.
+
+**/
+EFI_STATUS
+Ip4Config2SetDnsServerWorker (
+  IN IP4_CONFIG2_INSTANCE *Instance,
+  IN UINTN                DataSize,
+  IN VOID                 *Data
+  )
+{
+  UINTN                 OldIndex;
+  UINTN                 NewIndex;
+  UINTN                 Index1;
+  EFI_IPv4_ADDRESS      *OldDns;
+  EFI_IPv4_ADDRESS      *NewDns;
+  UINTN                 OldDnsCount;
+  UINTN                 NewDnsCount;
+  IP4_CONFIG2_DATA_ITEM *Item;
+  BOOLEAN               OneAdded;
+  VOID                  *Tmp;
+  IP4_ADDR              DnsAddress;
+
+  if ((DataSize % sizeof (EFI_IPv4_ADDRESS) != 0) || (DataSize == 0)) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  Item        = &Instance->DataItem[Ip4Config2DataTypeDnsServer];
+  NewDns      = (EFI_IPv4_ADDRESS *) Data;
+  OldDns      = Item->Data.DnsServers;
+  NewDnsCount = DataSize / sizeof (EFI_IPv4_ADDRESS);
+  OldDnsCount = Item->DataSize / sizeof (EFI_IPv4_ADDRESS);
+  OneAdded    = FALSE;
+
+  if (NewDnsCount != OldDnsCount) {
+    Tmp = AllocatePool (DataSize);
+    if (Tmp == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  } else {
+    Tmp = NULL;
+  }
+
+  for (NewIndex = 0; NewIndex < NewDnsCount; NewIndex++) {
+    CopyMem (&DnsAddress, NewDns + NewIndex, sizeof (IP4_ADDR));
+
+    if (!NetIp4IsUnicast (NTOHL (DnsAddress), 0)) {
+      //
+      // The dns server address must be unicast.
+      //
+      FreePool (Tmp);
+      return EFI_INVALID_PARAMETER;
+    }
+
+    for (Index1 = NewIndex + 1; Index1 < NewDnsCount; Index1++) {
+      if (EFI_IP4_EQUAL (NewDns + NewIndex, NewDns + Index1)) {
+        FreePool (Tmp);
+        return EFI_INVALID_PARAMETER;
+      }
+    }
+
+    if (OneAdded) {
+      //
+      // If any address in the new setting is not in the old settings, skip the
+      // comparision below.
+      //
+      continue;
+    }
+
+    for (OldIndex = 0; OldIndex < OldDnsCount; OldIndex++) {
+      if (EFI_IP4_EQUAL (NewDns + NewIndex, OldDns + OldIndex)) {
+        //
+        // If found break out.
+        //
+        break;
+      }
+    }
+
+    if (OldIndex == OldDnsCount) {
+      OneAdded = TRUE;
+    }
+  }
+
+  if (!OneAdded && (DataSize == Item->DataSize)) {
+    //
+    // No new item is added and the size is the same.
+    //
+    Item->Status = EFI_SUCCESS;
+    return EFI_ABORTED;
+  } else {
+    if (Tmp != NULL) {
+      if (Item->Data.Ptr != NULL) {
+        FreePool (Item->Data.Ptr);
+      }      
+      Item->Data.Ptr = Tmp;
+    }
+
+    CopyMem (Item->Data.Ptr, Data, DataSize);
+    Item->DataSize = DataSize;
+    Item->Status   = EFI_SUCCESS;
+    return EFI_SUCCESS;
+  }
+}
+
 /**
   Callback function when DHCP process finished. It will save the
   retrieved IP configure parameter from DHCP to the NVRam.
@@ -701,6 +820,9 @@
   IP4_ADDR                  StationAddress;
   IP4_ADDR                  SubnetMask;
   IP4_ADDR                  GatewayAddress;
+  UINT32                    Index;
+  UINT32                    OptionCount;
+  EFI_DHCP4_PACKET_OPTION   **OptionList;
 
   Instance = (IP4_CONFIG2_INSTANCE *) Context;
   ASSERT (Instance->Dhcp4 != NULL);
@@ -723,6 +845,44 @@
     if (EFI_ERROR (Status)) {
       goto Exit;
     }
+
+    //
+    // Parse the ACK to get required DNS server information.
+    //
+    OptionCount = 0;
+    OptionList  = NULL;
+
+    Status      = Instance->Dhcp4->Parse (Instance->Dhcp4, 
Dhcp4Mode.ReplyPacket, &OptionCount, OptionList);
+    if (Status != EFI_BUFFER_TOO_SMALL) {
+      goto Exit;
+    }
+
+    OptionList = AllocateZeroPool (OptionCount * sizeof 
(EFI_DHCP4_PACKET_OPTION *));
+    if (OptionList == NULL) {
+      goto Exit;
+    }
+
+    Status = Instance->Dhcp4->Parse (Instance->Dhcp4, Dhcp4Mode.ReplyPacket, 
&OptionCount, OptionList);
+    if (EFI_ERROR (Status)) {
+      FreePool (OptionList);
+      goto Exit;
+    }
+
+    for (Index = 0; Index < OptionCount; Index++) {
+      //
+      // Look for DNS Server opcode (6).
+      //
+      if (OptionList[Index]->OpCode == DHCP_TAG_DNS_SERVER) {
+        if (((OptionList[Index]->Length & 0x3) != 0) || 
(OptionList[Index]->Length == 0)) {
+          break;
+        }
+
+        Ip4Config2SetDnsServerWorker (Instance, OptionList[Index]->Length, 
&OptionList[Index]->Data[0]);
+        break;
+      }
+    }
+
+    FreePool (OptionList);
   
     Instance->DhcpSuccess = TRUE;
   }
@@ -831,9 +991,10 @@
   // yields the control of this DHCP service to us.
   //
   ParaList.Head.OpCode             = DHCP_TAG_PARA_LIST;
-  ParaList.Head.Length             = 2;
+  ParaList.Head.Length             = 3;
   ParaList.Head.Data[0]            = DHCP_TAG_NETMASK;
   ParaList.Route                   = DHCP_TAG_ROUTER;
+  ParaList.Dns                     = DHCP_TAG_DNS_SERVER;
   OptionList[0]                    = &ParaList.Head;
   Dhcp4Mode.ConfigData.OptionCount = 1;
   Dhcp4Mode.ConfigData.OptionList  = OptionList;
@@ -1293,102 +1454,11 @@
   IN VOID                 *Data
   )
 {
-  UINTN                 OldIndex;
-  UINTN                 NewIndex;
-  UINTN                 Index1;
-  EFI_IPv4_ADDRESS      *OldDns;
-  EFI_IPv4_ADDRESS      *NewDns;
-  UINTN                 OldDnsCount;
-  UINTN                 NewDnsCount;
-  IP4_CONFIG2_DATA_ITEM *Item;
-  BOOLEAN               OneAdded;
-  VOID                  *Tmp;
-  IP4_ADDR              DnsAddress;
-
-  if ((DataSize % sizeof (EFI_IPv4_ADDRESS) != 0) || (DataSize == 0)) {
-    return EFI_BAD_BUFFER_SIZE;
-  }
-
   if (Instance->Policy != Ip4Config2PolicyStatic) {
     return EFI_WRITE_PROTECTED;
   }
 
-  Item        = &Instance->DataItem[Ip4Config2DataTypeDnsServer];
-  NewDns      = (EFI_IPv4_ADDRESS *) Data;
-  OldDns      = Item->Data.DnsServers;
-  NewDnsCount = DataSize / sizeof (EFI_IPv4_ADDRESS);
-  OldDnsCount = Item->DataSize / sizeof (EFI_IPv4_ADDRESS);
-  OneAdded    = FALSE;
-
-  if (NewDnsCount != OldDnsCount) {
-    Tmp = AllocatePool (DataSize);
-    if (Tmp == NULL) {
-      return EFI_OUT_OF_RESOURCES;
-    }
-  } else {
-    Tmp = NULL;
-  }
-
-  for (NewIndex = 0; NewIndex < NewDnsCount; NewIndex++) {
-    CopyMem (&DnsAddress, NewDns + NewIndex, sizeof (IP4_ADDR));
-
-    if (!NetIp4IsUnicast (NTOHL (DnsAddress), 0)) {
-      //
-      // The dns server address must be unicast.
-      //
-      FreePool (Tmp);
-      return EFI_INVALID_PARAMETER;
-    }
-
-    for (Index1 = NewIndex + 1; Index1 < NewDnsCount; Index1++) {
-      if (EFI_IP4_EQUAL (NewDns + NewIndex, NewDns + Index1)) {
-        FreePool (Tmp);
-        return EFI_INVALID_PARAMETER;
-      }
-    }
-
-    if (OneAdded) {
-      //
-      // If any address in the new setting is not in the old settings, skip the
-      // comparision below.
-      //
-      continue;
-    }
-
-    for (OldIndex = 0; OldIndex < OldDnsCount; OldIndex++) {
-      if (EFI_IP4_EQUAL (NewDns + NewIndex, OldDns + OldIndex)) {
-        //
-        // If found break out.
-        //
-        break;
-      }
-    }
-
-    if (OldIndex == OldDnsCount) {
-      OneAdded = TRUE;
-    }
-  }
-
-  if (!OneAdded && (DataSize == Item->DataSize)) {
-    //
-    // No new item is added and the size is the same.
-    //
-    Item->Status = EFI_SUCCESS;
-    return EFI_ABORTED;
-  } else {
-    if (Tmp != NULL) {
-      if (Item->Data.Ptr != NULL) {
-        FreePool (Item->Data.Ptr);
-      }      
-      Item->Data.Ptr = Tmp;
-    }
-
-    CopyMem (Item->Data.Ptr, Data, DataSize);
-    Item->DataSize = DataSize;
-    Item->Status   = EFI_SUCCESS;
-    return EFI_SUCCESS;
-  }
-
+  return Ip4Config2SetDnsServerWorker (Instance, DataSize, Data);
 }
 
 /**
Index: MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Config2Impl.h
===================================================================
--- MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Config2Impl.h      (revision 18557)
+++ MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Config2Impl.h      (working copy)
@@ -2,6 +2,7 @@
   Definitions for EFI IPv4 Configuration II Protocol implementation.
 
   Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+  (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
 
   This program and the accompanying materials
   are licensed and made available under the terms and conditions of the BSD 
License
@@ -27,6 +28,7 @@
 #define DHCP_TAG_PARA_LIST             55
 #define DHCP_TAG_NETMASK               1
 #define DHCP_TAG_ROUTER                3
+#define DHCP_TAG_DNS_SERVER            6
 
 
 #define DATA_ATTRIB_SET(Attrib, Bits)       (BOOLEAN)((Attrib) & (Bits))
@@ -207,6 +209,7 @@
 typedef struct {
   EFI_DHCP4_PACKET_OPTION Head;
   UINT8                   Route;
+  UINT8                   Dns;
 } IP4_CONFIG2_DHCP4_OPTION;
 #pragma pack()

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to