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