MdeModulePkg Ip4Dxe: Ip4Config2 to request DHCP Option6 DNS server IP
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
This commit is contained in:
		
				
					committed by
					
						
						sfu5
					
				
			
			
				
	
			
			
			
						parent
						
							33ecfa8af9
						
					
				
				
					commit
					9feefde0cb
				
			@@ -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,6 +678,126 @@ Ip4Config2CleanDhcp4 (
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  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
 | 
			
		||||
@@ -701,6 +822,9 @@ Ip4Config2OnDhcp4Complete (
 | 
			
		||||
  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);
 | 
			
		||||
@@ -724,6 +848,44 @@ Ip4Config2OnDhcp4Complete (
 | 
			
		||||
      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 +993,10 @@ Ip4StartAutoConfig (
 | 
			
		||||
  // 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 +1456,11 @@ Ip4Config2SetDnsServer (
 | 
			
		||||
  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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -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,7 +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))
 | 
			
		||||
#define SET_DATA_ATTRIB(Attrib, Bits)       ((Attrib) |= (Bits))
 | 
			
		||||
@@ -207,6 +208,7 @@ struct _IP4_CONFIG2_INSTANCE {
 | 
			
		||||
typedef struct {
 | 
			
		||||
  EFI_DHCP4_PACKET_OPTION Head;
 | 
			
		||||
  UINT8                   Route;
 | 
			
		||||
  UINT8                   Dns;
 | 
			
		||||
} IP4_CONFIG2_DHCP4_OPTION;
 | 
			
		||||
#pragma pack()
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user