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:
Samer El-Haj-Mahmoud 2015-09-30 03:01:13 +00:00 committed by sfu5
parent 33ecfa8af9
commit 9feefde0cb
2 changed files with 168 additions and 94 deletions

View File

@ -2,6 +2,7 @@
The implementation of EFI IPv4 Configuration II Protocol. The implementation of EFI IPv4 Configuration II Protocol.
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 Callback function when DHCP process finished. It will save the
@ -701,6 +822,9 @@ Ip4Config2OnDhcp4Complete (
IP4_ADDR StationAddress; IP4_ADDR StationAddress;
IP4_ADDR SubnetMask; IP4_ADDR SubnetMask;
IP4_ADDR GatewayAddress; IP4_ADDR GatewayAddress;
UINT32 Index;
UINT32 OptionCount;
EFI_DHCP4_PACKET_OPTION **OptionList;
Instance = (IP4_CONFIG2_INSTANCE *) Context; Instance = (IP4_CONFIG2_INSTANCE *) Context;
ASSERT (Instance->Dhcp4 != NULL); ASSERT (Instance->Dhcp4 != NULL);
@ -724,6 +848,44 @@ Ip4Config2OnDhcp4Complete (
goto Exit; 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; Instance->DhcpSuccess = TRUE;
} }
@ -831,9 +993,10 @@ Ip4StartAutoConfig (
// yields the control of this DHCP service to us. // yields the control of this DHCP service to us.
// //
ParaList.Head.OpCode = DHCP_TAG_PARA_LIST; ParaList.Head.OpCode = DHCP_TAG_PARA_LIST;
ParaList.Head.Length = 2; ParaList.Head.Length = 3;
ParaList.Head.Data[0] = DHCP_TAG_NETMASK; ParaList.Head.Data[0] = DHCP_TAG_NETMASK;
ParaList.Route = DHCP_TAG_ROUTER; ParaList.Route = DHCP_TAG_ROUTER;
ParaList.Dns = DHCP_TAG_DNS_SERVER;
OptionList[0] = &ParaList.Head; OptionList[0] = &ParaList.Head;
Dhcp4Mode.ConfigData.OptionCount = 1; Dhcp4Mode.ConfigData.OptionCount = 1;
Dhcp4Mode.ConfigData.OptionList = OptionList; Dhcp4Mode.ConfigData.OptionList = OptionList;
@ -1293,102 +1456,11 @@ Ip4Config2SetDnsServer (
IN VOID *Data 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) { if (Instance->Policy != Ip4Config2PolicyStatic) {
return EFI_WRITE_PROTECTED; return EFI_WRITE_PROTECTED;
} }
Item = &Instance->DataItem[Ip4Config2DataTypeDnsServer]; return Ip4Config2SetDnsServerWorker (Instance, DataSize, Data);
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;
}
} }
/** /**

View File

@ -2,6 +2,7 @@
Definitions for EFI IPv4 Configuration II Protocol implementation. Definitions for EFI IPv4 Configuration II Protocol implementation.
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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_PARA_LIST 55
#define DHCP_TAG_NETMASK 1 #define DHCP_TAG_NETMASK 1
#define DHCP_TAG_ROUTER 3 #define DHCP_TAG_ROUTER 3
#define DHCP_TAG_DNS_SERVER 6
#define DATA_ATTRIB_SET(Attrib, Bits) (BOOLEAN)((Attrib) & (Bits)) #define DATA_ATTRIB_SET(Attrib, Bits) (BOOLEAN)((Attrib) & (Bits))
#define SET_DATA_ATTRIB(Attrib, Bits) ((Attrib) |= (Bits)) #define SET_DATA_ATTRIB(Attrib, Bits) ((Attrib) |= (Bits))
@ -207,6 +208,7 @@ struct _IP4_CONFIG2_INSTANCE {
typedef struct { typedef struct {
EFI_DHCP4_PACKET_OPTION Head; EFI_DHCP4_PACKET_OPTION Head;
UINT8 Route; UINT8 Route;
UINT8 Dns;
} IP4_CONFIG2_DHCP4_OPTION; } IP4_CONFIG2_DHCP4_OPTION;
#pragma pack() #pragma pack()